Реагирующие крючки бесконечного цикла

#javascript #reactjs #react-hooks

#javascript #reactjs #реагирующие крючки

Вопрос:

Я не понимаю, почему я получаю бесконечный цикл в 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>
}
  

Комментарии:

1. Я думаю, что цикл вызван вызовом useClick inside Home Component: Home вызывает useClick , внутри useClick вы изменяете val свойство Home , таким образом, Home компонент ` повторно отображается, таким образом, функция Home вызывается снова, таким образом, useClick выполняется снова.. И вот цикл

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

3. Да, именно поэтому я использую функцию useCallback, чтобы избежать

Ответ №1:

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>  

Ответ №2:

Глядя на то, что вы пытаетесь сделать, я считаю, что вам не хватает одной из самых полезных функций Hooks amp; 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>  

Комментарии:

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