获取 api 时未调用 useEffect 且未更新状态
useEffect not being called and not updating state when api is fetched
我正在使用 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)
return 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.current
而 weather
是 null
。
例如,您可以使用 {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>
);
};
所以,我遇到了类似的问题,似乎 useEffect
挂钩根本没有被调用。相关代码片段如下:
在我的功能组件中,这是代码出现的顺序:
一个变量 const facetFields = [];
声明,它应该由 useEffect
钩子
中的 AJAX 调用设置
useEffect
挂钩,上面的变量设置为 AJAX.
useEffect( ()=>{
console.log('FacetTreeView: useEffect entered');
facetFields = getFacetFieldNames(props.tabIndex);
}, []);
使用变量的 JSX 代码。
return (<MyComponent> { facetFields.map((facetLabel, index) => {
populateFacetInstances(facetLabel) }) } </Component>)
使用此代码,挂钩内的控制台语句根本不会打印。此外,我在 map
'ing facetFields 时不断收到未定义的错误。因此,事实证明 useHook 在组件渲染后被调用。因此,在渲染期间,变量 facetFields
是 undefined
。因此,我通过将此行添加到代码的 JSX 渲染部分来修复此问题:
facetFields && facetFields.map(.....
有一次,我进行了上述更改,控件开始转到 hook.So,总而言之,如果 JSX 中有任何代码是从 useEffect
钩子设置的,那么最好推迟 JSX 的执行,直到钩子执行完成。虽然这不是强制性的,但它会使 JSX 代码更易于阅读。这可以通过使用布尔状态标志以简单的方式实现。
- 定义状态:
const [readyForRender, setReadyForRender] = React.useState(false);
2. Set state in hook.
useEffect( ()=>{
console.log('FacetTreeView: useEffect entered');
facetFields = getFacetFieldNames(props.tabIndex);
setReadyForRender(true); }, []);
- 有条件地渲染 JSX。
if(readyForRender){
return ( { facetFields.map((facetLabel, index) => { populateFacetInstances(facetLabel) }) } );
} else{
return null;
}
我遇到过一次同样令人费解的问题
您可以尝试在父代码中创建组件时在组件上添加一个 key prop
<yourcomponent key="some_unique_value" />
这是因为在大多数情况下,当您的组件被重用时,基于它的创建方式,它通常可能会重新渲染它并进行一些更改,而不是在您重用它时再次创建它,因此 useEffect
不会被调用。例如在 SwitchRoute、循环、条件...
因此添加密钥将防止这种情况发生。如果它在一个循环中,您需要确保每个元素都是唯一的,如果找不到更好的唯一键,可以在键中包含索引 i
。
我正在使用 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)
return 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.current
而 weather
是 null
。
例如,您可以使用 {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>
);
};
所以,我遇到了类似的问题,似乎 useEffect
挂钩根本没有被调用。相关代码片段如下:
在我的功能组件中,这是代码出现的顺序:
一个变量
中的 AJAX 调用设置const facetFields = [];
声明,它应该由useEffect
钩子useEffect
挂钩,上面的变量设置为 AJAX.useEffect( ()=>{ console.log('FacetTreeView: useEffect entered'); facetFields = getFacetFieldNames(props.tabIndex); }, []);
使用变量的 JSX 代码。
return (<MyComponent> { facetFields.map((facetLabel, index) => { populateFacetInstances(facetLabel) }) } </Component>)
使用此代码,挂钩内的控制台语句根本不会打印。此外,我在 map
'ing facetFields 时不断收到未定义的错误。因此,事实证明 useHook 在组件渲染后被调用。因此,在渲染期间,变量 facetFields
是 undefined
。因此,我通过将此行添加到代码的 JSX 渲染部分来修复此问题:
facetFields && facetFields.map(.....
有一次,我进行了上述更改,控件开始转到 hook.So,总而言之,如果 JSX 中有任何代码是从 useEffect
钩子设置的,那么最好推迟 JSX 的执行,直到钩子执行完成。虽然这不是强制性的,但它会使 JSX 代码更易于阅读。这可以通过使用布尔状态标志以简单的方式实现。
- 定义状态:
const [readyForRender, setReadyForRender] = React.useState(false); 2. Set state in hook.
useEffect( ()=>{ console.log('FacetTreeView: useEffect entered'); facetFields = getFacetFieldNames(props.tabIndex); setReadyForRender(true); }, []);
- 有条件地渲染 JSX。
if(readyForRender){ return ( { facetFields.map((facetLabel, index) => { populateFacetInstances(facetLabel) }) } ); } else{ return null; }
我遇到过一次同样令人费解的问题
您可以尝试在父代码中创建组件时在组件上添加一个 key prop
<yourcomponent key="some_unique_value" />
这是因为在大多数情况下,当您的组件被重用时,基于它的创建方式,它通常可能会重新渲染它并进行一些更改,而不是在您重用它时再次创建它,因此 useEffect
不会被调用。例如在 SwitchRoute、循环、条件...
因此添加密钥将防止这种情况发生。如果它在一个循环中,您需要确保每个元素都是唯一的,如果找不到更好的唯一键,可以在键中包含索引 i
。