React Hooks中的useState与回调函数

3

我正在尝试找到一种使用hooks来模拟this.setState({},() => {})回调函数的方法。

我成功地创建了一个方法,模仿了useState函数,但返回一个带有更新后数据的回调函数。

接收回调函数在状态更新后返回,可以从日志中看到,只有在出现console.log("App")后,才会接收回调函数,这类似于如果使用this.statecallback的行为。

问题是,在修改过的setStatecallback内部,即使在更新应用程序后调用,我也无法看到状态的更新,也就是说,如果我尝试打印它,我不会看到更新的状态。

您认为是否有解决方案,能够做些什么来查看其更新。

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>


1
هڈھ需è¦پن½؟用useEffect(() => { /* code here */ }, [stateObj]);م€‚https://codesandbox.io/s/ecstatic-sun-exww1 - user5734311
2个回答

1
使用hooks后,当状态更新时,你已经获得一个回调:组件函数会再次被调用。这是hooks的一个基本方面,更新状态会使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在这里有一篇很好的文章,深入阐述了这个概念。虽然这篇文章是在解释useEffect的上下文中写的,但它所奠定的基础应该会有所帮助。


1
但是组件在道具更改或其他状态更新时也会重新渲染。在我看来,使用useEffect会更准确。 - undefined
1
@JonasWilms - 是的,这取决于OP实际想要做什么,越来越不确定我是否理解了。 :-) - undefined
喜欢这样的文章,非常精彩。 - undefined

0
如果我正确理解你想要做的事情,我认为你只需要将新的状态值作为参数传递给回调函数即可。这样你就不需要将它保存在一个ref中,也不需要从useEffect中更新它。
function useStateCallback(initialState) {
    const [state, setState] = useState(initialState);

    return [
        state,
        (value, callback) => {
            setState(value);

            if (typeof callback === "function") {
                callback(value);
            }
        }
    ];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接