Действительно странное поведение реакционного хука useState () - PullRequest
2 голосов
/ 09 января 2020

В настоящее время я пишу приложение реакции, используя Swiper для простого слайд-шоу, и все работает отлично. Сейчас я пытаюсь улучшить навигацию, отображая текущий слайд с помощью функции setActiveSlide. После первой загрузки все работает нормально. После нажатия кнопок, вызывающих setActiveSlide, для объекта истории устанавливается значение null, что приводит к ошибке (Uncaught TypeError: Невозможно прочитать свойство 'slideNext' из null) при повторном нажатии кнопок «Предыдущая» или «Следующая». Почему для объекта story устанавливается значение null после вызова setActiveSlide? Пожалуйста, помогите

Вот упрощенная версия приложения

import React, { useState, useEffect, useRef } from "react";
import Swiper from "swiper";

const Slideshow = props => {
    var swiper = useRef();
    var story = null;
    const [activeSlide, setActiveSlide] = useState("");

    useEffect(() => {
        story = new Swiper(swiper.current, {
            loop: false,
            speed: 1100
        });
    }, []);

    const prevSlide = () => {
        setActiveSlide("PREV");
        story.slidePrev();
    };

    const nextSlide = () => {
        setActiveSlide("NEXT");
        story.slideNext();
    };

    return (
        <div className="container-story" ref={swiper}>
            <div className="container-story-wrapper swiper-wrapper">
                {props.children}
            </div>

            <div className="navigation">
                <button onClick={prevSlide}> Previous </button>
                <button onClick={nextSlide}> Next </button>

                {activeSlide}
            </div>
            <div className="lightbox-container"></div>
        </div>
    );
};
export default Slideshow; 

Ответы [ 2 ]

5 голосов
/ 09 января 2020

Это функциональный компонент, поэтому, если вы хотите, чтобы переменная сохранялась во время нескольких рендеров, вы не можете объявить ее локально, как вы делаете с var story = null. У вашего первого рендера будет установлен этот параметр, но при повторном рендеринге компонента вы вернете его к нулю.

Правильный способ справиться с этим - использовать Reacts useRef hook. Это способ сохранить переменную в нескольких визуализациях.

Чтобы объявить ее: const _story = useRef(null);

Для чтения / записи в переменную _story вам потребуется доступ к _story.current , Таким образом, в вашем useEffect монтировании вы должны использовать это вместо:

_story.current = new Swiper(swiper.current, {
    loop: false,
    speed: 1100
});

А в ваших обработчиках: _story.current.slideNext();

Подробнее о useRef можно прочитать здесь .

0 голосов
/ 09 января 2020

Таким образом, проблема в

Назначения переменной 'story' изнутри React Hook useEffect будет потеряно после каждого рендера. Чтобы сохранить значение во времени, сохраните его в хуке useRef и сохраните изменяемое значение в свойстве .current. В противном случае вы можете переместить эту переменную непосредственно в useEffect.

Поэтому вам нужно обновить, как указано ниже

import React, { useState, useEffect, useRef } from "react";
import "./styles.css";

import Swiper from "swiper";

const Slideshow = props => {
  var swiper = useRef();
  var story = useRef(null);
  const [activeSlide, setActiveSlide] = useState("");

  useEffect(() => {
    story.current = new Swiper(swiper.current, {
      loop: false,
      speed: 1100
    });
  }, []);

  const prevSlide = () => {
    setActiveSlide("PREV");
    story.current.slidePrev();
  };

  const nextSlide = () => {
    setActiveSlide("NEXT");
    story.current.slideNext();
  };

  return (
    <div className="container-story" ref={swiper}>
      <div className="container-story-wrapper swiper-wrapper">
        {props.children}
      </div>

      <div className="navigation">
        <button onClick={prevSlide}> Previous </button>
        <button onClick={nextSlide}> Next </button>

        {activeSlide}
      </div>
      <div className="lightbox-container" />
    </div>
  );
};
export default Slideshow;

Работающий codesandbox

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...