reactjs - React router-dom 将状态从父组件传递到子路由器组件,在子组件中显示未定义
问题描述
父组件App.js的内容,我将用户状态传递给子组件 Book :-
import React, { useEffect, useState } from "react";
import NavBar from "./components/NavBar";
import Signup from "./pages/Signup";
import Home from "./pages/Home";
import Book from "./pages/Book";
function App() {
const [user, setUser] = useState();
useEffect(() => {
const token = "Bearer " + sessionStorage.getItem("token");
if (token) {
axios
.get(process.env.REACT_APP_API_URL + "user/self", {
headers: {
Authorization: token,
"Content-Type": "application/json",
},
})
.then((res) => setUser(res.data));
}
}, []);
console.log("user state in App component", user);
return (
<div className="container-fluid">
<NavBar user={user} />
<Route exact path="/" component={Home} />
<Route path="/signup" component={Signup} />
<Route exact path="/book/:id" render={(routeProps) => <Book user={user} {...routeProps} />} />
</div>
);
}
export default App;
以及子组件Book.js的内容:-
import React, { useState, useEffect } from "react";
import axios from "axios";
const Book = (props) => {
const [user,setUser] = useState();
useEffect(() => {
axios
.get(`${process.env.REACT_APP_API_URL}book/${props.match.params.id}`)
.then((res) => {
//Check if user Auth
console.log("user props.user in Book component", props.user);
const isAuth = props.user ? props.user.id === res.user_id : false;
}).catch((error) => {
console.log(error);
});
});
}
在上面的代码没有任何问题之前,我突然注意到 props.user 在子组件中未定义。
这是控制台日志中显示的结果:-
解决方案
答案在你的console.log
. 您的 Book 组件在用户 fetch 完成其调用之前呈现。这是 javascript 的异步特性的结果,也是大多数人在使用 React Hook 的useEffect
. 该解决方案很简单,并且是您应该在所有功能组件中使用的模式。
- 承诺您的请求(在需要时)。在这种情况下,您的子组件依赖于您的 axios 请求的结果来正确呈现。现在您尝试通过在
useEffect
. 但是,useEffect
按照设计,在回调中不期望/返回承诺,因为这种模式鼓励竞争条件。所以这是一个可靠的解决方法,使用async/await
. 您可以将以下内容应用于您的应用程序组件并替换useEffect
那里。
useEffect(() => {
const init = async () => {
const token = "Bearer " + sessionStorage.getItem("token");
if (token) {
const { data } = await axios.get(
process.env.REACT_APP_API_URL + "user/self", {
headers: {
Authorization: token,
"Content-Type": "application/json",
},
})
setUser(data)
}
}
init();
}, []);
- 保护您的子组件免受丢失数据的影响。这里有几个选项通常与加载指示器结合使用,以确保组件始终加载。这一切都取决于预期的用户体验。
您可以阻止整个路由加载,直到获取完成。
function App() {
const [user, setUser] = useState();
const [loading, setLoading] = useState(false);
...
// apply setLoading in useEffect
return (
...
<Route exact path="/book/:id" render={(routeProps) => loading ? <h1>LOADING</h1> : <Book user={user} {...routeProps} />} />
)
}
您可以阻止整个子组件呈现,直到 fetch 完成。
const Book = (props) => {
const [user, setUser] = useState();
const [loading, setLoading] = useState(false);
useEffect(() => {
const init = async () => {
setLoading(true);
try {
const {user_id} = await axios.get(`${process.env.REACT_APP_API_URL}book/${props.match.params.id}`)
//Check if user Auth
console.log("user props.user in Book component", props.user);
const isAuth = props.user ? props.user.id === user_id : false;
setLoading(false);
}
catch (err) {
console.error(err);
}
}
init();
});
}
推荐阅读
- javascript - 使用 Firebase 实现对单个功能的多个帐户访问
- python - 为主题创建多个客户端
- c# - SQL查询中的计数行
- javascript - JavaScript 异步函数 Google Sheet API,由于是公式检索,数据可用性延迟?如何克服?
- mongodb - 猫鼬,在深层种群中使用上模型场进行匹配
- ios - 远程音频流未路由到蓝牙耳机
- javascript - 在 python3 中解码 application/x-www-form-urlencoded 类型请求
- python - DRF request.data 没有属性 _mutable
- arrays - 在 Julia 中,如何计算两个 DateTime 数组之间的平均值(平均值)?
- sql - 计算 URL bigquery sql 中的特定模式