как использовать window.matchMedia в next.js с темой компонентов стиля?

#reactjs #next.js #media-queries #styled-components

Вопрос:

У меня есть тема:

 const smartPhonePortrait = 320;   const theme = {  isCompact:  typeof window !== 'undefined'  ? window.matchMedia(`(min-width:${smartPhonePortrait}px)`).matches  : false };  export default theme;  

А затем я добавляю эту тему своему провайдеру

внутри _app.js:

 import { ThemeProvider } from 'styled-components'; import theme from '../theme';  const App = ({ Component, pageProps, router }) =gt; {  return (  lt;ThemeProvider theme={theme}gt;  ... my app  lt;/ThemeProvidergt;  ); };  

и в моем стилизованном компоненте я делаю это:

 const Item = styled.div`  display: flex;  flex-direction: column;  flex-grow: 1;  flex-shrink: 0;  flex-basis: ${(props) =gt; (props.theme.isCompact ? '100%' : '48%')}; `;  

Это работает при первом рендеринге, но когда я изменяю размер экрана, он не обновляется. Если я на мобильном телефоне, я получаю flex-basis 100% , но если я изменю размер экрана на рабочий стол, я не получу 48%

Как мне заставить это работать?

Комментарии:

1. Запрос (min-width: 320px) мультимедиа по-прежнему будет верен для размеров экрана рабочего стола. Вам нужно создать другой запрос, соответствующий размерам экрана рабочего стола.

Ответ №1:

Что вы могли бы сделать, так это сделать крюк:

 import { useState, useCallback, useEffect } from 'react'; const useMediaQuery = (width) =gt; {  const [targetReached, setTargetReached] = useState(false);   const updateTarget = useCallback((e) =gt; {  if (e.matches) {  setTargetReached(true);  } else {  setTargetReached(false);  }  }, []);   useEffect(() =gt; {  if (typeof window !== 'undefined') {  const media = window.matchMedia(`(max-width:${width}px)`);  media.addListener(updateTarget);   if (media.matches) {  setTargetReached(true);  }   return () =gt; media.removeListener(updateTarget);  }  }, []);   return targetReached; };  export default useMediaQuery;  

и в вашем __app.js вы импортируете его и добавляете в свою тему:

 import MediaQuery from 'hooks/useMedia';  const isCompact = MediaQuery (576);  const useTheme = { ...theme, isCompact };  lt;ThemeProvider theme={useTheme}gt;  ... my app lt;/ThemeProvidergt;