代码之家  ›  专栏  ›  技术社区  ›  Paul

使用回调对状态做出反应

  •  1
  • Paul  · 技术社区  · 6 年前

    我在想办法模仿 callback 功能 this.setState({},() => {}) 但是用钩子。

    我设法创造了一种模仿 useState 函数,但返回一个回调,其中包含更新数据的更改结果。

    从日志中可以看出,状态更新后,回调的接收返回,回调的接收仅在状态更新后返回 console.log("App") 看起来,它的行为类似于当它被用于 this.state 用一个 回拨 .

    问题在于 回拨 修改后的 setState ,即使在更新应用程序后调用它,我也看不到状态的更新,也就是说,在它内部,如果我试图打印它,我看不到更新的状态。

    根据你的说法,有一个解决方案,可以做一些事情来看到它的更新。

    const { useState, useRef, useEffect } = React;
    
    function useStateCallback(initialState) {
      const [state, setState] = useState(initialState);
      const cbRef = useRef(null);
      useEffect(() => {
        if (cbRef.current) {
          cbRef.current(state);
          cbRef.current = null;
        }
      }, [state]);
      return [
        state,
        (value, cb) => {
          cbRef.current = typeof cb === "function" ? cb : null;
          setState(value);
        }
      ];
    }
    
    const App =() => {
    
      const [stateObj, setStateObj] = useStateCallback({
        name: "James",
        surname: "Bond",
        number: 7
      });
      const { name, surname, number } = stateObj;
    
      useEffect(() => {
        //console.log("componentDidMount", stateObj);
        //console.log("componentDidMount2", stateObj);
        //console.log("useEffect", stateObj);
      }, []);
    
      const change = () => {
        //console.log("componentDidMount", stateObj);
        setStateObj(
          previousValue => ({
            ...previousValue,
            name: "Arthur",
            surname: "Conan",
            number: previousValue.number + 14
          }),
          res => {
            console.log("Res:", res, stateObj);
          }
        );
        //console.log("componentDidMount2", stateObj);
      };
    
      console.log("App", stateObj);
    
      return (
        <div>
          Name: {name}
          <br />
          Surname: {surname}
          <br />
          Number: {number}
          <br />
          <button onClick={change}>Change</button>
          <button onClick={() => console.log(stateObj)}>Render</button>
        </div>
      );
    }
    
    ReactDOM.render(
      <App />,
      document.getElementById("root")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    
    <div id="root"></div>
    2 回复  |  直到 6 年前
        1
  •  0
  •   T.J. Crowder    6 年前

    用钩子,你 已经 状态更新后获取回调:再次调用组件函数。这是钩子的一个基本方面,更新状态会使React再次调用组件函数。

    例子:

    const { useState } = React;
    
    const Example = () => {
        const [counter, setCounter] = useState(0);
        console.log(`Example called, counter = ${counter}`);
        return (
            <div>
                {counter} <input type="button" value="+" onClick={() => setCounter(c => c + 1)} />
            </div>
        );
    };
    
    ReactDOM.render(<Example />, document.getElementById("root"));
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>

    不需要任何其他setter回调。组件 回拨电话。

    丹·阿布拉莫夫(Dan Abramov)写了一篇很好的文章,这篇文章让这个家庭深受感动 here .这是在解释 useEffect 但是它的基础应该有帮助。

        2
  •  0
  •   Alvaro    6 年前

    如果我理解了您试图正确执行的操作,我认为您只需要将新的状态值作为参数传递给回调调用。这样你就不需要把它保存在 ref 也不能从 useEffect :

    function useStateCallback(initialState) {
        const [state, setState] = useState(initialState);
    
        return [
            state,
            (value, callback) => {
                setState(value);
    
                if (typeof callback === "function") {
                    callback(value);
                }
            }
        ];
    }