Бесконечный цикл React крючки - PullRequest
3 голосов
/ 06 марта 2019

Я не понимаю, почему я получаю бесконечный цикл в useClick Я вижу, что я изменяю значение состояния внутри useEffect , используя setVal , но useEffect должно работатьтолько на onClick, как указано во втором парам.Я думал, что это потому, что параметр onClick, который я передаю, запоминается, но обратный вызов не вызывается (я проверил, используя console.log ('go set')

function useClick(onClick, setVal, val) {
  React.useEffect(() => {
    console.log('Click');
    setVal(val + 1);
  }, [onClick]);
}

const Home = () => {
  const [val, setVal] = React.useState(0);
  const incrementOnClick = React.useCallback(() => {
    console.log('go set');
    setVal(val + 1);
  } , [setVal, val]);
  useClick(incrementOnClick, setVal, val);
  return <div>
    <div>{val}</div>
    <button onClick={incrementOnClick}>Click me</button>
 </div>
}

Ответы [ 2 ]

5 голосов
/ 06 марта 2019

val и setVal будут меняться при каждом рендеринге, что, в свою очередь, приведет к тому, что incrementOnClick станет новой ссылкой на функцию, и ваш useClick эффект всегда будет вызываться.

Вместо этого вы можете дать функцию в качестве первого аргумента для setVal. Эта функция получает текущий val в качестве аргумента и возвращает новое значение. Таким образом, incrementOnClick всегда будет одной и той же функцией.

const { useEffect, useState, useCallback } = React;

function useClick(onClick, setVal, val) {
  useEffect(() => {
    console.log("Click");
    setVal(val + 1);
  }, [onClick]);
}

const Home = () => {
  const [val, setVal] = useState(0);
  const incrementOnClick = useCallback(() => {
    console.log("go set");
    setVal(val => val + 1);
  }, []);

  useClick(incrementOnClick, setVal, val);

  return (
    <div>
      <div>{val}</div>
      <button onClick={incrementOnClick}>Click me</button>
    </div>
  );
};

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

<div id="root"></div>

Приведенный выше код показывает, как вы можете выйти из бесконечного цикла и быть полезным для экспериментов, но в большинстве случаев это не нужно. Вместо этого вы можете написать такую ​​же функциональность, как эта:

const { useState } = React;

const Home = () => {
  const [val, setVal] = useState(1);
  
  return (
    <div>
      <div>{val}</div>
      <button onClick={() => setVal(val + 1)}>Click me</button>
    </div>
  );
};

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

<div id="root"></div>
0 голосов
/ 06 марта 2019

Глядя на то, что вы пытаетесь сделать, я считаю, что вы упустили одну из самых полезных функций Hooks & React, и это композиция.

Вот пример того, что вы сделали, но просто создаете другоеКомпонент называется <IncrementButton/>, для меня это просто делает код намного проще для понимания / отладки.Кастомные хуки хороши, но я считаю, что это неправильный инструмент.

const { useEffect, useState } = React;

const IncrementButton = props => {
  const {val, setVal, children} = props;
  return <button
    onClick={() => setVal(val + 1)}
  >{children}</button>;
}

const Home = () => {
  const [val, setVal] = useState(0);
  return (
    <div>
      <div>{val}</div>
      <IncrementButton val={val} setVal={setVal}>
        Click me
      </IncrementButton>
    </div>
  );
};

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

<div id="root"></div>
...