考虑以下钩子示例
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>
}
}
但是我的查询是如何强制上述功能组件立即通过钩子重新渲染?
答案 0 :(得分:7)
简单代码
const forceUpdate = React.useReducer(bool => !bool)[1];
使用:
forceUpdate();
答案 1 :(得分:6)
useState
或useReducer
可以做到这一点,因为useState
在内部使用了useReducer
:
const [, updateState] = React.useState();
const forceUpdate = useCallback(() => updateState({}), []);
forceUpdate
不能在正常情况下使用,仅在测试或其他突出情况下使用。这种情况可能会以更常规的方式解决。
setCount
是不正确使用的forceUpdate
的一个示例。 setState
出于性能原因是异步的,不应仅由于状态更新未正确执行而被迫同步。如果状态依赖于先前设置的状态,则应使用updater function,
如果您需要基于先前的状态来设置状态,请阅读下面的updater参数。
<...>
由updater函数接收的状态和道具均得到保证 是最新的。更新程序的输出与 状态。
setCount
可能不是一个说明性示例,因为其用途尚不清楚,但更新程序功能就是这种情况:
setCount(){
this.setState(({count}) => ({ count: count + 1 }));
this.setState(({count2}) => ({ count2: count + 1 }));
this.setState(({count}) => ({ count2: count + 1 }));
}
答案 2 :(得分:6)
最好只让您的组件依赖状态和道具,并且它会按预期工作,但是如果您确实需要一个函数来强制重新渲染组件,则可以使用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/react@16.7.0-alpha.0/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
答案 3 :(得分:3)
单行解决方案:
const useForceUpdate = () => useState()[1];
useState 返回一对值:当前状态和一个更新状态的函数- state 和 setter ,这里我们仅使用设置器以强制重新渲染。
答案 4 :(得分:3)
一行解决方案:
const [,forceRender] = useReducer((s) => s+1, 0)
您可以在此处了解useReducer。 https://reactjs.org/docs/hooks-reference.html#usereducer
答案 5 :(得分:2)
正如其他人所提到的,useState
的工作原理-这是mobx-react-lite实现更新的方式-您可以执行类似的操作。
简化的代码如下-
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
答案 6 :(得分:2)
您可以像这样简单地定义useState:
const [, forceUpdate] = React.useState(0);
和用法:forceUpdate(n => !n)
希望获得帮助!
答案 7 :(得分:2)
react-tidy
有一个自定义钩子,专门用于执行useRefresh
:
import React from 'react'
import {useRefresh} from 'react-tidy'
function App() {
const refresh = useRefresh()
return (
<p>
The time is {new Date()} <button onClick={refresh}>Refresh</button>
</p>
)
}
免责声明。我是该库的作者。
答案 8 :(得分:2)
@MinhKha的答案的替代方法:
使用useReducer
可以更加清洁:
const [, forceUpdate] = useReducer(x => x + 1, 0);
用法:
forceUpdate()
-没有参数的清洁器
答案 9 :(得分:2)
通常,您可以使用任何要触发更新的状态处理方法。
const forceUpdate: () => void = React.useState()[1].bind(null, {}) // see NOTE below
const forceUpdate = React.useReducer(() => ({}), undefined)[1] as () => void
只需包装您喜欢的这种方法
function useForceUpdate(): () => void {
return React.useReducer(() => ({}), undefined)[1] as () => void // <- paste here
}
“ 触发更新” 的意思是告诉React引擎某些值已更改,应该重新渲染您的组件。
[, setState]
中的 useState()
需要一个参数。我们通过绑定新对象{}
来摆脱它。
() => ({})
中的useReducer
是伪减速器,每次分派动作时都会返回一个新对象。
{}
(新鲜对象)是必需的,以便通过更改状态中的引用来触发更新。
PS:useState
仅在内部包装useReducer
。 source
注意: 将.bind与useState一起使用会导致渲染之间的函数引用发生变化。可以将其包装在useCallback中,就像已经explained here一样,但是它不会是 sexy one-liner™。 Reducer版本已已保持渲染之间的引用相等。如果要在props中传递forceUpdate函数,这一点很重要。
const forceUpdate = React.useState()[1].bind(null, {}) // see NOTE above
const forceUpdate = React.useReducer(() => ({}))[1]
答案 10 :(得分:2)
这是React Hooks FAQ中的官方解决方案(forceUpdate
+功能组件):
const Test = () => {
const [_count, forceUpdate] = useReducer(x => x + 1, 0);
return (
<div>
<h3 onClick={forceUpdate}>Click me!</h3>
<p>Rendered {_count} times</p>
</div>
);
};
ReactDOM.render(<Test />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.1/umd/react.production.min.js" integrity="sha256-vMEjoeSlzpWvres5mDlxmSKxx6jAmDNY4zCt712YCI0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.1/umd/react-dom.production.min.js" integrity="sha256-QQt6MpTdAD0DiPLhqhzVyPs1flIdstR4/R7x4GqCvZ4=" crossorigin="anonymous"></script>
<script>var useReducer = React.useReducer</script>
<div id="root"></div>
答案 11 :(得分:2)
这将渲染3次依赖组件(元素相等的数组不相等):
const [msg, setMsg] = useState([""])
setMsg(["test"])
setMsg(["test"])
setMsg(["test"])
答案 12 :(得分:1)
您可以利用JSX代码中的 React不打印布尔值这一事实,使用(ab)普通钩子强制重新渲染
// create a hook
const [forceRerender, setForceRerender] = React.useState(true);
// ...put this line where you want to force a rerender
setForceRerender(!forceRerender);
// ...make sure that {forceRerender} is "visible" in your js code
// ({forceRerender} will not actually be visible since booleans are
// not printed, but updating its value will nonetheless force a
// rerender)
return (
<div>{forceRerender}</div>
)
答案 13 :(得分:0)
有很多方法可以在 Hook 中强制重新渲染。
对我来说使用 useState()
和参考对象值提示的简单方法。
const [, forceRender] = useState({});
// Anywhre
forceRender({});
答案 14 :(得分:0)
现在还有一个小的 npm包:use-force-update。由于功能的命名和封装清晰,我认为它比此处介绍的解决方法更好。
答案 15 :(得分:0)
我对forceUpdate
的变化不是通过counter
而是通过对象:
// Emulates `forceUpdate()`
const [unusedState, setUnusedState] = useState()
const forceUpdate = useCallback(() => setUnusedState({}), [])
因为每次{} !== {}
。
答案 16 :(得分:0)
对于常规的基于React Class的组件,请访问位于this URL的forceUpdate
api的React Docs。文档提到:
通常,您应尽量避免仅使用forceUpdate()并仅 从render。)中的this.props和this.state中读取
但是,文档中也提到:
如果您的render()方法依赖于其他数据,则可以告诉React 该组件需要通过调用forceUpdate()重新呈现。
因此,尽管使用forceUpdate
的用例可能很少见,而且我从未使用过,但是我看到其他开发人员在我从事的一些传统公司项目中使用了它。
因此,对于功能组件的等效功能,请参考位于this URL的React Docs for HOOKS。根据上述URL,可以使用“ useReducer”挂钩为功能组件提供forceUpdate
功能。
下面提供了一个有效的代码示例that does not use state or props
,也可以在CodeSandbox的this URL上找到它
import React, { useReducer, useRef } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
// Use the useRef hook to store a mutable value inside a functional component for the counter
let countref = useRef(0);
const [, forceUpdate] = useReducer(x => x + 1, 0);
function handleClick() {
countref.current++;
console.log("Count = ", countref.current);
forceUpdate(); // If you comment this out, the date and count in the screen will not be updated
}
return (
<div className="App">
<h1> {new Date().toLocaleString()} </h1>
<h2>You clicked {countref.current} times</h2>
<button
onClick={() => {
handleClick();
}}
>
ClickToUpdateDateAndCount
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
注意:this URL也提供了一种使用useState钩子(而不是useReducer)的替代方法。
答案 17 :(得分:0)
可能的选项是仅使用key
强制对特定组件进行更新。更新密钥会触发组件渲染(之前无法更新)
例如:
const [tableKey, setTableKey] = useState(1);
...
useEffect(() => {
...
setTableKey(tableKey + 1);
}, [tableData]);
...
<DataTable
key={tableKey}
data={tableData}/>