Следующая Js передача динамич c ширина при изменении размера без повторного рендеринга - PullRequest
0 голосов
/ 25 марта 2020

Я пытаюсь динамически передать ширину стилям компонента. При первой загрузке все в порядке, но если я изменяю размер, он никогда не перерисовывает компонент, даже если перехватчик работает.

Я читал об этом, поскольку Next Js - это рендеринг на стороне сервера, это может привести к тому, что на стороне клиента вопросы. Итак, вот код:

Крюк

const useWidth = () => {
  if (process.browser) {
    const [width, setWidth] = useState(window.innerWidth);
    const handleResize = () => setWidth(window.innerWidth);
    useEffect(() => {
      window.addEventListener('resize', handleResize);
      return () => window.removeEventListener('resize', handleResize);
    }, [width]);
    return width;
  }
  return 0;
};

Компонент (уменьшен только для показа примера)

const Login = () => {
  const windowWidth = useWidth();
  const width = windowWidth > CELLPHONE_WIDTH ? '36.6rem' : '90%';
  const loginStyles = styles(width);
  return (
    <div className='container'>
      <TextInput
        type='text'
        width={width}
        placeholder='Email'
      />
    </div>
  );
};

Стили

function textInputStyles(width) {
  return css`
    width: ${width};
  `;
}

export default textInputStyles;

Ответы [ 2 ]

1 голос
/ 25 марта 2020

Проблема здесь в том, что код сначала запускается на стороне сервера с помощью Next. js. Поскольку process.browser возвращает false на стороне сервера, ваша ловушка logi c никогда не регистрируется. Только 0 возвращается. Так как никакой ловушки не было зарегистрировано, и никакое событие не было установлено, изменение размера окна не вызовет повторную визуализацию.

Вам необходимо использовать componentDidMount () или useEffect.

Здесь пример для вашего случая, который будет работать.

const useWidth = () => {
    const [width, setWidth] = useState(0); // default width, detect on server.
    const handleResize = () => setWidth(window.innerWidth);
    useEffect(() => {
      window.addEventListener('resize', handleResize);
      return () => window.removeEventListener('resize', handleResize);
    }, [handleResize]);
    return width;
};

С другой стороны, если вы хотите убедиться, что ваше начальное состояние соответствует состоянию окна браузера, вы можете динамически загружать свой компонент только на стороне клиента. .

import dynamic from 'next/dynamic'
const Login = dynamic(
  () => import('./pathToLogin/Login'),
  { ssr: false },
)

и в вашем компоненте, где используется Login.

const TopLevelComponent = () => {
 <Login {...props} />
}

, а затем вы можете свободно использовать объект окна в вашем компоненте Login.

const useWidth = () => {
  // Use window object freely
  const [width, setWidth] = useState(window.innerWidth); // default width, detect on server.

См. это , если все еще есть путаница.

0 голосов
/ 25 марта 2020

Большое спасибо Хасан Таукир за вашу помощь !!! : D

Когда я увидел ваш первый ответ, я попробовал его, но не смог вызвать пользовательский хук внутри useEffect, поскольку он нарушал правило Call Hooks from React function components

Но мне удалось найти решение с помощью этот код почти такой же, как тот, который вы опубликовали после того, как отредактировали ответ. Единственное отличие состоит в том, что в массиве зависимостей useEffect внутри пользовательского хука я использую ширину вместо обработчика. Не знаю, имеет ли это какое-то значение в этом случае, но он работает отлично.

const useWidth = () => {
  const [width, setWidth] = useState(0);
  const handleResize = () => setWidth(window.innerWidth);
  useEffect(() => {
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, [width]);
  return width;
};

И из компонента Im, использующего его как:

const Login = () => {
  const [width, setWidth] = useState('0');
  const windowWidth = useWidth();
  useEffect(() => {
    if (windowWidth < CELLPHONE_WIDTH) {
      setWidth('90%');
    } else {
      setWidth('36.6rem');
    }
  }, []);
// rest of the code
...