【问题标题】:React: Access Data from Redux in componentReact:从组件中的 Redux 访问数据
【发布时间】:2020-10-23 20:14:52
【问题描述】:

我已经创建了一个身份验证系统来与 redux 和 axios 做出反应,但我不知道如何在我的组件中呈现数据。
这是我的操作/auth.js:

import axios from 'axios';
import {
    SIGNUP_SUCCESS,
    SIGNUP_FAIL,
    LOGIN_SUCCESS,
    LOGIN_FAIL,
    ACTIVATION_SUCCESS,
    ACTIVATION_FAIL,
    RESET_PASSWORD_SUCCESS,
    RESET_PASSWORD_FAIL,
    RESET_PASSWORD_CONFIRM_SUCCESS,
    RESET_PASSWORD_CONFIRM_FAIL,
    LOGOUT,
    USER_LOADED_SUCCESS,
    USER_LOADED_FAIL,
    AUTHENTICATED_FAIL,
    AUTHENTICATED_SUCCESS
} from './types';

export const checkAuthenticated = () => async dispatch => {
    if (typeof window == 'undefined') {
        dispatch({
            type: AUTHENTICATED_FAIL
        });
    }
    if (localStorage.getItem('access')) {
        const config = {
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            }
        };
    
        const body = JSON.stringify({ token: localStorage.getItem('access') });
    
        try {
            const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/jwt/verify/`, body, config);
    
            if (res.data.code !== 'token_not_valid') {
                dispatch({
                    type: AUTHENTICATED_SUCCESS
                });
            } else {
                dispatch({
                    type: AUTHENTICATED_FAIL
                });
            }
        } catch (err) {
            dispatch({
                type: AUTHENTICATED_FAIL
            });
        }
    } else {
        dispatch({
            type: AUTHENTICATED_FAIL
        });
    }
};

export const load_user = () => async dispatch => {
    if (localStorage.getItem('access')) {
        const config = {
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `JWT ${localStorage.getItem('access')}`,
                'Accept': 'application/json'
            }
        };

        try {
            const res = await axios.get(`${process.env.REACT_APP_API_URL}/auth/users/me/`, config);

            dispatch({
                type: USER_LOADED_SUCCESS,
                payload: res.data
            });
        } catch (err) {
            dispatch({
                type: USER_LOADED_FAIL
            });
        }
    } else {
        dispatch({
            type: USER_LOADED_FAIL
        });
    }
};

export const login = (email, password) => async dispatch => {
    const config = {
        headers: {
            'Content-Type': 'application/json'
        }
    };

    const body = JSON.stringify({ email, password });

    try {
        const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/jwt/create/`, body, config);

        dispatch({
            type: LOGIN_SUCCESS,
            payload: res.data
        });

        dispatch(load_user());
    } catch (err) {
        dispatch({
            type: LOGIN_FAIL
        });
    }
};

export const logout = () => dispatch => {
    dispatch({ type: LOGOUT });
};

这是我的 reducers/auth.js:

import {
    SIGNUP_SUCCESS,
    SIGNUP_FAIL,
    LOGIN_SUCCESS,
    LOGIN_FAIL,
    LOGOUT,
    AUTHENTICATED_FAIL,
    AUTHENTICATED_SUCCESS,
    USER_LOADED_SUCCESS,
    USER_LOADED_FAIL
} from '../actions/types';

const initialState = {
    access: localStorage.getItem('access'),
    refresh: localStorage.getItem('refresh'),
    isAuthenticated: null,
    user: null
};

export default function(state = initialState, action) {
    const { type, payload } = action;

    switch(type) {
        case AUTHENTICATED_SUCCESS:
            return {
                ...state,
                isAuthenticated: true
            }
        case LOGIN_SUCCESS:
            localStorage.setItem('access', payload.access);
            return {
                ...state,
                isAuthenticated: true,
                access: payload.access,
                refresh: payload.refresh
            }
        case USER_LOADED_SUCCESS:
            return {
                ...state,
                user: payload
            }
        case AUTHENTICATED_FAIL:
            return {
                ...state,
                isAuthenticated: false
            }
        case USER_LOADED_FAIL:
            return {
                ...state,
                user: null
            }
        case LOGIN_FAIL:
        case LOGOUT:
            localStorage.removeItem('access');
            localStorage.removeItem('refresh');
            return{
                ...state,
                access: null,
                refresh: null,
                isAuthenticated: false,
                user: null
            }
        default:
            return state
    }
}

如果我登录并使用 redux Devtool 我可以看到这个状态:

{
  auth: {
    access: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjAzNDgzODY1LCJqdGkiOiJhYTAzYzIzNTUwN2M0YTkxYjA2NjNmNDc0ZTU2MjIxMSIsInVzZXJfaWQiOjF9.Jyld4U7i6EqmsNoi0_qT9O9Kcu1TiEuyLLYCWWaoBrU',
    refresh: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYwMzU2OTk2NSwianRpIjoiOWIzMWIyN2M1ODkyNDRiZDk3Y2EwMDI1NTY2Mzk3ZWMiLCJ1c2VyX2lkIjoxfQ.UgH_753OoWD3NXiwPwa1645_vIHUl-FwyvQMJWMgHtk',
    isAuthenticated: true,
    user: {
      name: 'Jonas Levin',
      id: 1,
      email: 'jonaslevin1903@gmail.com'
    }
  }
}

但我不知道如何显示数据,例如 user.name。
我已经尝试在我的一个组件中使用 mapStateToProps,但出现错误:“TypeError: Cannot read property 'name' of undefined”

const mapStateToProps = state => ({
    userName: state.user.name,
    userEmail: state.user.email
});

编辑
这是我得到的响应数据。但是正如您所看到的,还有另一个 API 调用仍然来自我在重定向到“/”之前所在的登录页面,并且该浅红色 /me 调用中有一条错误消息,因为当您在登录页面上时,您没有访问令牌。 如何在我的组件中访问此响应数据以呈现名称?

Store.js:

import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const initialState = {};

const middleware = [thunk];

const store = createStore(
    rootReducer,
    initialState,
    composeWithDevTools(applyMiddleware(...middleware))
);

export default store;

【问题讨论】:

  • 我假设你的组件已经连接(连接)到redux,对吧?
  • 是的,我正在使用的一个组件是这样连接的:export default connect ()(ProfileMenu);

标签: reactjs react-redux axios


【解决方案1】:

我设法通过将状态添加到道具来访问我的 layout.js 文件中的用户名:

const mapStateToProps = (state, ownProps) => {
  return {
    isAuthenticated: state.auth.isAuthenticated,
    user: state.auth.user,
    props: ownProps
  }
};

我使用 ownProps 也是为了能够在布局容器中使用 props.children。比我将 tham 作为布局容器的参数,并且能够使用 user.name 访问用户名。 当我已经尝试使用 mapStateToProps 时,我不完全确定为什么它现在有效,而不是以前有效。

【讨论】:

    【解决方案2】:

    这就是你应该如何访问 auth reducer 然后访问用户

    const mapStateToProps = state => ({
        userName: state.auth.user.name,
        userEmail: state.auth.user.email
    });
    

    redux 就是这样工作的,假设这是你的商店

    
    import {cartReducer} from './reducers/CartReducer'
    import { authReducer } from './reducers/AuthReducer'
    import { ordersReducer } from './reducers/OrdersReducer'
    import { errorsReducer } from './reducers/ErrorsReducer'
    
    const initialState={
        products:{
            items:[],
            filterdProducts:[]
        },
        cart:{
            items:[],
        },
        orders:{
            items:[],
            canOrder:true,
        },
       auth: {
        access: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjAzNDgzODY1LCJqdGkiOiJhYTAzYzIzNTUwN2M0YTkxYjA2NjNmNDc0ZTU2MjIxMSIsInVzZXJfaWQiOjF9.Jyld4U7i6EqmsNoi0_qT9O9Kcu1TiEuyLLYCWWaoBrU',
        refresh: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYwMzU2OTk2NSwianRpIjoiOWIzMWIyN2M1ODkyNDRiZDk3Y2EwMDI1NTY2Mzk3ZWMiLCJ1c2VyX2lkIjoxfQ.UgH_753OoWD3NXiwPwa1645_vIHUl-FwyvQMJWMgHtk',
        isAuthenticated: true,
        user: {
          name: 'Jonas Levin',
          id: 1,
          email: 'jonaslevin1903@gmail.com'
        }
      },
        error:{
            msg:null,
            status:null,
            id:null
        }
    }
    
    const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__  || compose 
    
    const  store = createStore(combineReducers({
            products: productsReducer,
            cart    : cartReducer ,
            orders  : ordersReducer ,
            auth    : authReducer,
            error   : errorsReducer ,
        }),
        initialState,
        composeEnhancer(applyMiddleware(thunk))
    )
    export default store
    

    如果你想从任何其他组件访问用户,你首先需要访问 auth reducer,同样的项目,你可以访问 products.items 或 cart .items 等等

    【讨论】:

    • 我在原始问题中添加了我的商店,因此您可以查看它,但我在 actions/auth.js 文件中指定了初始状态,然后将其导入到我的商店
    • 所以你不能访问state.auth.user.name, 吗?
    • 不,它没有用。我认为错误在于,当我查看 redux Devtool 中的状态时,AUTHENTICATED_SUCCESS 类型的用户对象设置为 null,但 load_user 也被调用并显示了 USER_LOADED_SUCCES 的类型,另一方面,该函数具有带有用户名的用户对象。但我认为,当我执行 mapStateToProps:userName: state.auth.user.name 时,它会从 AUTHENTICATED_SUCCESS 获取对象,这是 null 但我希望它获取 USER_LOADED_SUCCES 类型的对象。
    • 可以尝试按照我设置的方式设置您的商店,因为这是常见做法,更容易发现错误且直观
    【解决方案3】:

    如果你使用函数式组件,你可以使用useSelector hook。

    const user = useSelector(state => state.auth.user)
    

    【讨论】:

    • 我尝试了 useSelector 钩子并尝试渲染 {user},但我得到了一个对象数组,它们是名称、id、电子邮件并得到一个错误。如果我尝试渲染 {user.name} 我也会收到一个错误,因为它指出 {user.name}: null
    猜你喜欢
    • 2017-10-31
    • 1970-01-01
    • 2020-10-15
    • 1970-01-01
    • 2021-05-04
    • 2019-02-27
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    相关资源
    最近更新 更多