简体   繁体   English

仅在特定的 setState() 上执行 useEffect()

[英]Execute useEffect() only on specific setState()

I am using a hook component and several state variables.我正在使用一个钩子组件和几个 state 变量。 I have read about using useEffect() with params to get a kind of callback after updating a state.我已经阅读了有关在更新 state 后使用带有参数的useEffect()来获得一种回调的信息。 Example:例子:

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

In this example, useEffect() would be executed on every setVar() call.在此示例中,将在每个setVar() useEffect()上执行 useEffect()。 In my case, I do not want to execute useEffect() everytime, but only on specific occasions.就我而言,我不想每次都执行useEffect() ,而只是在特定情况下执行。 I would like to give the setVar() some kind of information which I can use in useEffect() like setVar(newValue, true) .我想给setVar()一些我可以在useEffect()中使用的信息,比如setVar(newValue, true)

Note: I do not want to store this information in var.注意:我不想将此信息存储在 var 中。

Is there a way to do this?有没有办法做到这一点?

Like Nizar said, simple conditional check on 'var' in useEffect就像 Nizar 所说,在 useEffect 中对 'var' 进行简单的条件检查

If expensive calc you can如果计算昂贵,你可以

const expensiveValue = useMemo(() => {
    // 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(() => {
    //do things
    //expensiveValue only changes when you want it to from the memo
}, [expensiveValue])

Thank you sambomartin and Nizar for your input.感谢 sambomartin 和 Nizar 的意见。

For everyone looking for an answer: After some further research I found 3 possible solutions:对于所有寻找答案的人:经过进一步研究,我发现了 3 种可能的解决方案:

  1. Use a class component.使用 class 组件。 If you really are dependent on that state update to be completed switch to a class component, which allows you to give the setState() a callback as a second param.如果您确实依赖于要完成的 state 更新,请切换到 class 组件,它允许您为setState()提供回调作为第二个参数。
  2. Use the useRef hook to determine where your state update is comming from.使用useRef挂钩来确定 state 更新的来源。 You can use this information in the useEffect() method.您可以在useEffect()方法中使用此信息。
  3. Get independent from the state.独立于 state。 I used this solution and externalized my callback function with the drawback of giving it every parameter on every call, although they are present in the component the states are saved.我使用了这个解决方案并将我的回调 function 外部化,缺点是在每次调用时都给它每个参数,尽管它们存在于组件中并保存了状态。

As far as I know, the useEffect only triggers if the dependency value changes , not simply by executing setValue.据我所知, useEffect 仅在依赖值更改时触发,而不仅仅是通过执行 setValue。

I offer you three solutions, the first one, close to what you want but without using useEffect hook, the second one is an extension of the first one, that may be required if you need control over the previous state, and the third, more general, like comments say, though it won't be triggered if the state is the same, even if you execute setValue .我为您提供三个解决方案,第一个接近您想要的但不使用 useEffect 挂钩,第二个是第一个的扩展,如果您需要控制以前的 state,则可能需要,第三个,更多一般,就像评论说的那样,尽管如果 state 相同,即使您执行 setValue 也不会触发它

  1. First solution: Wrap your set value with another function that definitely controls what may happen after or before the new state:第一个解决方案:用另一个 function 包装您的设定值,这绝对控制在新 state 之后或之前可能发生的事情:
export default function MyComponent() {
  const [state, setState] = useState(null);

  const handleChangeSetState = (nextState, flag) => {
    if (flag) {
      specialUseCaseCb();
    }
    setState(nextState);
  };

  return <div>{/* ... */}</div>;
}
  1. Second solution: Wrap your set value with another function, like in the solution 1, and ask for the previous or next state within setState inner callback:第二种解决方案:用另一个 function 包装您的设置值,就像在解决方案 1 中一样,并在 setState 内部回调中询问上一个或下一个 state:
export default function MyComponent2() {
  const [state, setState] = useState(0);

  const handleChangeSetState = (increment, flag) =>
    setState((prevState) => {
      const nextState = prevState + increment;
      // you may need prevState or nextState for checking your use case
      if (flag) {
        specialUseCaseCb();
      }
      return nextState;
    });

  return <div>{/* ... */}</div>;
}
  1. Third solution: use useEffect hook to follow changes , remember though that setState won't re-trigger useEffect hook if the state is the same:第三种解决方案:使用 useEffect 挂钩来跟踪更改,但请记住,如果 state 相同,则 setState 不会重新触发 useEffect 挂钩:
export default function MyComponent3() {
  const [state, setState] = useState("");

  // notice that this will only be triggered if state changes
  useEffect(() => {
    if (state !== "my-special-use-case") return;
    specialUseCaseCb();
  }, [state]);

  return <div>{/* ... */}</div>;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM