简体   繁体   English

跟踪 state 在组件外部使用 promise Hooks React JS 更新

[英]Track that state is updated outside of a component with promise Hooks React JS

I have an external function that changes a state inside a component thru ref and ImperativeHandler hook我有一个外部 function 通过refImperativeHandler挂钩更改组件内的 state

const [state, setState] = useState(0);

// inside component
const testFunc = () => {
   setState(1)
}

// outside of component
function *generator {
    yield ...
    yield testFunc()
    // next yield should wait till state is updated, only then it can be executed 
    yield ...
}

but I can't figured out how to track that state has been chaged, since setState hook has no callback option.但我不知道如何跟踪 state 已被更改,因为setState挂钩没有回调选项。 How can I track the moment when the state changed in the outside function such as my generator example?如何跟踪 state 在外部 function 中发生变化的时刻,例如我的generator示例?

Since you are using hooks and the updater function doesn't receive a 2nd argument like the class updater version, you might want to implement an updater with a 2nd argument on your own:由于您正在使用钩子并且更新程序 function 没有收到像 class 更新程序版本这样的第二个参数,您可能希望自己实现一个带有第二个参数的更新程序:

function useStateWithCallback(initState) {
  const cbRef = useRef(null);

  const [state, setState] = useState(initState);

  useEffect(() => {
    if (cbRef.current) {
      cbRef.current(state);
      cbRef.current = null;
    }
  }, [state]);

  const updater = (value, callback) => {
    cbRef.current = typeof callback === "function" ? callback : null;
    setState(value);
  };

  return [state, updater];
}
  • We create our own useState with the same signature, a function that accept an initial state and returns a tuple of the current state and an update function, but this time the updater function takes 2 arguments, the next state and a callback. We create our own useState with the same signature, a function that accept an initial state and returns a tuple of the current state and an update function, but this time the updater function takes 2 arguments, the next state and a callback.

  • We need a way to store the callback passed to our updater, we could store it inside a state with useState but each update will trigger a render so we are storing it in a ref which is persistent across renders but mutable and won't trigger re-renders when updated.我们需要一种方法来存储传递给更新程序的回调,我们可以将它存储在useState中,但每次更新都会触发渲染,所以我们将它存储在一个 ref 中,该 ref 在渲染中是持久的,但可变并且不会触发重新- 更新时渲染。 We start with a null value.我们从null值开始。

  • We store and handle the actual state of the value with useState我们使用 useState 存储和处理值的实际useState

  • We sync an effect to this state value and calling the callback stored in our ref.我们将效果同步到这个 state 值并调用存储在我们的参考中的回调。 We do that conditionally as the effect will run on the first render before any state been updated (this is why we start the ref with null ).我们有条件地这样做,因为效果将在任何 state 更新之前的第一次渲染上运行(这就是我们以null开头的原因)。

  • We create our own updater function which store the callback in our ref (while validating that its indeed a function) and trigger the actual state update.我们创建自己的updater function 将回调存储在我们的 ref 中(同时验证它确实是一个函数)并触发实际的 state 更新。

  • We return our tuple with the real state and our custom updater我们用真正的 state 和我们的自定义更新程序返回我们的元组

Running example:运行示例:

 const {useState, useRef, useEffect} = React; function useStateWithCallback(initState) { const cbRef = useRef(null); const [state, setState] = useState(initState); useEffect(() => { if (cbRef.current) { cbRef.current(state); cbRef.current = null; } }, [state]); const updater = (value, callback) => { cbRef.current = typeof callback === "function"? callback: null; setState(value); }; return [state, updater]; } function App() { const [count, setCount] = useStateWithCallback(0); const myCallback = currentState => console.log("currentState", currentState); const onClick = () => { setCount(c => c + 1, myCallback); }; return <button onClick={onClick}>{count}</button>; } const rootElement = document.getElementById("root"); ReactDOM.render( <App />, rootElement );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script> <div id="root" />

You can create a special case for this promise:您可以为此 promise 创建一个特殊情况:

// inside imperative handle
specialStateSetter: () => {
  // your logic/tracker here
  setState({ value: 0 })
}

since setState has no callback option因为 setState 没有回调选项

setState can be passed a second argument, which is a callback function executed after state has been updated. setState可以传递第二个参数,它是在 state 更新后执行的回调 function。

ref: https://fr.reactjs.org/docs/react-component.html#setstate参考: https://fr.reactjs.org/docs/react-component.html#setstate

since setState has no callback option How can I track the moment when the state changed因为 setState 没有回调选项我如何跟踪 state 更改的时刻

You're wrong.你错了。 There's callback for setState : setState有回调:

setState(() => ({ value: 0 }), callback)

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

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