Функция не может правильно прочитать значение состояния - PullRequest
3 голосов
/ 01 апреля 2020

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

export const MainJobs = () => {
  const [items, setItems] = useState([]);
  const [ind, setInd] = useState(1);
  const errText = useLang(
    "sagas // Something went wrond // fasa"
  );
  const [element, setElement] = useState(null);
  const incrementState = () => {
    console.log(ind, ind + 1); //logs 1,2
    setInd(ind + 1);
  };
  useEffect(() => {
    const fetchInfo = async () => {
      const res = await fetch(`/api/search/vacancy?page=${ind}`);
      if (res.ok) {
        const data = await res.json();
        setItems(data);
      } else {
        pop({
          icon: "error",
          title: "Oops...",
          text: errText
        });
      }
    };
    fetchInfo();
  }, [ind]);
  useEffect(() => {
    const currentElement = element;
    const currentObservor = observor.current;
    if (currentElement) {
      currentObservor.observe(currentElement);
    }
    return () => {
      if (currentElement) {
        currentObservor.unobserve(currentElement);
      }
    };
  }, [element]);
  const observor = useRef(
    new IntersectionObserver(
      entries => {
        const first = entries[0];
        if (first.isIntersecting) {
          incrementState();
        }
      },
      { threshold: 1 }
    )
  );
  return (
    <div className="mainjobs-container">
      ...rest of markup
      <div className="bottom" ref={setElement}></div>
    </div>
  );
};

Он регистрирует 1,2 каждый раз, но не увеличивает ind. Также в devtools увеличивается до 2, а затем останавливается.

Мне нужно увеличивать ind каждый раз, когда вызывается функция incrementState. PS Я думаю, что проблема в useRef или Observor.

1 Ответ

1 голос
/ 01 апреля 2020

Из документов :

Почему внутри функции отображается устаревший реквизит или состояние?

Любая функция внутри компонента, включая обработчики событий и эффекты, «видит» реквизит и состояние из рендера, в котором он был создан.

Бывает, что incrementState определен внутри useRef и, следовательно, только «видит» начальное состояние.

Если вы хотите исправить только одно состояние, это довольно просто:

const incrementState = () => {
  setInd(prevInd => prevInd + 1);
}

Мы используем функциональную версию установщика состояний , так что мы не будем Не пропустите никаких обновлений о состоянии.

Но что, если этот обработчик фактически зависит от другой переменной состояния?

const observer = useRef();

// Adding a placeholder state for demo
const [secondState, setSecondState] = useState();

useEffect(() => {

  const incrementState = () => {
    // something to do with second state here
    if(secondState) 
      setInd(prevInd => prevInd + 1);
  };

  observer.current = new IntersectionObserver(
      entries => {
        const first = entries[0];
        if (first.isIntersecting) {
          incrementState();
        }
      },
      { threshold: 1 }
    );

}, [secondState]);  // note dependency here, ensures that each updates "sees" the new version of function

useEffect(() => {
  // observer and so on...
});

const { Component, useRef, useState, useEffect } = React;
const { render } = ReactDOM;

function App() {
  const thingRef = useRef();
  const [count, setCount] = useState(0);

  const incrementCounter = () => {
    setCount(prevCount => prevCount + 1);
  };

  const observer = useRef(
    new IntersectionObserver(
      entries => {
        const first = entries[0];
        if (first.isIntersecting) {
          incrementCounter();
        }
      },
      { threshold: 1 }
    )
  );

  useEffect(() => {
    const currentElement = thingRef.current;
    const currentObserver = observer.current;
    if (currentElement) {
      currentObserver.observe(currentElement);
    }
    return () => {
      if (currentElement) {
        currentObserver.unobserve(currentElement);
      }
    };
  }, []);

  return (
    <main style={{ height: "600vh", position: "relative" }}>
      <div
        ref={thingRef}
        style={{
          position: "absolute",
          top: "50%",
          left: "50%",
          transform: "translate(-50%, -50%)",
          height: '80vh',
          border: '1px solid pink',
          width: '98%',
          textAlign: 'center',
        }}
      >
        Thing
      </div>
      <p
        style={{
          backgroundColor: 'red',
          borderRadius: '50%',
          color: 'white',
          width: '20px',
          height: '20px',
          lineHeight: '20px',
          textAlign: 'center',
          position: 'fixed',
          top: '10px',
          right: '80px',
          margin: 0
        }}
      >{count}</p>
    </main>
  );
}

render(<App />, document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />
...