javascript - 使用 Promise Hooks React JS 跟踪组件外部的状态更新
问题描述
我有一个外部函数,它通过ref
和ImperativeHandler
钩子改变组件内部的状态
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 ...
}
但我不知道如何跟踪该状态已被更改,因为setState
钩子没有回调选项。如何跟踪外部函数(例如我的generator
示例)中状态更改的时刻?
解决方案
由于您正在使用钩子并且更新程序函数没有像类更新程序版本那样接收第二个参数,因此您可能希望自己实现一个带有第二个参数的更新程序:
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];
}
我们使用相同的签名创建自己
useState
的函数,一个接受初始状态并返回当前状态元组的函数和一个更新函数,但这次更新函数接受 2 个参数,下一个状态和一个回调。我们需要一种方法来存储传递给我们的更新程序的回调,我们可以将它存储在一个状态中,
useState
但是每次更新都会触发一个渲染,所以我们将它存储在一个 ref 中,该 ref 在渲染之间是持久的,但是是可变的,不会触发 re-更新时呈现。我们从一个null
值开始。我们存储和处理值的实际状态
useState
我们将一个效果同步到这个状态值并调用存储在我们的 ref 中的回调。我们有条件地这样做,因为效果将在任何状态更新之前的第一次渲染上运行(这就是我们使用 ref 开始的原因
null
)。我们创建自己的
updater
函数,将回调存储在我们的 ref 中(同时验证它确实是一个函数)并触发实际的状态更新。我们返回带有真实状态和自定义更新器的元组
运行示例:
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" />
推荐阅读
- node.js - 反应部署错误 = 断言 `args[1]->IsString()'
- ruby-on-rails - 继承外键rails
- c - 如何计算这个递归函数的时间复杂度?(英国夏令时)
- javascript - 如何在 django 中使用 ajax 从 javascript 调用 python 函数
- hashmap - 为什么 csv::Reader 记录中的字符串在插入 HashMap 时的寿命不够长?
- ios - NSBundle mainBundle 返回 nil
- xcode - XCODE 9.3.1 功能信息
- r - 在 R 中,如果我在“arg_233_1_3.RData”下有一个 RData 文件,我如何仅通过指定“arg”来调用它?
- ubuntu - 系统上有声音,但脉冲音频访问被拒绝问题
- ruby-on-rails - 根据标题和正文属性查找相似记录