【问题标题】:How can i synchronise hooks我怎样才能同步钩子
【发布时间】:2021-07-06 14:07:24
【问题描述】:

过去,我是这样编写 reactjs 代码的:

  class App extends Component {
    state = { var1:null, var2:null, var3:null };
    
    myfunction1 = async () => {
       ...
       this.setState({ var1:10, var2:20, var3:30 }, this.myfunction2); 
    }

    myfunction2 = async () => {
       ...
    };

    render() {
       console.log("render");
       return (
          <div className="App">
            { this.state.var1 }
            { this.state.var2 }
            { this.state.var3 }
          </div>
       );
    }

现在,我正在这样工作:

const App = () => {
  const [var1, setVar1] = useState(null);
  const [var2, setVar2] = useState(null);
  const [var3, setVar3] = useState(null);

  async function init() {
     setVar1(10);
     setVar2(20);
     setVar3(30);
     function2();
  }

  useEffect(() => { init(); }, []);

  async function function2() {

  }

  console.log("render");
  return (
          <div className="App">
            { var1 }
            { var2 }
            { var3 }
          </div>
       );

这是我在第二种方式中遇到的问题:

  • 有没有办法让 setVar1、setVar2 和 setVar3 在同一个调用中?问题是页面将被刷新 3 次。在第一次刷新时,var1 将等于 10,但 var2 和 var3 将为空。这可能会导致一些问题...

  • 我如何确定在设置 var1、var2 和 var3 之后会调用 function2?在第一种方法中,有一个回调函数,仅在设置状态时调用。我怎样才能在第二种方法中做同样的事情?

谢谢

【问题讨论】:

标签: reactjs react-hooks


【解决方案1】:

请注意,您的两个示例不等价,您需要有一个单独的状态对象,这样它们才可以。

有没有办法在同一个调用中创建 setVar1、setVar2 和 setVar3 ?

您实际上是在问how to batch state changes,React 不像您 (async) 那样批量承诺调用

要么将 Promise 调用更改为普通调用,要么尝试一个常见的解决方案,比如拥有一个状态对象。

useState({ var1: null, var2: null, var3: null })

我如何确定 function2 将在 init 之后被调用

您正在使用异步调用,因此只需在第一次调用解决后调用function2。或者你可以有一个布尔引用来表明你在 init 呼叫之后,similar logic on having useEffect stop running after mount

完整示例:

const App = () => {
  const [state, setState] = useState({ var1: null, var2: null, var3: null });

  // or
  const isInitCalled = useRef(false);

  function function2() {
    console.log("after");
  }

  useEffect(async () => {
    async function init() {
      setVar1({ var1: 10, var2: 20, var3: 30 });
      function2();
    }

    await init();
    function2();
  }, []);

  // Or
  useEffect(() => {
    init();
    isInitCalled.current = true;
  }, []);

  useEffect(() => {
    if (isInitCalled.current) {
      func2();
    }
  }, [state]);

  return (
    <div className="App">
      {var1}
      {var2}
      {var3}
    </div>
  );
};

【讨论】:

    【解决方案2】:

    您可以使用数组或对象来代替原始值:

    const App = () => {
      const [vars, setVars] = useState([null, null, null]);
    
      async function init() {
         setVars([10, 20, 30]);
         function2();
      }
    
      useEffect(() => { init(); }, []);
    
      async function function2() {
    
      }
    
      console.log("render");
      return (
              <div className="App">
                { vars[0] }
                { vars[1] }
                { vars[2] }
              </div>
           );
    

    当然,如果您的实际 'vars' 没有编号,您可能更喜欢具有属性的对象而不是数组。

    【讨论】:

    • 非常感谢,我知道我可以使用数组,但它的可读性不是很好。还有其他方法吗?谢谢
    • 是的,如前所述,对象。
    【解决方案3】:

    有没有办法让 setVar1、setVar2 和 setVar3 在同一个调用中?问题是页面将被刷新 3 次。在第一次刷新时,var1 将等于 10,但 var2 和 var3 将为空。这可能会导致一些问题...

    首先,我只想指出它不一定会渲染多次。如果代码在 react 中开始执行(例如,useEffect 或合成事件),那么 react 将批量处理多个状态更改并且只进行一次重新渲染。但确实在某些情况下,react 并没有开始执行,所以执行不会返回到 react,所以 react 没有选择,只能立即重新渲染。例如,如果您在 setTimeout 回调中设置状态,或者在 await 执行承诺之后,就会发生这种情况。

    如果你需要多次设置状态,只需要一次重新渲染,你可以使用unstable_batchedUpdates

    import { unstable_batchedUpdates } from 'react';
    
    // ...
    async function init() {
       unstable_batchedUpdates(() => {
         setVar1(10);
         setVar2(20);
         setVar3(30);    
       })
    
       function2();
    }
    

    术语“不稳定”是 react 团队的说法,即这个 api 可能会在下一个主要版本的 react 中发生变化。但是它使用起来是完全安全的,只要你在升级你的 react 版本时注意这一点。

    我如何确定在设置 var1、var2 和 var3 之后会调用 function2?在第一种方法中,有一个回调函数,仅在设置状态时调用。我怎样才能在第二种方法中做同样的事情?

    在函数组件中设置状态并不能知道组件何时重新呈现。那可能是因为它没有任何好处。没有 this 正在发生变异,因此无论经过多长时间,function2 都不会看到新值。它的闭包中有来自当前渲染的值,并且无法访问下一个渲染。

    相反,修复最有可能将新值传递给 function2。例如,如果它需要知道 var1 正在变为 10,则需要将 10 传递进去。

    async function init() {
       const newVar1 = 10;
       unstable_batchedUpdates(() => {
         setVar1(newVar1);
         setVar2(20);
         setVar3(30);    
       })
    
       function2(newVar1);
    }
    
    async function function2(newVar1) {
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-28
      • 2016-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多