ReactJS 组件间传递数据时props的value参数为空问题咨询
React组件传值及路由属性丢失问题解决方案
问题根因
- 路由属性丢失:直接在Layout中渲染
<Profile value={user}/>,没有将Profile组件通过React Router的Route组件渲染,也没有使用withRouter高阶组件/路由Hook注入路由属性,因此Profile只能拿到手动传递的value和全局传递的AuthStore属性,默认不会继承路由相关的history、match、location属性 - value初始为空:Layout组件中
user的初始值是空对象{},/api/authenticate请求是异步执行的,首次渲染Profile时请求还未返回结果,因此拿到的value是空对象,请求完成setUser触发重渲染后才会拿到实际的user值 - Hook使用违规:将
useEffect放在了if(props.location.key)的条件判断内,违反了React Hook不能在条件/循环/嵌套函数内调用的规则,会导致Hook调用顺序紊乱,触发运行时报错 - useEffect依赖缺失:Profile内的useEffect用到了
params.username、props.AuthStore等变量,没有加入依赖数组,会导致请求参数不会跟随变量更新,拿到过期数据
修复方案
1. 路由属性获取修复
推荐直接使用React Router提供的原生Hook获取路由属性,无需依赖props传递,兼容性更强:
// Profile组件顶部引入路由Hook import { useParams, useLocation, useHistory } from 'react-router-dom'
如果仍需要从props获取路由属性,可给Profile组件包裹withRouter高阶组件:
import { withRouter } from 'react-router-dom' // 组件导出时包裹 export default withRouter(Profile)
2. 完整修复后代码
front.layout.js
import Profile from '../../Views/profile' const Layout = (props) => { const [user, setUser] = useState({}); const [isLoggedIn, setIsLoggedIn] = useState(false); const [loading, setLoading] = useState(true); props.AuthStore.getToken(); const history = useHistory(); useEffect(() => { const token = props.AuthStore.appState != null ? props.AuthStore.appState.user.access_token : null; axios .post( "/api/authenticate", {}, { headers: { Authorization: "Bearer " + token, }, } ) .then((res) => { if (!res.data.isLoggedIn) { history.push("/login"); return } setUser(res.data.user); setIsLoggedIn(res.data.isLoggedIn); }) .catch((error) => { history.push("/login"); }) .finally(() => { setLoading(false) }) }, [history, props.AuthStore]); if(loading) return <div>加载中...</div> return ( <> <Profile value={user} /> </> )
index.js
import { useParams, useLocation, useHistory } from 'react-router-dom' const Profile = (props) => { console.log(props); const params = useParams(); const location = useLocation(); const [data, setData] = useState({}); const history = useHistory(); useEffect(() => { if(!location?.key || !props.AuthStore?.appState?.user?.access_token) return axios .get( `/api/${params.username}`, { headers: { Authorization: "Bearer " + props.AuthStore.appState.user.access_token, }, } ) .then((res) => { if (res.data.username) { setData(res.data); } }) .catch((error) => { console.log(error); }); }, [location?.key, params.username, props.AuthStore]); }
内容的提问来源于stack exchange,提问作者322quick1
相关产品推荐
相关产品推荐

