从useEffect挂钩中的axios调用更新状态

时间:2020-02-07 16:22:01

标签: javascript reactjs axios react-hooks

我是新来的反应者,我才刚刚开始学习钩子和上下文。

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

const getScreen = async uuid => {

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

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

继续使用减速器。

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);
  }

2 个答案:

答案 0 :(得分:0)

使用自定义钩子,例如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/

答案 1 :(得分:0)

您可以使用类似这样的东西。只需用您的API请求替换console.log。

  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]);