Выполните useEffect() только для определенного состояния набора()

#javascript #reactjs #react-hooks #callback #use-effect

Вопрос:

Я использую компонент hook и несколько переменных состояния. Я читал об использовании useEffect() с параметрами для получения своего рода обратного вызова после обновления состояния. Пример:

 export const hookComponent = () =gt; {  const [var, setVar] = useState(null);  useEffect(() =gt; {  //do things  }, [var]) }  

В этом примере useEffect() будет выполняться при каждом setVar() вызове. В моем случае я не хочу выполнять useEffect() каждый раз, а только в определенных случаях. Я хотел бы предоставить setVar() некоторую информацию, которую я могу использовать в useEffect() подобных setVar(newValue, true) случаях .

Примечание: Я не хочу хранить эту информацию в var.

Есть ли способ сделать это?

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

1. в вашем useEffect просто проверьте, если var === desiredValue тогда //do things

2. В моем случае использования речь идет не только о значении, но и о действиях пользователя. setState не возвращает обещание, которого я мог бы дождаться в соответствующих экземплярах после набора. Или есть способ дождаться завершения состояния набора?

3. как, по-вашему, было предпринято это действие ? эта информация должна быть где-то собрана.

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

5. Похоже, что лучший способ подойти к этому-иметь другое состояние newVar , которое обновляется там, где вы хотели бы, чтобы вы useEffect запускали, и зависимости от этого были newVar бы, а не вашими var .

Ответ №1:

Как сказал Низар, простая условная проверка на «var» в действии

Если дорогой расчет, вы можете

 const expensiveValue = useMemo(() =gt; {  // other logic here if needed  // could even be simple return var=='x'?true:false, although this would be easier to do in the useEffect hook?  return computeExpensiveValue(var); },[var]);  useEffect(() =gt; {  //do things  //expensiveValue only changes when you want it to from the memo }, [expensiveValue])  

Ответ №2:

Спасибо вам, самбомартин и Низар, за ваш вклад.

Для всех, кто ищет ответ: После некоторых дальнейших исследований я нашел 3 возможных решения:

  1. Используйте компонент класса. Если вы действительно зависите от завершения обновления этого состояния, переключитесь на компонент класса, который позволяет вам передавать setState() обратный вызов в качестве второго параметра.
  2. Используйте useRef крючок, чтобы определить, откуда поступает обновление состояния. Вы можете использовать эту информацию в useEffect() методе.
  3. Станьте независимыми от государства. Я использовал это решение и экстернализировал свою функцию обратного вызова с недостатком, заключающимся в том, что при каждом вызове ей присваиваются все параметры, хотя они присутствуют в компоненте, состояния которого сохраняются.

Ответ №3:

Насколько я знаю, эффект использования срабатывает только при изменении значения зависимости, а не просто при выполнении setValue.

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

  1. Первое решение: Оберните установленное значение другой функцией, которая определенно контролирует, что может произойти после или до нового состояния:
 export default function MyComponent() {  const [state, setState] = useState(null);   const handleChangeSetState = (nextState, flag) =gt; {  if (flag) {  specialUseCaseCb();  }  setState(nextState);  };   return lt;divgt;{/* ... */}lt;/divgt;; }  
  1. Второе решение: Оберните установленное значение другой функцией, как в решении 1, и запросите предыдущее или следующее состояние во внутреннем обратном вызове setState:
 export default function MyComponent2() {  const [state, setState] = useState(0);   const handleChangeSetState = (increment, flag) =gt;  setState((prevState) =gt; {  const nextState = prevState   increment;  // you may need prevState or nextState for checking your use case  if (flag) {  specialUseCaseCb();  }  return nextState;  });   return lt;divgt;{/* ... */}lt;/divgt;; }  
  1. Третье решение: используйте крючок useEffect для отслеживания изменений, помните, что setState не будет повторно запускать крючок useEffect, если состояние то же самое:
 export default function MyComponent3() {  const [state, setState] = useState("");   // notice that this will only be triggered if state changes  useEffect(() =gt; {  if (state !== "my-special-use-case") return;  specialUseCaseCb();  }, [state]);   return lt;divgt;{/* ... */}lt;/divgt;; }  

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

1. Спасибо вам за ваш ответ. Первое решение-это то, о чем я подумал с первой попытки. Но в моем случае я хочу дождаться обновленного состояния, а затем выполнить обратный вызов. Если я правильно понял, то в вашем примере это не так, верно?

2. В третьем примере вы будете ждать обновления состояния, чтобы выполнить обратный вызов.

3. Но для содержания состояния используется, чтобы решить, выполнять мой обратный вызов или нет. Я не хотел вносить изменения в структуру государства