提取api时未调用useEffect且未更新状态

时间:2019-07-30 02:22:45

标签: reactjs react-hooks use-effect

我正在使用useEffect挂钩从天气api中获取数据,并正确声明依赖项。我的状态仍然没有更新,因此我的渲染函数出现错误。我已经做了很多尝试,从摆脱依赖项数组到在依赖项数组中声明倍数。我不知道我的功能出了什么问题。 API的JSON响应采用以下格式:

this.editForm = this.formBuilder.group({
   RequestNo : [data.Request_x0020_Number],
   RequestId : [data.Request_x0020_ID]
})

这就是我的代码:

{
 location: {
 name: "Paris",
 region: "Ile-de-France",
 },
 current: {
  last_updated_epoch: 1564279222,
  last_updated: "2019-07-28 04:00",
  temp_c: 16,
  temp_f: 60.8,
  is_day: 0,
  condition: {
    text: "Clear",
    icon: "//cdn.apixu.com/weather/64x64/night/113.png",
    code: 1000
  },
  wind_mph: 6.9,
  wind_kph: 11.2
 }
}

我希望能够显示该图标的图像,但是我在渲染函数中收到此错误消息:

const Weather = ({ capital }) => {
  const [weather, setWeather] = useState(null);

  useEffect(() => {
    console.log("useEffect called");
    const getWeather = async () => {
      try {
        const res = await axios.get(
          `http://api.apixu.com/v1/current.json?key=53d601eb03d1412c9c004840192807&q=${capital}`
        );
        setWeather(res.data);
      } catch (e) {
        console.log(e);
      }
    };
    getWeather();
  }, [capital]);
  console.log(weather);

  return (
    <Card style={{ width: "18rem", marginTop: "25px" }}>
      <Card.Img variant="top" src={weather.current.condition.icon} />

      <Card.Header style={{ textAlign: "center", fontSize: "25px" }}>
        Weather in {capital}
      </Card.Header>
    </Card>
  )
}

并且我的TypeError: Cannot read property 'current' of null Weather src/components/Weather.js:26 23 | 24 | return ( 25 | <Card style={{ width: "18rem", marginTop: "25px" }}> 26 | <Card.Img variant="top" src={weather.current.condition.icon} /> | ^ 27 | 28 | <Card.Header style={{ textAlign: "center", fontSize: "25px" }}> 29 | Weather in {capital} 返回null,即使在useEffect()和console.log(weather)之后调用它的原始状态也没有记录,这意味着没有调用useEffect。

3 个答案:

答案 0 :(得分:2)

请确保当weather.currentweather时不要尝试读null

使用src={weather && weather.current && weather.current.condition.icon}

const Weather = ({capital}) => {
  const [weather, setWeather] = useState(null);

  useEffect(() => {
    console.log("useEffect called");
    const getWeather = async () => {
      try {
        const res = await axios.get(
          `http://api.apixu.com/v1/current.json?key=53d601eb03d1412c9c004840192807&q=${capital}`,
        );
        setWeather(res.data);
      } catch (e) {
        console.log(e);
      }
    };
    getWeather();
  }, [capital]);
  console.log(weather);

  return (
    <Card style={{width: "18rem", marginTop: "25px"}}>
      <Card.Img variant="top" src={weather && weather.current && weather.current.condition.icon} />

      <Card.Header style={{textAlign: "center", fontSize: "25px"}}>
        Weather in {capital}
      </Card.Header>
    </Card>
  );
};

答案 1 :(得分:0)

因此,我遇到了类似的问题,似乎useEffect钩子根本没有被调用。相关代码段如下:

在我的功能组件中,这是代码出现的顺序:

  • 变量const facetFields = [];声明,该声明应该由useEffect挂钩内的AJAX调用设置

  • useEffect挂钩,使用AJAX在其中设置了以上变量。

     useEffect( ()=>{
          console.log('FacetTreeView: useEffect entered');
          facetFields = getFacetFieldNames(props.tabIndex);   
       }, []);
    
  • 使用该变量的JSX代码。

    return( {facetFields.map((facetLabel,index)=> { populateFacetInstances(facetLabel)})} )

使用此代码,挂钩中的console语句根本无法打印。另外,在map处理facetFields的过程中,我始终收到未定义的错误。因此,事实证明,在呈现组件之后将调用useHook。因此,在渲染过程中,变量facetFieldsundefined。因此,我通过将以下行添加到我的JSX渲染代码部分中来解决了此问题:

facetFields && facetFields.map(.....

一旦进行了上述更改,控件便开始进入钩子。因此,总而言之,如果JSX中有任何useEffect钩子中设置的代码,则最好推迟执行直到挂钩执行完成为止。尽管这不是强制性的,但是它将使JSX代码更易于阅读。这可以通过使用布尔状态标志以简单的方式实现。

  1. 定义状态:

const [readyForRender,setReadyForRender] = React.useState(false); 2.设置状态为钩子。

useEffect( ()=>{
            console.log('FacetTreeView: useEffect entered');
            facetFields = getFacetFieldNames(props.tabIndex);
            setReadyForRender(true); }, []);
  1. 有条件地渲染JSX。

if(readyForRender){ return({facetFields.map((facetLabel,index)=> {populateFacetInstances(facetLabel)})}); }其他{ 返回null; }

答案 2 :(得分:0)

我曾经遇到过同样令人费解的问题

在父代码中创建组件时可以尝试在组件上添加一个key prop

<yourcomponent key="some_unique_value" />

这是因为在大多数情况下,当您的组件被重用时,根据它的创建方式,它通常可能会通过一些更改重新渲染它,而不是在您重用它时再次创建它,因此 {{1} } 不会被调用。例如在 SwitchRoute、循环、条件...

所以添加一个密钥可以防止这种情况发生。如果是在循环中,则需要确保每个元素都是唯一的,如果找不到更好的唯一键,可以在键中包含索引 useEffect