我使用useEffect钩子从天气API获取数据,并正确声明依赖项。我的状态仍然没有更新,因此我在渲染函数中出错。我几乎尝试了从摆脱依赖数组到在依赖数组中声明倍数的所有方法。我不知道我的函数有什么问题。API的JSON响应格式如下:
{
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}
我的console.log(weather)
返回null,即原始状态,即使它在useEffect()之后被调用,并且console.log(useEffect called)
根本不记录,这意味着useEffect没有被调用。
4条答案
按热度按时间w8ntj3qf1#
错误消息泄露了它,
Cannot read property 'current' of null
,current
被调用的唯一地方是在Card.Img
的src
中的weather.current
中,因此我们推断在渲染期间weather
是null
。发生这种情况的原因是因为API调用是异步的,它不会立即填充状态,所以渲染首先发生,并尝试从初始天气状态
null
读取.current
。解决方案:在
render
方法中,确保在weather
是null
时不读取weather.current
。例如,您可以使用
{weather && <Card>...</Card}
隐藏整个卡,直到加载数据并显示加载指示符,或者您可以使用src={weather && weather.current.condition.icon}
作为快速解决方案。h9a6wy2h2#
我有一次也遇到过同样的难题
您可以尝试在父代码中创建组件时在组件上添加键 prop
这是因为在大多数情况下,当你的组件被重用时,基于它的创建方式,它通常会重新渲染它,而不是在重用它时再次创建它,因此
useEffect
不会被调用。所以添加一个键可以防止这种情况发生。如果是在循环中,你需要确保每个元素都是唯一的,如果你找不到更好的唯一键,可以在键中包含索引
i
。8hhllhi23#
所以,我也遇到了类似的问题,似乎
useEffect
钩子根本没有被调用。下面给出了相关的代码片段:在我的函数组件中,这是代码的外观序列:
const facetFields = [];
声明,应该由useEffect
钩子中的 AJAX 调用设置useEffect
钩子,上面的变量是用 AJAX 设置的。return( {facetFields.map((面标签,索引)=〉{填充面示例(面标签)})})
使用这段代码,钩子中的控制台语句根本没有打印。此外,我在
map
'ing facetFields时一直得到一个未定义的错误。所以,原来useHook是在组件渲染后调用的。所以,在渲染期间,变量facetFields
是undefined
。所以,我通过将这一行添加到我的JSX渲染代码部分来修复这个问题:一旦,我做了上面的更改,控件开始进入钩子。所以,总而言之,如果JSX中有任何代码是从
useEffect
钩子设置的,那么最好推迟JSX的执行,直到钩子执行完成。虽然,这不是强制性的,但它会使JSX代码更容易阅读。这可以通过使用布尔状态标志以一种简单的方式实现。1.定义状态:
const [readyForRender,setReadyForRender] = React.useState(false);2.在钩子中设置状态。
1.有条件地呈现JSX。
if(readyForRender){ return({facetFields.map((facetLabel,index)=〉{ populateFacetInstances(facetLabel)})});} else{ return null;}
4szc88ey4#
我有类似的问题。它有时工作,大多数时候它不工作。我已经尝试根据上面建议的解决方案更新代码,但没有运气。我在这里尝试将从EDIdata.json接收到的数据传递到子组件。但首先,由于页面加载时没有调用getData(),因此没有从API获取数据。
数据的console.log不记录任何东西。请注意。