在单个useEffect

时间:2019-01-28 07:38:48

标签: reactjs react-hooks

我正在尝试使用新的React钩子功能,但跌跌撞撞了。

Fiddle

我有一个useEffect,它调用setInterval,它会更新本地状态。像这样:

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

  React.useEffect(() => {
    const k = setInterval(() => {
        setCounter(counter + 1);
    }, 1000);
    return () => clearInterval(k);
  }, []);

  return (
    <div>Counter via state: {counter}<br/></div>
  );

这行不通,因为计数器是在第一次调用时捕获的,因此计数器停留在1值上。

如果我使用refs,则会更新ref,但不会调用rerender(在UI中只会看到0值):

  const counterRef = React.useRef(0);

  React.useEffect(() => {
    const k = setInterval(() => {
      counterRef.current += 1;
    }, 1000);
    return () => clearInterval(k);
  }, []);

  return (
    <div>Counter via ref: {counterRef.current}</div>
  );

我可以通过组合它们来实现自己想要的东西,但实际上看起来并不正确:

  const [counter, setCounter] = React.useState(0);
  const counterRef = React.useRef(0);

  React.useEffect(() => {
    const k = setInterval(() => {
        setCounter(counterRef.current + 1);
      counterRef.current += 1;
    }, 1000);
    return () => clearInterval(k);
  }, []);

  return (
    <div>Counter via both: {counter}</div>
  );

您能告诉谁用钩子妥善处理此类案件吗?

2 个答案:

答案 0 :(得分:1)

useRef仅在不需要组件更新的情况下才有用。但是可以通过相同的方法解决在异步useEffect中访问当前状态的问题,即使用对象引用而不是不可变状态:

  const [state, setState] = React.useState({ counter: 0 });

  React.useEffect(() => {
    const k = setInterval(() => {
        state.counter++;
        setCounter(state);
    }, 1000);
    return () => clearInterval(k);
  }, []);

在React社区中不建议使用可变状态,因为它比不可变状态具有更多的缺点。

与类组件中的setState一样,状态更新程序功能可用于在状态更新期间获取当前状态:

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

  React.useEffect(() => {
    const k = setInterval(() => {
        setCounter(conter => counter + 1);
    }, 1000);
    return () => clearInterval(k);
  }, []);

或者,setTimeout可用于每秒设置新间隔:

  React.useEffect(() => {
    const k = setTimeout(() => {
        setCounter(counter + 1);
    }, 1000);
    return () => clearInterval(k);
  }, [counter]);

答案 1 :(得分:1)

到目前为止,我已经几次遇到这种情况了,我更喜欢的解决方案是使用useReducer而不是useState,就像这样:

  const [counter, dispatch] = React.useReducer((state = 0, action) => {
    // better declared outside of the component
    if (action.type === 'add') return state + 1
    return state
  });

  React.useEffect(() => {
    const k = setInterval(() => {
        dispatch({ type: 'add' });
    }, 1000);
    return () => clearInterval(k);
  }, []);

  return (
    <div>Counter via state: {counter}<br/></div>
  );

尽管添加了一些样板,但实际上简化了“何时考虑我的变量?”。 更多https://reactjs.org/docs/hooks-reference.html#usereducer