“无法读取 null 的属性(读取‘令牌’)”Reacjs、Redux

问题描述 投票:0回答:1

我正在观看 Brad Traversy MERN 教程。他在其中创建了一个目标设定器应用程序。我几乎已经完成了,但是在 goalSlice 的 Reset() 函数中出现错误。不知道实际的问题是什么。当从 Dashboard.jsx 调度 reset() 时,以及添加目标并在 chrome 中的 redux devtool 中查看它们之后。当我按下注销按钮时,chrome 挂起并且控制台显示此消息无法读取 null 的属性(读取“令牌”)
我相信这是 Dashboard.jsx 中的

console.log(message)
,但我不知道如何解决它。我尝试评论
dispatch(reset())
来消除此错误,但我还必须在用户注销时重置目标。有人对此有任何想法吗??
我也已将代码上传到 github 上,因此如果有人需要有关代码的更多信息,可以访问此链接:https://github.com/anishdalvi/MERN-Goal-Setter-.git
Youtube 链接:https://youtu.be/UXjMo25Nnvc

仪表板.jsx

import { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { useSelector, useDispatch } from 'react-redux'
import GoalForm from '../components/GoalForm'
import Spinner from '../components/Spinner'
import { getGoals, reset } from '../features/goals/goalSlice'

function Dashboard() {  
  const dispatch = useDispatch()
  const navigate = useNavigate()
  const { user } = useSelector((state) => state.auth)
  const { goals, isLoading, isError, message } = useSelector((state) => state.goals)


  useEffect(() => {
    if(isError){
      console.log("iserror  "+ message)
    }

    if(!user){
      navigate('/login')
    }

    dispatch(getGoals())
    
    /* return () => {
      dispatch(reset())
    } */

  } , [user, navigate, isError, message, dispatch] )


  if (isLoading){
    return <Spinner />
  }


  return (
    <>
      <section className="heading">
        <h1>Welcome {user && user.name}</h1>
        <p>Goals Dashboard</p>
      </section>
      <GoalForm />
    </>
  )
}

export default Dashboard

goalService.js

import axios from 'axios'

const API_URL = '/api/goals/'


// create new goal
const createGoal = async (goalData, token) => {
    const config = {
        headers: {
            Authorization: `Bearer ${token}`
        }
    }

    const response = await axios.post(API_URL, goalData, config)

    return response.data
}



// get goals
const getGoals = async (token) => {
    const config = {
        headers: {
            Authorization: `Bearer ${token}`
        }
    }

    const response = await axios.get(API_URL, config)

    return response.data
}


const goalService = {
    createGoal,
    getGoals
}

export default goalService

goalSlice.js

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import goalService from './goalService'


const initialState = {
    goals: [],
    isError: false,
    isSuccess: false,
    isLoading: false,
    message: ""

}


// create new Goal

export const createGoal = createAsyncThunk('goals/create', async (goalData, thunkAPI) => {
    try {
        const token = thunkAPI.getState().auth.user.token
        return await goalService.createGoal(goalData, token)
      } catch (error) {
        const message = (error.response && error.response.data && error.response.data.message) || error.message || error.toString()
        return thunkAPI.rejectWithValue(message)
      }
} )


// get user goals

export const getGoals = createAsyncThunk('goals/getAll', async(_, thunkAPI) => {
    try {
        const token = thunkAPI.getState().auth.user.token
        return await goalService.getGoals(token)
      } catch (error) {
        const message = (error.response && error.response.data && error.response.data.message) || error.message || error.toString()
        return thunkAPI.rejectWithValue(message)
      }
})



export const goalSlice = createSlice({
    name: 'goal',
    initialState,
    reducers: {
        reset: (state) => initialState,
       
    
    },
    extraReducers:(builder) => {
        builder
            .addCase(createGoal.pending, (state) => {
                state.isLoading = true
            })
            .addCase(createGoal.fulfilled, (state, action) => {
                state.isLoading = false
                state.isSuccess = true
                state.goals.push(action.payload)
            })
            .addCase(createGoal.rejected, (state, action) => {
                state.isLoading = false
                state.isError = true
                state.message = action.payload
            })


            .addCase(getGoals.pending, (state) => {
                state.isLoading = true
            })
            .addCase(getGoals.fulfilled, (state, action) => {
                state.isLoading = false
                state.isSuccess = true
                state.goals = action.payload
            })
            .addCase(getGoals.rejected, (state, action) => {
                state.isLoading = false
                state.isError = true
                state.message = action.payload
            })
    }

})


export const { reset } = goalSlice.actions
export default goalSlice.reducer

authService.js

import axios from 'axios'

const API_URL = '/api/users/'


// Register User

const register = async (userData) => {
    const response = await axios.post(API_URL, userData)

    if(response.data){
        localStorage.setItem('user', JSON.stringify(response.data))
    }

    return response.data

}

// login User

const login = async (userData) => {
    const response = await axios.post(API_URL + 'login', userData)

    if(response.data){
        localStorage.setItem('user', JSON.stringify(response.data))
    }

    return response.data

}

// Logout User

const logout = () => {
    localStorage.removeItem('user')
}



const authService = {
    register, logout, login
}

export  default authService

authSlice.js

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import authService from './authService'



// Get user from localStorage

const user = JSON.parse(localStorage.getItem('user'))

const initialState = {
    user: user ? user : null,
    isError: false,
    isSuccess: false,
    isLoading: false,
    message: ""
}


// Register user
export const register = createAsyncThunk('auth/register', async (user, thunkAPI) => {
  try {
    return await authService.register(user)
  } catch (error) {
    const message = (error.response && error.response.data && error.response.data.message) || error.message || error.toString()
    return thunkAPI.rejectWithValue(message)
  }
})

// Login user
export const login = createAsyncThunk('auth/login', async (user, thunkAPI) => {
  try {
    return await authService.login(user)
  } catch (error) {
    const message = (error.response && error.response.data && error.response.data.message) || error.message || error.toString()
    return thunkAPI.rejectWithValue(message)
  }
})

// logout
export const logout = createAsyncThunk('auth/logout' , async () => {
  await authService.logout()
})


export const authSlice = createSlice({
    name: 'auth',
    initialState,
    reducers: {
      reset: (state) => {
        state.isLoading = false
        state.isSuccess = false
        state.isError = false
        state.message = ''
      }
    },
    extraReducers: (builder) => {
      builder
        .addCase(register.pending, (state) => {
          state.isLoading = true
        } )
        .addCase(register.fulfilled, (state, action) => {
          state.isLoading = false
          state.isSuccess = true
          state.user = action.payload
        })
        .addCase(register.rejected, (state, action) =>{
          state.isLoading = false
          state.isError = true
          state.message = action.payload
          state.user = null
        })

        .addCase(login.pending, (state) => {
          state.isLoading = true
        } )
        .addCase(login.fulfilled, (state, action) => {
          state.isLoading = false
          state.isSuccess = true
          state.user = action.payload
        })
        .addCase(login.rejected, (state, action) =>{
          state.isLoading = false
          state.isError = true
          state.message = action.payload
          state.user = null
        })

        .addCase(logout.fulfilled, (state) =>{
          state.user = null
        })
    }
})




export const { reset } = authSlice.actions
export default authSlice.reducer
node.js reactjs redux
1个回答
2
投票

看看这个属性访问:

thunkAPI.getState().auth.user.token

您正在尝试访问身份验证用户的令牌。

但是你的初始状态是这样的:

const initialState = {
    user: user ? user : null,
    isError: false,
    isSuccess: false,
    isLoading: false,
    message: ""
}

在用户不存在的情况下,如何访问他们的令牌?

当您调用

reset()
时,您的用户可能被设置为
null
,因此错误仅在此时出现。

您应该在访问令牌之前检查用户是否不为空,并根据需要处理用户为空的情况。

if (thunkAPI.getState().auth.user) {
  // only in the case the above condition is true,
  // then you can access the token. 
}
© www.soinside.com 2019 - 2024. All rights reserved.