我正在使用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。
错误消息会泄露它,Cannot read property 'current' of null
,唯一调用current
的地方是在Card.Img
src
的weather.current
中,所以我们推断weather
在渲染过程中被null
。
发生这种情况的原因是因为 api 调用是异步的,它不会立即填充状态,因此渲染首先发生并尝试从初始天气状态读取.current
null
。
解决方案:在render
方法中,请确保在weather
null
时不要读取weather.current
。
例如,您可以使用{weather && <Card>...</Card}
隐藏整个卡,直到加载数据并显示加载指示器,也可以使用src={weather && 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.condition.icon} />
<Card.Header style={{textAlign: "center", fontSize: "25px"}}>
Weather in {capital}
</Card.Header>
</Card>
);
};
我有一次遇到了同样令人费解的问题
在父代码中创建组件时,可以尝试在组件上添加键属性
<yourcomponent key="some_unique_value" />
这是因为在大多数情况下,当您的组件被重用时,根据它的创建方式,它通常会通过一些更改重新渲染它,而不是在您重用它时再次创建它,因此不会调用useEffect
。 例如在开关路由中,循环,条件...
因此,添加密钥将防止这种情况发生。如果它在循环中,则需要确保每个元素都是唯一的,如果找不到更好的唯一键,则可以在键中包含索引i
。
所以,我面临着类似的问题,似乎useEffect
钩子根本没有被调用。下面给出了相关的代码片段:
在我的功能组件中,这是代码出现的顺序:
-
一个变量
const facetFields = [];
声明,应该由钩子中的 AJAX 调用设置useEffect
使用 AJAX 设置了上述变量。
useEffect( ()=>{ console.log('FacetTreeView: useEffect entered'); facetFields = getFacetFieldNames(props.tabIndex); }, []);
使用该变量的 JSX 代码。
return (
{ facetFields.map((facetLabel, index) => { populateFacetInstances(facetLabel) }) } )
useEffect
钩子,其中使用此代码,钩子内的控制台语句根本没有打印。此外,我在map
FacetFields 时不断收到一个未定义的错误。因此,事实证明,useHook 是在组件渲染后调用的。因此,在渲染过程中,变量facetFields
undefined
。因此,我通过将这一行添加到我的 JSX 渲染部分代码来解决此问题:
facetFields && facetFields.map(.....
有一次,我做了上述更改,控件开始进入钩子。因此,总而言之,如果 JSX 中有任何代码是从useEffect
钩子设置的,那么最好推迟 JSX 的执行,直到钩子执行完成。虽然这不是强制性的,但它会使 JSX 代码更易于阅读。这可以通过使用布尔状态标志以简单的方式实现。
- 定义状态:
const [readyForRender, setReadyForRender] = React.useState(false); 2. 在钩子中设置状态。
useEffect( ()=>{ console.log('FacetTreeView: useEffect entered'); facetFields = getFacetFieldNames(props.tabIndex); setReadyForRender(true); }, []);
- 有条件地渲染 JSX。
if(readyForRender){ return ( { facetFields.map((facetLabel, index) => { populateFacetInstances(facetLabel) }) } ); } else{ 返回空值; }
我遇到了类似的问题。它有时有效,大多数时候不起作用。我尝试根据上面建议的解决方案更新代码,但没有运气。 我在这里尝试将从EDIdata.json接收的数据传递给子组件。但首先,数据不是从 API 获取的,因为 getData() 不会在页面加载时调用。
import { React, useEffect, useState } from 'react';
import MilestoneSummary from './MilestoneSummary';
import { Grid, Column } from '@carbon/react';
const OrderSummary = () => {
const [data, setData] = useState({ data: {} });
useEffect(() => {
getData()
})
const getData = () => {
fetch('EDIData.json'
, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}
)
.then(function (response) {
console.log("JSON response" + response)
return response.json();
})
.then(function (myJson) {
setData(myJson)
})
.catch(err => { console.log(err) })
}
console.log(data);
return (
<>
<Grid>
<Column md={4} lg={4} sm={4}>
<h3 className="landing-page__label">Order milestone summary</h3>
<MilestoneSummary summaryItems={data.OrderMilestoneSummary} />
</Column>
</Grid>
</>
)
};
export default OrderSummary;
控制台.log数据只是不记录任何内容。恳请指教。
由于 UseEffect 运行异步提取并在幕后进行渲染,因此 React 尝试渲染 HTML,但尚未获取数据。所以,天气null
.在 JSX 中放置一个条件,如果要显示,请确保天气不为空
weather.current.condition.icon
我在这里发表评论,因为我无法在任何地方找到它。 我遇到了同样的问题(useEffect根本没有执行),结果发现这是因为我的功能组件被错误地定义为异步(可能更漂亮或其他什么)。
从组件定义中删除异步修复了它。
以前:
const SomeComponent = async () => { //<--- this is the issue
useEffect(() => {console.log("TEST")},[]); // This will never fire
return <></>
}
后:
const SomeComponent = () => { // Removed async from definition
useEffect(() => {console.log("TEST")},[]); // Working normally.
return <></>
}
希望它有用。