考虑下面的钩子示例
import { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
基本上我们使用this.forceUpdate()方法强制组件立即在React类组件中重新渲染,如下例所示
class Test extends Component{
constructor(props){
super(props);
this.state = {
count:0,
count2: 100
}
this.setCount = this.setCount.bind(this);//how can I do this with hooks in functional component
}
setCount(){
let count = this.state.count;
count = count+1;
let count2 = this.state.count2;
count2 = count2+1;
this.setState({count});
this.forceUpdate();
//before below setState the component will re-render immediately when this.forceUpdate() is called
this.setState({count2: count
}
render(){
return (<div>
<span>Count: {this.state.count}></span>.
<button onClick={this.setCount}></button>
</div>
}
}
但我的查询是如何强制上面的功能组件立即用钩子重新渲染?
这可能与useState
或useReducer
,因为useState
内部使用useReducer
:
const [, updateState] = React.useState();
const forceUpdate = useCallback(() => updateState({}), []);
forceUpdate
不适合在正常情况下使用,仅用于测试或其他未决案件。可以以更传统的方式解决这种情况。
setCount
是使用不当的forceUpdate
的一个例子。由于性能原因,setState
是异步的,因为状态更新没有正确执行,所以不应强制同步。如果一个州依赖于先前设定的状态,这应该用updater function完成,
如果需要根据以前的状态设置状态,请阅读下面的updater参数。
<...>
更新程序功能接收的状态和道具都保证是最新的。 updater的输出与state轻微合并。
setCount
可能不是一个说明性的例子,因为它的目的不明确但更新器功能的情况如下:
setCount(){
this.setState(({count}) => ({ count: count + 1 }));
this.setState(({count2}) => ({ count2: count + 1 }));
this.setState(({count}) => ({ count2: count + 1 }));
}
您应该最好只让您的组件依赖于状态和道具,它将按预期工作,但如果您真的需要一个强制组件重新渲染的函数,您可以使用useState
钩子并在需要时调用该函数。
例
const { useState, useEffect } = React;
function Foo() {
const [, forceUpdate] = useState();
useEffect(() => {
setTimeout(forceUpdate, 2000);
}, []);
return <div>{Date.now()}</div>;
}
ReactDOM.render(<Foo />, document.getElementById("root"));
<script src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
<div id="root"></div>
正如其他人提到的那样,useState
的工作原理 - 这就是mobx-react-lite如何实现更新 - 你可以做类似的事情。
定义一个新钩子,useForceUpdate
-
export function useForceUpdate() {
const [, setTick] = useState(0);
const update = () => {
setTick(tick => tick + 1);
})
return update;
}
并在组件中使用它 -
const forceUpdate = useForceUpdate();
if (...) {
forceUpdate(); // force re-render
}
见https://github.com/mobxjs/mobx-react-lite/blob/master/src/utils.ts和https://github.com/mobxjs/mobx-react-lite/blob/master/src/useObserver.ts
您可以像这样简单地定义useState:
const [, forceUpdate] = React.useState(0);
用法:forceUpdate(n => !n)
希望这有帮助!