【问题标题】:Update state from axios call in useEffect hook在 useEffect 挂钩中从 axios 调用更新状态
【发布时间】:2020-02-07 16:22:01
【问题描述】:

我是新手,刚开始学习钩子和上下文。

我正在使用以下代码从 API 获取一些数据:

const getScreen = async uuid => {

    const res = await axios.get(
      `${url}/api/screen/${uuid}`
    );

    dispatch({
      type: GET_SCREEN,
      payload: res.data
    });
  };

接下来使用reducer。

case GET_SCREEN:
      return {
        ...state,
        screen: action.payload,
      };

在 Screen.js 中,我调用 getScreen 并发送 UUID 以显示确切的屏幕。效果很好。我遇到的问题是,当我尝试获取 API(每 3 秒进行一次测试)并根据从 API 中检索到的内容更新 nodeupdated 的状态时。问题是,screen.data 始终未定义(因为它是异步的?)

import React, {
  useState,
  useEffect,
  useContext,
} from 'react';
import SignageContext from '../../context/signage/signageContext';

const Screen = ({ match }) => {
  const signageContext = useContext(SignageContext);

  const { getScreen, screen } = signageContext;

  const [nodeupdated, setNodeupdated] = useState('null');

  const foo = async () => {
    getScreen(match.params.id);

    setTimeout(foo, 3000);
  };

  useEffect(() => {
    foo();
    setNodeupdated(screen.data)
  }, []);

如果我删除 [] 实际上确实从 api 获取数据...但是在无限循环中。

问题是,在我将其转换为钩子之前,这似乎工作得很好:

  componentDidMount() {
    // Get screen from UUID in url
    this.props.getScreen(this.props.match.params.id);

    // Get screen every 30.5 seconds
    setInterval(() => {
      this.props.getScreen(this.props.match.params.id);

      this.setState({
        nodeUpdated: this.props.screen.data.changed
      });
    }, 3000);
  }

【问题讨论】:

  • 如果你删除了[],useEffect 钩子将在每次更新道具时运行。我认为无限循环是由于您的 setTimeout 方法造成的?

标签: javascript reactjs axios react-hooks


【解决方案1】:

使用像useInterval这样的自定义钩子

function useInterval(callback, delay) {
  const savedCallback = useRef();

  useEffect(() => {
    savedCallback.current = callback;
  });

  useEffect(() => {
    function tick() {
      savedCallback.current();
    }

    let id = setInterval(tick, delay);
    return () => clearInterval(id);
  }, [delay]);
}

然后在你的组件中

 useInterval(() => {
    setCount(count + 1);
  }, delay);

Dan Abramov 对此有一篇很棒的博文

https://overreacted.io/making-setinterval-declarative-with-react-hooks/

【讨论】:

    【解决方案2】:

    你可以使用这样的东西。只需将 console.log 替换为您的 API 请求即可。

      useEffect(() => {
        const interval = setInterval(() => {
          console.log("Making request");
        }, 3000);
        return () => clearInterval(interval);
      }, []);
    

    或者,替换 foouseEffect 并添加 requestId

     const [requestId, setRequestId] = useState(0);
    
     const foo = async () => {
        getScreen(match.params.id);
        setTimeout(setRequestId(requestId+1), 3000);
      };
    
      useEffect(() => {
        foo();
        setNodeupdated(screen.data)
      }, [requestId]);
    

    【讨论】:

    • console.log(screen) 仍处于初始状态
    • 类似于之前的钩子代码,你可以在getScreen之后调用setNodeupdated(screen.data)对吗?
    • 您也可以尝试使用 [screen] 的第二个参数吗?
    • 3 秒后它只是错误 - 无法读取未定义的属性...
    • 哦,我明白了。 @Daniel,您可以尝试我刚刚更新答案的替代方法吗?
    猜你喜欢
    • 2019-09-23
    • 2021-02-14
    • 2019-12-27
    • 2021-01-29
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 2020-08-03
    • 2021-02-11
    相关资源
    最近更新 更多