本文介绍了组件中的 React-Redux 状态与 store 中的状态不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 React 和 Redux 构建应用程序.

我有一个 Account 组件,它通过 componentWillMount 方法从服务器获取数据.在获取数据时,组件必须显示正在加载"文本,因此我已将isFetching"属性添加到帐户缩减程序中.从服务器获取数据时,此属性设置为 true.

问题是,在获取数据时,render 方法中isFetching"属性的值为false,同时store.getState 的值为false().account.isFetching 为真(必须如此).这会导致异常,因为 this.props.isFetching 是假的,所以代码试图显示 this.props.data.protectedStringdata 仍在从服务器加载(所以它是空的).

我假设 mapStateToProps 绑定了一些错误的值(可能是初始状态),但我不知道为什么以及如何修复它.

这是我的 AccountView 代码:

从'react'导入React;从'react-redux'导入{连接};从redux"导入 { bindActionCreators };import * as actionCreators from '../../actions/account';类 AccountView 扩展了 React.Component {componentWillMount() {const token = this.props.token;//使用凭据获取数据this.props.actions.accountFetchData(token);}使成为() {console.log("存储状态", window.store.getState().account);//isFetching == trueconsole.log("componentState", window.componentState);//isFetching == false返回 (<div>{this.props.isFetching === 真的吗?<h3>加载</h3>:<div>{this.props.data.protectedString}</div>}

);}}const mapStateToProps = (状态) =>{window.componentState = state.account;返回 {数据:state.account.data,isFetching: state.account.isFetching};};const mapDispatchToProps = (调度) =>{返回 {动作:bindActionCreators(actionCreators, dispatch)};};导出默认连接(mapStateToProps,mapDispatchToProps)(AccountView);

帐户缩减器:

const initialState = {数据:空,isFetching: 假};导出默认函数(状态 = 初始状态,动作){开关(动作.类型){案例 ACCOUNT_FETCH_DATA_REQUEST:返回 Object.assign({}, state, {isFetching: 真});案例 ACCOUNT_RECEIVE_DATA:返回 Object.assign({}, state, {数据:action.payload.data,isFetching: 假});默认:返回状态;}}

操作:

导出函数 accountReceiveData(data) {返回 {类型:ACCOUNT_RECEIVE_DATA,有效载荷:{数据}};}导出函数 accountFetchDataRequest() {返回 {类型:ACCOUNT_FETCH_DATA_REQUEST};}导出函数 accountFetchData(令牌){返回(调度,状态)=>{调度(accountFetchDataRequest());轴({//用于从服务器获取数据的 axios 参数}).then(checkHttpStatus).then((响应) => {dispatch(accountReceiveData(response.data));}).catch((错误) => {//错误处理});};}

这就是我创建商店的方式:

import { applyMiddleware, compose, createStore } from 'redux';从'react-router-redux'导入{路由器中间件};从'../reducers'导入rootReducer;导出默认函数 configureStore(initialState, history) {//将如此调度的路由操作添加到历史记录中const reduxRouterMiddleware = routerMiddleware(history);const 中间件 = applyMiddleware(thunk, reduxRouterMiddleware);const createStoreWithMiddleware = compose(中间件);返回 createStoreWithMiddleware(createStore)(rootReducer, initialState);}

在 index.js 中:

import { createBrowserHistory } from 'history';从'react-router-redux'导入{syncHistoryWithStore};从 './store/configureStore' 导入 configureStore;const initialState = {};const newBrowserHistory = createBrowserHistory();const store = configureStore(initialState, newBrowserHistory);const history = syncHistoryWithStore(newBrowserHistory, store);//用于测试目的window.store = 商店;

我的代码基于这个例子 - https://github.com/joshgeller/react-redux-jwt-auth-example

代码看起来一样,但由于一些模块的新版本,我改变了一些地方.

解决方案

你的三元语句是不是切换了?你的渲染函数有这个:

{this.props.isFetching === true ?<h3>加载</h3>:<div>{this.props.data.protectedString}</div>}

你的减速器中的初始状态是这样的:

const initialState = {数据:空,isFetching: 假};

这将在挂载时立即默认为 this.props.data.protectedString.

I'm building an application with React and Redux.

I have an Account component that fetches data from the server in the componentWillMount method. While the data is being fetched, the component must show the "loading" text, so I've added the "isFetching" property to the account reducer. This property is set to true while data is fetching from the server.

The problem is, that while data is being fetched, the value of the "isFetching" property in the render method is false, while at the same time the value of store.getState().account.isFetching is true (as it must be). This causes the exception, because this.props.isFetching is false, so the code is trying to show the this.props.data.protectedString while the data is still being loaded from the server (so it is null).

I assume that the mapStateToProps bind some wrong value (maybe the initial state), but I cannot figure out why and how can I fix it.

Here is my AccountView code:

import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actionCreators from '../../actions/account';

class AccountView extends React.Component {
    componentWillMount() {
        const token = this.props.token;
        // fetching the data using credentials
        this.props.actions.accountFetchData(token);
    }

    render() {
        console.log("store state", window.store.getState().account); // isFetching == true
        console.log("componentState", window.componentState); // isFetching == false
        return (
            <div>
                {this.props.isFetching === true ? <h3>LOADING</h3> : <div>{this.props.data.protectedString}</div> }
            </div>
        );
    }
}

const mapStateToProps = (state) => {
    window.componentState = state.account;
    return {
        data: state.account.data,
        isFetching: state.account.isFetching
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        actions: bindActionCreators(actionCreators, dispatch)
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(AccountView);

Account reducer:

const initialState = {
    data: null,
    isFetching: false
};

export default function(state = initialState, action) {
    switch (action.type) {
    case ACCOUNT_FETCH_DATA_REQUEST:
        return Object.assign({}, state, {
            isFetching: true
        });
    case ACCOUNT_RECEIVE_DATA:
        return Object.assign({}, state, {
            data: action.payload.data,
            isFetching: false
        });
    default:
      return state;
  }
}

Actions:

export function accountReceiveData(data) {
    return {
        type: ACCOUNT_RECEIVE_DATA,
        payload: {
            data
        }
    };
}

export function accountFetchDataRequest() {
    return {
        type: ACCOUNT_FETCH_DATA_REQUEST
    };
}

export function accountFetchData(token) {
    return (dispatch, state) => {
        dispatch(accountFetchDataRequest());

        axios({
            // axios parameters to fetch data from the server
        })
        .then(checkHttpStatus)
        .then((response) => {
            dispatch(accountReceiveData(response.data));
        })
        .catch((error) => {
            //error handling
        });
    };
}

This is how I'm creating the store:

import { applyMiddleware, compose, createStore } from 'redux';
import { routerMiddleware } from 'react-router-redux';

import rootReducer from '../reducers';

export default function configureStore(initialState, history) {
    // Add so dispatched route actions to the history
    const reduxRouterMiddleware = routerMiddleware(history);

    const middleware = applyMiddleware(thunk, reduxRouterMiddleware);

    const createStoreWithMiddleware = compose(
        middleware
    );

    return createStoreWithMiddleware(createStore)(rootReducer, initialState);
}

And in index.js:

import { createBrowserHistory } from 'history';
import { syncHistoryWithStore } from 'react-router-redux';
import configureStore from './store/configureStore';

const initialState = {};
const newBrowserHistory = createBrowserHistory();
const store = configureStore(initialState, newBrowserHistory);
const history = syncHistoryWithStore(newBrowserHistory, store);

// for test purposes
window.store = store;

My code is based on this example - https://github.com/joshgeller/react-redux-jwt-auth-example

The code looks the same, but I've changed some places because of new versions of some modules.

解决方案

Isn't your ternary statement switched? Your render function has this:

{this.props.isFetching === true ? <h3>LOADING</h3> : <div>{this.props.data.protectedString}</div> }

and your initialState in your reducer is this:

const initialState = {
  data: null,
  isFetching: false
};

That would default to this.props.data.protectedString immediately on mount.

这篇关于组件中的 React-Redux 状态与 store 中的状态不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 11:39