React中componentDidMount内Fetch请求无法获取用户数据问题
React JWT认证中componentDidMount无法正确获取用户数据的问题
问题描述
我正在开发一个基于JWT认证的React应用,需要从本地存储的token中提取user._id,再通过Fetch请求从后端MongoDB获取完整用户对象并存入状态。遇到以下问题:
- 在App.jsx的
componentDidMount中实现逻辑时,后端控制器打印req.params.id为null,无法从数据库获取用户对象,返回null到前端。 payload.user._id的控制台打印结果正确,但componentDidMount无法将用户存入状态;- 而Discover.jsx组件中的
useEffect钩子通过几乎相同的逻辑却能成功设置用户状态。
相关代码
App.jsx
export default class App extends Component { state = { user: false, } setUserInState = (incomingUserData) => { this.setState({user: incomingUserData}) } async componentDidMount() { let token = localStorage.getItem('token') if (token) { const payload = JSON.parse(atob(token.split('.')[1])) if (payload.exp < Date.now() / 1000) { localStorage.removeItem('token') token = null } else { try { console.log('payload.user: ' + JSON.stringify(payload.user)) let userId = payload.user._id await fetch(`/api/users/getProfile/${userId}`) .then(res => res.json()) .then(data => console.log('DATA: ' + JSON.stringify(data))) .then(data => this.setState({user: data})) } catch (error) { console.log(error) } } } } render() { return ( <div className="App"> <Navbar user={this.state.user} setUserInState={this.setUserInState}/> <Routes> <Route path='/ideas/create' element={<NewIdea user={this.state.user} setUserInState={this.setUserInState}/>}/> <Route path='/users/getProfile/:userId' element={<UserProfile user={this.state.user} setUserInState={this.setUserInState}/>}/> <Route path='/users/editProfile' element={<EditProfile user={this.state.user} setUserInState={this.setUserInState}/>}/> <Route path='/publishers/becomePublisher' element={<BecomePublisher user={this.state.user} setUserInState={this.setUserInState}/>} /> <Route path='/users/addSubscription'/> <Route path='/users/removeSubscription'/> <Route path='/publishers/show/:id' element={<PubProfile user={this.state.user}/>}/> <Route path='/ideas/show/:id' element={<PubIdeas user={this.state.user}/>}/> <Route path='/ideas/ideasFeed/:userId' element={<IdeasFeed user={this.state.user}/>}/> <Route path='/discover/:id' element={<Discover user={this.state.user} setUserInState={this.setUserInState}/>}/> <Route path='*' element={<Navigate to='/discover/:id' replace />}/> </Routes> </div> ) } }
Discover.jsx(省略导入/返回语句)
export default function Discover (props) { const [isActive, setActive] = useState({}) const [publishers, setPublishers] = useState([]) let handleSeeMore = (id) => { let temp = {...isActive} temp[id] = !temp[id] setActive(temp) } let getPublishers = async () => { let token = localStorage.getItem('token') // 如果存在token/用户已登录,则同时获取用户对象和发布者对象 if (token) { let payload = JSON.parse(atob(token.split('.')[1])) let userId = payload.user._id let response = await fetch(`/api/publishers/discover/${userId}`) let data = await response.json() props.setUserInState(data.user) setPublishers(data.publishers) // 否则只获取发布者对象 } else { let userId = 'false' await fetch(`/api/publishers/discover/${userId}`) .then(res => res.json()) .then(data => setPublishers(data)) } } useEffect(() => { (async() => { await getPublishers() })() },[])
问题分析与解决
1. componentDidMount中fetch的链式调用错误
你在App.jsx的componentDidMount里混合使用了await和.then(),并且第三个.then()接收的data是undefined——因为前一个.then()只执行了console.log,没有返回任何值。这直接导致this.setState({user: data})无法正确设置用户状态。
修复方案(二选一)
方案一:统一使用await语法(更清晰)
async componentDidMount() { let token = localStorage.getItem('token') if (token) { const payload = JSON.parse(atob(token.split('.')[1])) if (payload.exp < Date.now() / 1000) { localStorage.removeItem('token') token = null } else { try { console.log('payload.user: ' + JSON.stringify(payload.user)) let userId = payload.user._id const res = await fetch(`/api/users/getProfile/${userId}`) const data = await res.json() console.log('DATA: ' + JSON.stringify(data)) this.setState({user: data}) } catch (error) { console.log(error) } } } }
方案二:保持链式调用,确保每个.then()返回数据
async componentDidMount() { let token = localStorage.getItem('token') if (token) { const payload = JSON.parse(atob(token.split('.')[1])) if (payload.exp < Date.now() / 1000) { localStorage.removeItem('token') token = null } else { try { console.log('payload.user: ' + JSON.stringify(payload.user)) let userId = payload.user._id await fetch(`/api/users/getProfile/${userId}`) .then(res => res.json()) .then(data => { console.log('DATA: ' + JSON.stringify(data)) return data // 关键:将data返回给下一个then }) .then(data => this.setState({user: data})) } catch (error) { console.log(error) } } } }
2. 后端req.params.id为null的排查方向
- 检查后端路由参数名:如果后端路由定义的是
/api/users/getProfile/:userId,那后端应该取req.params.userId而不是req.params.id,或者前端调整请求路径的参数名。 - 验证请求URL:在
fetch前打印完整URL,确认userId是否正确拼接到路径中,比如console.log(/api/users/getProfile/${userId})。
3. 修复默认路由的动态参数错误
App.jsx中默认路由跳转到/discover/:id是错误的,:id是动态参数占位符,不能直接作为跳转路径。建议根据用户状态跳转:
<Route path='*' element={ this.state.user ? <Navigate to={`/discover/${this.state.user._id}`} replace /> : <Navigate to='/discover/false' replace /> }/>
内容的提问来源于stack exchange,提问作者curtis
相关产品推荐
相关产品推荐

