реагировать начальное состояние, рассчитанное из DOM - PullRequest
0 голосов
/ 01 февраля 2019

Я использую https://www.npmjs.com/package/react-slick, и я пытаюсь сделать его "slidesToShow" динамически на основе доступной ширины.

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

Это мой код (интересные части):

const Carousel = (props: ICarouselProps) => {
  const slider = useRef(null);
  const recalculateItemsShown = () => {
    const maxItems = Math.round(
      slider.current.innerSlider.list.parentElement.clientWidth / 136, // content width is just hardcoded for now.
    );
    updateSettings({...props.settings, slidesToShow: maxItems});
  };
  useEffect(() => {
    window.addEventListener('resize', recalculateItemsShown);

    return () => {
      window.removeEventListener('resize', recalculateItemsShown);
    };
  });

  const [settings, updateSettings] = useState({
    ...props.settings,
    slidesToShow: //How do I set this properly? slider is null here
  });

  return (
    <div id="carousel" className="carousel">
      <Slider {...settings} {...arrows} ref={slider}>
        <div className="test-content/>
        <div className="test-content/>
        /* etc. */
        <div className="test-content/>
        <div className="test-content/>
        <div className="test-content/>
      </Slider>
    </div>
  );
};

export default Carousel;

, если я позвоню updateSettings в моем useEffectЯ получаю бесконечный цикл.

Так что мне придется либо:

  • Каким-то образом получить ширину элемента, который еще не был создан
  • или
  • вызывать updateSettings один раз после самого первого рендера.

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Я считаю, что хук uselayouteffect предназначен для этого конкретного случая использования.

https://reactjs.org/docs/hooks-reference.html#uselayouteffect

Он работает точно так же, как useEffect, за исключением того, что он срабатывает после загрузки domчто вы можете рассчитать ширину элемента при необходимости.

0 голосов
/ 01 февраля 2019

Вы можете иметь функцию, которая возвращает maxItems, и использовать ее везде, поэтому:

const getMaxItems = () => Math.round(slider.current.innerSlider.list.parentElement.clientWidth / 136)

Вы можете использовать ее возвращаемый результат в пределах recalculateItemsShown для обновления настроек.

const recalculateItemsShown = () => {
  updateSettings({...props.settings, slidesToShow: getMaxItems()});
};

И вы также используете его возвращаемое значение для первоначальной установки состояния.

const [settings, updateSettings] = useState({
  ...props.settings,
  slidesToShow: getMaxItems()
});

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

useEffect(() => {
  updateSettings({...props.settings, slidesToShow: getMaxItems()});
}, []);

Вы можете прочитатьПодробнее о том, как пропустить заявку здесь: https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

...