You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:25:49