React - useEffect axios请求中设置的状态为空
Posted
技术标签:
【中文标题】React - useEffect axios请求中设置的状态为空【英文标题】:React - State set inside useEffect axios request is empty 【发布时间】:2021-09-26 12:41:41 【问题描述】:嘿,
我有一个 PortfolioPage 组件(下面的代码)通过组件 useEffect 内的 axios 库向我的 api 调用 GET 请求。
请求之后 它使用 setPortfolio 挂钩设置投资组合属性。
然后,我将投资组合传递给 HoldingsChart 组件(添加的组件的代码)。 当我尝试使用在 HoldingsChart 组件中传递的投资组合道具时,它显示投资组合是一个空对象。
我相信这与 setState 的异步方式有关 但是另一个组件(AssetChart)确实得到了正确渲染,所以我找不到问题。 真的很想得到一些帮助。
PortfolioPage 组件代码:
const PortfolioPage = (match) =>
const user = useContext(UserContext)
const [portfolio, setPortfolio] = useState()
const portfolioId = match.params.portfolioId
useEffect(() =>
// getPortfolio(user.token, portfolioId, setPortfolio)
const getPortfolio = async () =>
const domain = "http://127.0.0.1:8000/api"
await axios.get(domain + `/portfolios/$portfolioId`,
headers:
'Authorization': `Token $user.token`
)
.then((res) =>
setPortfolio(res.data)
)
getPortfolio()
,[])
return (
<React.Fragment>
<AssetChart records=portfolio.records />
<HoldingsChart portfolio=portfolio/>
</React.Fragment>
)
HoldingsChart 组件代码:
const HoldingChart = (portfolio) =>
const holdings = portfolio.holdings
const totalValue = portfolio.total_value
const [data, setData] = useState([])
useEffect(() =>
const holdingsPercentages = []
holdings.forEach(holding => holdingsPercentages.push(value: holding.total_value / totalValue))
setData(holdingsPercentages)
,[])
const renderCustomizedLabel = (
cx, cy, midAngle, innerRadius, outerRadius, percent, index,
) =>
const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
const x = cx + radius * Math.cos(-midAngle * RADIAN);
const y = cy + radius * Math.sin(-midAngle * RADIAN);
return (
<text x=x y=y fill="black" fontSize="10" textAnchor=x > cx ? 'start' : 'end' dominantBaseline="central">
`$data[index].asset $(percent * 100).toFixed(0)%`
</text>
);
;
return (
<PieChart width=350 height=350>
<Pie
data=data
cx=175
cy=100
labelLine=false
label=renderCustomizedLabel
innerRadius=40
outerRadius=80
fill="#8884d8"
dataKey="value"
>
data.map((entry, index) => <Cell key=`cell-$index` fill=COLORS[index % COLORS.length] />)
<Tooltip/>
</Pie>
</PieChart>
);
错误:
TypeError: Cannot read property 'forEach' of undefined
(anonymous function)
C:/Users/David/Desktop/Long-Term/longterm/src/components/assets-comps/HoldingsChart.js:15
12 | const [data, setData] = useState([])
13 | useEffect(() =>
14 | const holdingsPercentages = []
> 15 | holdings.forEach(holding => holdingsPercentages.push(value: holding.total_value / totalValue))
| ^ 16 | setData(holdingsPercentages)
17 | ,[])
18 |
谢谢
【问题讨论】:
如果你写console.log(portfolio)
Insider HoldingChart
组件你看到了什么?
@monesulhaque 它打印一个空对象
如果你这样做,你会看到什么? .then((res) => console.log(res); setPortfolio(res.data) )
@monesulhaque 它打印从 api 返回的对象,它还使用投资组合对象渲染 AssetChart。
如果您成功接收数据,那么可能存在一个问题,您的HoldingChart组件在您进行API调用之前呈现。所以请在holdings.forEach(holding => holdingsPercentages.push(value: holding.total_value / totalValue))
之前检查一下是否为空。
【参考方案1】:
在循环holdings
之前添加一个空检查
if(holdings && holdings.length)
holdings.forEach
或
holdings && holdings.length && holdings.forEach
或
holdings?.forEach
原因:
您的持有图表组件甚至在收到 api 响应之前就已呈现。 (收到api响应时会重新渲染,所以添加null检查即可解决问题。
更简单更好的解决方案
添加一个变量 isResponseLoading 以在 api 调用正在进行时显示加载器并呈现您的 HoldingsChart 组件,仅当 api 响应可用时。
isResponseLoading && <Spinner />
!isResponseLoading && portfolio?.length && <HoldingsChart portfolio=portfolio/>
【讨论】:
以上是关于React - useEffect axios请求中设置的状态为空的主要内容,如果未能解决你的问题,请参考以下文章
在 React Hooks useEffect cleanup 中取消 Axios REST 调用失败
Axios 没有使用 useEffect() (React Js) [重复]
为啥我的 axios 使用 React.useEffect 一遍又一遍地从 Rails 后端获取调用?