【问题标题】:I can't get a value out of Redux store in App component我无法从 App 组件中的 Redux 商店中获取价值
【发布时间】:2021-06-16 04:03:26
【问题描述】:

我正在使用 Redux DevTools Chrome Extension,可以看到 Redux 商店中的 auth.isSignedIn 已通过 Register 组件正确填充。但是当我重定向到主页时它重新呈现时,我无法在 App.js 中访问 this.state.auth.isSignedIn 以正确地将用户路由到正常的主页组件。我在这里做错了什么?这是我经过培训后的第一个独立的 React 项目(但我已经做了很长时间的开发人员)。

App.js 应用组件

import React  from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import { connect } from 'react-redux';
import Header from './Header';
import history from '../history';
import Login from './Login/Login';
import Register from './Login/Register';

class App extends React.Component {
    state = { isSignedIn: null };
    
    render(){
      
        console.log('getting isSigned in');
        if(this.state.auth && this.state.auth.isSignedIn){
            console.log('it has VALUE');
            console.log(this.state.auth.isSignedIn);
        }else{
            console.log('no isSignedIn');
        }
    }
}
const mapStateToProps = (state) => {
    return { isSignedIn: state.auth.isSignedIn };
};
export default connect(mapStateToProps)(App);

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from 'redux';
import reduxThunk from 'redux-thunk';

import App from './components/App';
import reducers from './reducers';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
    reducers,
    composeEnhancers(applyMiddleware(reduxThunk))
    );

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>, 
document.querySelector('#root')
);

Register.js 注册组件

import React from 'react';
import { register } from '../../actions';
import { connect } from 'react-redux';
import LoginForm from './LoginForm';
    
class Register extends React.Component {
            
    onSubmit = (formValues) => {
        this.props.register(formValues);
    }

    render(){
        return(
            <div >
             <LoginForm formHeading="Register Now" onSubmit={this.onSubmit} />
            </div>
          );
    }
}

const mapStateToProps = (state) => {
    return { isSignedIn: state.auth.isSignedIn };
};
export default connect(mapStateToProps, { register })(Register);

actions/index.js 动作创建者

import listItems from '../apis/listItems';
import user from '../apis/user';
import history from '../history';
import { SIGN_IN, SIGN_OUT, REGISTER, CREATE_LIST_ITEM, EDIT_LIST_ITEM, DELETE_LIST_ITEM, FETCH_LIST_ITEM, FETCH_LIST_ITEMS, MARK_COMPLETED_LIST_ITEM } from './types';

export const signIn = formValues => async (dispatch, getState) => {
    let data = new FormData();
    data.append('request', 'login');
    data.append('email', formValues.email);
    data.append('password', formValues.password);

    const response = await listItems.post('/user', data);

    dispatch({ type: SIGN_IN, payload: response.data });
    history.push('/');
    
    return {
        type: SIGN_IN,
        payload: response.data
    };
};

export const register = (formValues) => async (dispatch, getState) => {
    let data = new FormData();
    data.append('request', 'register');
    data.append('email', formValues.email);
    data.append('password', formValues.password);

    const response = await user.post('/user', data);

    dispatch({ type: REGISTER, payload: response.data });
    history.push('/');
    
    return {
        type: REGISTER,
        payload: response.data
    };
};


export const signOut = () => {
    return {
        type: SIGN_OUT
    };
};

export const createListItem = formValues => async (dispatch, getState) => {
    let data = new FormData();
    data.append('listItem', formValues.list_item);
    data.append('completionLabel', formValues.completion_label);

    const response = await listItems.post('/listItemsMaintenance', data);

    dispatch({ type: CREATE_LIST_ITEM, payload: response.data });
    history.push('/');
};
export const fetchListItems = () => async dispatch => {
    const response = await listItems.get('/listItemsMaintenance');

    dispatch({ type: FETCH_LIST_ITEMS, payload: response.data });
};

export const fetchListItem = (id) => async dispatch => {
    let data = new FormData();
    data.append('list_item_id', id);
    const response = await listItems.get(`/listItemsMaintenance?list_item_id=${id}`);
        
    dispatch({ type: FETCH_LIST_ITEM, payload: response.data});
};

