代码之家  ›  专栏  ›  技术社区  ›  Hemadri Dasari

如何在React中使用钩子强制组件重新渲染?

  •  3
  • Hemadri Dasari  · 技术社区  · 7 年前

    考虑以下挂钩示例

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

    基本上我们使用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>
            }
     }
    

    2 回复  |  直到 7 年前
        1
  •  67
  •   Estus Flask    6 年前

    这是可能的 useState 或 useReducer useState uses useReducer internally

    const [, updateState] = React.useState();
    const forceUpdate = React.useCallback(() => updateState({}), []);
    

    forceUpdate 不打算在正常情况下使用,仅用于测试或其他悬而未决的情况。这种情况可以用更传统的方式来解决。

    setCount 强制更新 setState 出于性能原因是异步的,不应仅仅因为状态更新未正确执行而强制同步。如果依赖于此状态,则应设置此状态 updater function

    如果需要根据以前的状态设置状态,请阅读下面的updater参数。

    <…>

    更新程序函数接收的状态和属性都得到保证 国家。

    集合计数 可能不是一个说明性的例子,因为它的目的不明确,但更新程序函数就是这样:

    setCount(){
      this.setState(({count}) => ({ count: count + 1 }));
      this.setState(({count2}) => ({ count2: count + 1 }));
      this.setState(({count}) => ({ count2: count + 1 }));
    }
    

       const [state, setState] = useState({ count: 0, count2: 100 });
    
       const setCount = useCallback(() => {
         setState(({count}) => ({ count: count + 1 }));
         setState(({count2}) => ({ count2: count + 1 }));
         setState(({count}) => ({ count2: count + 1 }));
       }, []);
    
        2
  •  24
  •   Brian Burns Yugansh    7 年前

    正如其他人提到的, 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

        3
  •  16
  •   Qwerty    6 年前

    codesandbox example

    使用状态

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

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

    作为自定义挂钩

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

    这是怎么回事?

    " 触发更新 " 意味着告诉React引擎某些值已更改,它应该重新呈现组件。

    [, setState] useState() 需要参数。我们通过绑定一个新对象来消除它 {}
    () => ({}) 在里面 useReducer 是一个虚拟的reducer,它在每次调度操作时返回一个新对象。
    (新对象) 是必需的,以便它通过更改状态中的引用触发更新。

    useState 只是包装 内部。 source

    注: explained here 但那就不会是 性感的一条线 . 减速机版本 渲染之间的引用相等。如果要在道具中传递forceUpdate函数,这一点很重要。

    普通JS

    const forceUpdate = React.useState()[1].bind(null, {})  // see NOTE above
    const forceUpdate = React.useReducer(() => ({}))[1]
    
        4
  •  11
  •   nullspace    6 年前

    它可以更干净 useReducer :

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

    forceUpdate() -无参数的清洁器

        5
  •  10
  •   Tholle    7 年前

    最好只让组件依赖于状态和道具,它将按预期工作,但如果确实需要一个函数来强制组件重新呈现,则可以使用 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>
        6
  •  10
  •   Minh Kha    7 年前

    您可以这样简单地定义useState:

    const [, forceUpdate] = React.useState(0);
    

    和用法: forceUpdate(n => !n)

    希望你能帮上忙!

        7
  •  5
  •   Fergie    7 年前

    React不打印布尔值

    // 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>
    )
    
    
        8
  •  5
  •   GilCarvalhoDev    6 年前

    简单代码

    const forceUpdate = React.useReducer(bool => !bool)[1];
    

    forceUpdate();
    
        9
  •  5
  •   ford04    6 年前

    React Hooks FAQ forceUpdate :

    const [_, forceUpdate] = useReducer((x) => x + 1, 0);
    // usage
    <button onClick={forceUpdate}>Force update</button>
    

    const App = () => {
      const [_, forceUpdate] = useReducer((x) => x + 1, 0);
    
      return (
        <div>
          <button onClick={forceUpdate}>Force update</button>
          <p>Forced update {_} times</p>
        </div>
      );
    };
    
    ReactDOM.render(<App />, 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>
        10
  •  4
  •   think-serious    6 年前

    一行解决方案:

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

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

        11
  •  3
  •   arielhad    6 年前

    一线解决方案:

    const useForceUpdate = () => useState()[1];

    返回一对值:当前状态和更新它的函数- 状态 和 设定者 ,这里我们只使用setter来强制重新渲染。

        12
  •  2
  •   Idan    7 年前

    可能的选择是使用 key . 更新密钥会触发组件的呈现(之前未能更新)

    例如:

    const [tableKey, setTableKey] = useState(1);
    ...
    
    useEffect(() => {
        ...
        setTableKey(tableKey + 1);
    }, [tableData]);
    
    ...
    <DataTable
        key={tableKey}
        data={tableData}/>
    
        13
  •  2
  •   Janek Olszak    6 年前

    这将渲染依赖组件3次(元素相等的数组不相等):

    const [msg, setMsg] = useState([""])
    
    setMsg(["test"])
    setMsg(["test"])
    setMsg(["test"])
    
        14
  •  1
  •   Alan C. S.    7 年前

    对于基于React类的常规组件,请参阅React文档 forceUpdate api在 this 网址。文件中提到:

    通常,您应该尽量避免使用forceUpdate()并且只 从这个。道具以及这个州在render()中

    如果render()方法依赖于其他数据,则可以判断React 组件需要通过调用forceUpdate()重新呈现。

    所以,尽管使用 强制更新 可能很少见,而且我从来没有使用过它,但是我看到其他开发人员在我所从事的一些遗留企业项目中使用过它。

    this 网址。根据上面的URL,可以使用“useReducer”钩子来提供 强制更新 功能组件的功能。

    工作代码示例 that does not use state or props 在下面提供,它也可以在CodeSandbox上获得 this 统一资源定位地址

    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);
    

    注意:使用useState钩子(而不是useReducer)的另一种方法也可以在 this 网址。

        15
  •  1
  •   catamphetamine    6 年前

    我的变体 forceUpdate 不是通过 counter 而是通过一个对象:

    // Emulates `forceUpdate()`
    const [unusedState, setUnusedState] = useState()
    const forceUpdate = useCallback(() => setUnusedState({}), [])
    

    {} !== {} 每一次。

        16
  •  -2
  •   omakoleg    6 年前

    你可以用前面提到的 key

    在这里阅读更多 https://kentcdodds.com/blog/understanding-reacts-key-prop

        17
  •  -3
  •   nachtigall    6 年前

    为此: use-force-update . 由于明确的命名和将功能封装在一个包中,我认为它比这里介绍的解决方法更好。