考虑下面的钩子示例

   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>
        }
 }

但我的问题是,我如何才能强制上述功能组件重新渲染立即与挂钩?


当前回答

通常,您可以使用任何想要触发更新的状态处理方法。

与打印稿

codesandbox例子

使用状态

const forceUpdate: () => void = React.useState({})[1].bind(null, {})  // see NOTE below

useReducer(推荐)

const forceUpdate = React.useReducer(() => ({}), {})[1] as () => void

作为自定义钩子

只要像这样包装你喜欢的任何方法

function useForceUpdate(): () => void {
  return React.useReducer(() => ({}), {})[1] as () => void // <- paste here
}

这是怎么回事?

“触发更新”意味着告诉React引擎某个值发生了变化,它应该重新渲染你的组件。

来自useState()的[,setState]需要一个参数。我们通过绑定一个新对象{}来摆脱它。 () =>({})在useReducer是一个虚拟的减速器,每次调度一个动作时返回一个新的对象。 {} (fresh对象)是必需的,这样它就可以通过改变状态中的引用来触发更新。

PS: useState只是在内部包装了useReducer,所以使用reducer来降低复杂性。源

注:参考不稳定性

使用.bind与useState一起使用会导致呈现之间的函数引用发生变化。 可以将它包装在useCallback中,就像在这里的回答中已经解释的那样,但这样它就不是一个性感的单行程序™了。Reducer版本已经在渲染之间保持了引用相等(稳定性)。如果你想把props中的forceUpdate函数传递给另一个组件,这很重要。

平原JS

const forceUpdate = React.useState({})[1].bind(null, {})  // see NOTE above
const forceUpdate = React.useReducer(() => ({}))[1]

其他回答

@MinhKha的回答:

使用useReducer可以更简洁:

const [, forceUpdate] = useReducer(x => x + 1, 0);

用法: forceUpdate() -没有参数的清洁器

在Hook中有许多强制重渲染的方法。

对我来说,使用useState()和引用对象值提示的简单方法。

const [, forceRender] = useState({});

// Anywhre
forceRender({});

Codesandbox例子

正如其他人提到的,useState工作-这是mobx-react-lite如何实现更新-你可以做一些类似的事情。

定义一个新的钩子useForceUpdate -

import { useState, useCallback } from 'react'

export function useForceUpdate() {
  const [, setTick] = useState(0);
  const update = useCallback(() => {
    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

单行解决方案:

const [,forceRender] = useReducer((s) => s+1, 0)

你可以在这里了解useReducer。 https://reactjs.org/docs/hooks-reference.html#usereducer

有点晚了,但我注意到大多数(所有)的答案都错过了可以传递回调到forceUpdate生命周期方法的部分。

根据react源代码,此回调具有与setState方法中的行为相同的行为-它在更新后执行。

因此,最正确的实现应该是这样的:

/** *增加导致重传并执行回调的状态 * @param {function}回调-状态更新后执行的回调 * @返回{函数} * / export const useForceUpdate = (callback) => { const [state, updater] = useReducer((x) => x + 1,0); useEffect(() => { Callback && Callback (); },[状态]); 返回useCallback(() => { 更新(); },[]); };