export const editListItem = (list_item_id, formValues) => async dispatch => {
    let data = new FormData();
    data.append('request', 'edit');
    data.append('list_item_id', list_item_id);
    data.append('listItem', formValues.list_item);
    data.append('completionLabel', formValues.completion_label);

    const response = await listItems.post(`/listItemsMaintenance`, data);

    dispatch({ type: EDIT_LIST_ITEM, payload: {...formValues, list_item_id } });
    history.push('/');
};

export const markListItemCompleted = (list_item_id) => async dispatch => {
    let data = new FormData();
    data.append('request', 'markCompleted');
    data.append('list_item_id', list_item_id);

    const response = await listItems.post('/listItemsMaintenance', data);
    // not sure what the payload actually needs to be
    dispatch({ type: MARK_COMPLETED_LIST_ITEM, payload: {...response.data, list_item_id } });
    history.push('/');
};

export const deleteListItem = (list_item_id) => async dispatch => {
    let data = new FormData();
    data.append('request', 'delete');
    data.append('list_item_id', list_item_id);

    await listItems.post(`/listItemsMaintenance`, data);

    dispatch({ type: DELETE_LIST_ITEM, payload: list_item_id });
    history.push('/');

};

reducers/authReducer.js 减速器

import { SIGN_IN, SIGN_OUT, REGISTER } from '../actions/types';

const INITIAL_STATE = {
    isSignedIn: null,
    userId: null
};

export default (state = INITIAL_STATE, action) => {
    switch (action.type){
        case REGISTER:
            return {...state, isSignedIn: true, userId: action.payload };
        case SIGN_IN:
            return {...state, isSignedIn: true, userId: action.payload };
        case SIGN_OUT:
            return {...state, isSignedIn: false, userId: null};
        default:
            return state;
    }
};

【问题讨论】:

    标签: reactjs react-redux


    【解决方案1】:

    你正在使用这个函数将你的 redux 状态映射到你的道具:

    const mapStateToProps = (state) => {
        // Suggestion, map the whole auth object:
        // return { auth: state.auth };
        return { isSignedIn: state.auth.isSignedIn };
    };
    

    在这里您说您希望使用 redux state.auth.isSignedIn 填充属性 isSignedIn。
    正如函数名称所描述的:您正在将您的 redux 状态映射到您的 PROPS

    在您的代码中,您再次使用状态来尝试获取先前映射的值。

    class App extends React.Component {
        // state = { isSignedIn: null };  This could be removed
        // For simplicity and readability's sake I suggest to
        // destructure your props into seperate variables like this
        const { isSignedIn } = this.props; // <--- Make sure to use PROPS and not STATE
    
        // FYI you mapped your redux state to an object with property isSignedIn,
        // and only mapped that variable, as stated before
        // You did not map the whole auth object so you can't reach that here
    
        render(){
          
            console.log('getting isSigned in');
            // if(this.state.auth && this.state.auth.isSignedIn){ <--- Your code
            // I liked your comparison, above this line, but you didn't map the
            // whole object so you can't check if auth is null here
            if(isSignedIn){
                console.log('it has VALUE');
                console.log(isSignedIn);
            }else{
                console.log('no isSignedIn');
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      当您将 mapStateToProps 参数传递给 connect 函数时,您的 redux 状态会添加到 this.props

      在您的情况下,您应该能够使用this.props.isSignedIn 访问isSignedIn

      【讨论】:

      • 感谢您的回复!这有效!
      【解决方案3】:

      要从商店获取东西,您应该使用来自 react-redux 的钩子名称 useSelector

      import { useSelector } from 'react-redux'
      
      // inside component
      const state = useSelector( state => state ) // return whole store
      const isSignedIn = useSelector( state => state.auth.isSignedIn ) // return only isSignedIn value
      

      【讨论】:

      • 这个答案对于类组件不正确(App.js是类组件)
      猜你喜欢
      • 2020-08-18
      • 1970-01-01
      • 2020-10-09
      • 2019-12-20
      • 1970-01-01
      • 2020-06-09
      • 2021-10-21
      • 1970-01-01
      • 2018-11-30
      相关资源
      最近更新 更多