简体   繁体   English

从另一个减速器中的一个减速器访问减速器状态的一部分

[英]Accessing a part of reducer state from one reducer within another reducer

I do not know how to access a boolean isLoading flag from reducerForm.js reducer in reducerRegister.js .我不知道如何从reducerRegister.js中的reducerForm.js reducer 访问 boolean isLoading标志。 I have used combineReducers() and I use isLoading to disable a button during form submit.我使用combineReducers()并使用isLoading在表单提交期间禁用按钮。

It's initial state is false, after clicking submit, it changes to true .它的初始状态是 false,点击提交后,它变为true After the form submission is successful, isLoading is reset to false again.表单提交成功后,再次将isLoading重置为false Below is the relevant code for this issue:下面是这个问题的相关代码:

actionRegister.js actionRegister.js

let _registerUserFailure = (payload) => {
    return {
        type: types.SAVE_USER_FAILURE,
        payload
    };
};
let _registerUserSuccess = (payload) => {
    return {
        type: types.SAVE_USER_SUCCESS,
        payload,
        is_Active: 0,
        isLoading:true
    };
};

let _hideNotification = (payload) => {
    return {
        type: types.HIDE_NOTIFICATION,
        payload: ''
    };
};

// asynchronous helpers
export function registerUser({ // use redux-thunk for asynchronous dispatch
    timezone,
    password,
    passwordConfirmation,
    email,
    name
}) {
    return dispatch => {
        axios.all([axios.post('/auth/signup', {
                    timezone,
                    password,
                    passwordConfirmation,
                    email,
                    name,
                    is_Active: 0
                })
                // axios.post('/send', {email})
            ])
            .then(axios.spread(res => {
                dispatch(_registerUserSuccess(res.data.message));
                dispatch(formReset());
                setTimeout(() => {
                    dispatch(_hideNotification(res.data.message));
                }, 10000);
            }))
            .catch(res => {
                // BE validation and passport error message
                dispatch(_registerUserFailure(res.data.message));
                setTimeout(() => {
                    dispatch(_hideNotification(res.data.message));
                }, 10000);
            });
    };
} 

actionForm.js actionForm.js

export function formUpdate(name, value)  {
    return {
        type: types.FORM_UPDATE_VALUE,
        name, //shorthand from name:name introduced in ES2016
        value
    };
}
export function formReset() {
  return {
    type: types.FORM_RESET
  };
}

reducerRegister.js reducerRegister.js

const INITIAL_STATE = {
  error:{},
  is_Active:false,
  isLoading:false
};
const reducerSignup = (state = INITIAL_STATE , action) => {
  switch(action.type) {
    case types.SAVE_USER_SUCCESS:
      return { ...state, is_Active:false, isLoading: true, error: { register: action.payload }};
      case types.SAVE_USER_FAILURE:
      return { ...state, error: { register: action.payload }};
      case types.HIDE_NOTIFICATION:
      return { ...state , error:{} };
   }
      return state;
};
export default reducerSignup;

reducerForm.js reducerForm.js

const INITIAL_STATE = {
    values: {}
};
const reducerUpdate = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case types.FORM_UPDATE_VALUE:
            return Object.assign({}, state, {
                values: Object.assign({}, state.values, {
                    [action.name]: action.value,
                })
            });
        case types.FORM_RESET:
        return INITIAL_STATE;
        // here I need isLoading value from reducerRegister.js
    }
    return state;
};
export default reducerUpdate;

reducerCombined.js reducerCombined.js

import { combineReducers } from 'redux';
import reducerRegister from './reducerRegister';
import reducerLogin from './reducerLogin';
import reducerForm from './reducerForm';

const rootReducer = combineReducers({
  signup:reducerRegister,
  signin: reducerLogin,
  form: reducerForm
});

export default rootReducer;

This is where I use isLoading :这是我使用isLoading的地方:

  let isLoading = this.props.isLoading;
<FormGroup>
    <Col smOffset={4} sm={8}>
     <Button type="submit"  disabled={isLoading}
       onClick={!isLoading ? isLoading : null}
     >
     { isLoading ? 'Creating...' : 'Create New Account'}
       </Button>
   </Col>
       </FormGroup>

Mapping state to props within the same component将状态映射到同一组件内的道具

function mapStateToProps(state) {
    return {
        errorMessage: state.signup.error,
    isLoading: state.signup.isLoading,
    values: state.form.values

    };
}

This is covered in the Redux FAQ at https://redux.js.org/faq/reducers#how-do-i-share-state-between-two-reducers-do-i-have-to-use-combinereducers :这在 Redux 常见问题解答中有所介绍,网址为https://redux.js.org/faq/reducers#how-do-i-share-state-between-two-reducers-do-i-have-to-use-combinereducers

Many users later want to try to share data between two reducers, but find that combineReducers does not allow them to do so.许多用户后来想尝试在两个 reducer 之间共享数据,但发现 combineReducers 不允许他们这样做。 There are several approaches that can be used:有几种方法可以使用:

  • If a reducer needs to know data from another slice of state, the state tree shape may need to be reorganized so that a single reducer is handling more of the data.如果一个 reducer 需要了解来自另一个状态片的数据,则可能需要重新组织状态树形状,以便单个 reducer 可以处理更多数据。
  • You may need to write some custom functions for handling some of these actions.您可能需要编写一些自定义函数来处理其中一些操作。 This may require replacing combineReducers with your own top-level reducer function.这可能需要用您自己的顶级 reducer 函数替换 combineReducers。 You can also use a utility such as reduce-reducers to run combineReducers to handle most actions, but also run a more specialized reducer for specific actions that cross state slices.您还可以使用诸如 reduce-reducers 之类的实用程序来运行 combineReducers 来处理大多数操作,但也可以为跨状态切片的特定操作运行更专业的 reducer。
  • Async action creators such as redux-thunk have access to the entire state through getState(). redux-thunk 等异步操作创建者可以通过 getState() 访问整个状态。 An action creator can retrieve additional data from the state and put it in an action, so that each reducer has enough information to update its own state slice. action creator 可以从状态中检索额外的数据并将其放入 action 中,这样每个 reducer 都有足够的信息来更新自己的状态片。

A reducer cannot access another reducer's state, but if you're using redux-thunk you can do so from within an action creator.一个 reducer 不能访问另一个 reducer 的状态,但是如果你使用redux-thunk ,你可以在 action creator 中这样做。 As an example, you can define an action creator like this:例如,您可以像这样定义一个动作创建者:

export const someAction = () =>
  (dispatch, getState) => {
    const someVal = getState().someReducer.someVal;
    dispatch({ type: types.SOME_ACTION, valFromOtherReducer: someVal });
  };

React Redux works on unidirectional data flow. React Redux 适用于单向数据流。

Action ---> Reducer /store ---> Reducer

Reducer works on small subset of store, you can not access store inside reducer which is not part of Reducer. Reducer 在小的 store 子集上工作,你不能访问不属于 Reducer 的 reducer 内部的 store。 you can either need to fire new action from the component based on reducer state return.您可能需要根据 reducer 状态返回从组件中触发新操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM