【问题标题】:Set `store` as reducer's `state` parameter将`store`设置为reducer的`​​state`参数
【发布时间】:2019-07-07 21:45:06
【问题描述】:

我是 Redux(和 React)的新手,所以这可能是一个非常基本的问题,但我无法通过 Internet 找到直接的答案。

我的应用上有一个注册屏幕,我称之为SignUp。它非常简单,只有三个输入(emailpasswordpasswordCheck)和一个按钮(signup)。 问题是,我想让我的用户生活尽可能简单,所以当passwordCheck 发生变化时,我会对照password 进行检查。如果它们匹配,signup 设置为启用,如果它们不匹配,signup 将禁用,并向用户显示一条消息。 当我只使用 React 时,事情非常简单——我只是做了一个 this.state

this.state: {
    // ... stuff
    password: "",
    passwordIsValid: false, //test password against a predicate function
    passwordMessage: "", //if the password is not valid there is a message
    passwordStyle: "", //if password is wrong i put some classes here
    passwordCheck: "",
    passwordCheckMessage: "", //the 'passwords do not match' message goes here
    passwordCheckStyle: "",
    passwordsMatch: false
}

然后我在SignUp 中处理了应用程序的状态。 现在我也在使用 Redux,所以我杀死了 this.state,将所有内容移至 store,并开始使用 reducer 而不是处理程序。 password 一切正常,但 passwordCheck 是另一回事。由于我需要知道 Store 的 password 以对照 passwordCheck 进行检查,因此我无法(到目前为止?)在 passwordCheckReducer 上执行此操作。相反,我从passwordCheckReducer 中删除了passwordCheckMessagepasswordCheckStylepasswordsMatch,在SignUp 上计算这些值。不过,在我看来,这是一种非常错误和丑陋的方式来解决整个问题。

所以,相反,我想要一个更优雅和类似 Redux 的解决方案。

如果我能让store 出现在passwordCheckReducerstate 上,我就可以在reducer 中设置passwordsMatch 和其他人,同时保持它的纯净。不幸的是,我一直无法做到(到目前为止?)。 所以,我想知道我想做的事情是否可行,或者是否有其他更理想的方法。

OBS1:我在网上随便找了一个关于初始化state1的Redux官方文档。不过,我不认为preloadedState 是解决我的问题的方法,因为它用于初始化store,而不是让它在我的减速器上可用。相反,我只需要让store——即使是空的——对passwordCheckReducer 可见。 OBS2:我知道我可以将store 作为action 的键传递,但由于reducer 模式包含state 参数,因此在action 中定义传递这样的参数对我来说似乎是多余的。

这是我的商店:

// store.js
import { applyMiddleware, createStore } from 'redux';
import { createLogger } from 'redux-logger';
import thunkMiddleare from 'redux-thunk';
import { Reducers } from '../reducers/reducers';

const logger = createLogger();
const middleware = applyMiddleware(thunkMiddleare, logger);

export const Store = createStore(Reducers, middleware);

我正在使用combineReducers

// reducers.js
import { combineReducers } from 'redux';
import { emailReducer } from './emailReducer';
import { passwordReducer } from './passwordReducer';
import { passwordCheckReducer } from './passwordCheckReducer';

export const Reducers = combineReducers({
    emailChange: emailReducer,
    passwordChange: passwordReducer,
    passwordCheckChange: passwordCheckReducer
}); 

这里是passwordCheckReducer

// passwordCheckReducer.js
import { CHANGE_PASSWORDCHECK } from '../actions/actionTypes';

const initialState = {
    passwordCheck: ""
};

export const passwordCheckReducer = (state=initialState, action) => {
    const { payload, type } = action;

    switch(type) {
        case CHANGE_PASSWORDCHECK:
            const passwordCheck = payload;
            return {
                ...state,
                passwordCheck
            };
        default: 
            return state;
    }
};

最后,这是mapDispatchToProps的实现:

// SignUp.js
const mapDispatchToProps = dispatch => ({
    handleEmailChange: e => dispatch(updateEmail(e.target.value)),
    handlePasswordChange: e => dispatch(updatePassword(e.target.value)),
    handlePasswordCheckChange: e => dispatch(updatePasswordCheck(e.target.value))
});

【问题讨论】:

    标签: javascript reactjs redux state store


    【解决方案1】:

    如果我没记错的话,当您将 reducer 传递给 combineReducers 时,该 reducer 将接收 redux 模块状态(因此,initialState 是什么,而不是整个应用程序的根状态对象)。您无权访问其他减速器的状态。

    您有几个选择。

    我认为为passwordpasswordCheck 设置单独的减速器有点矫枉过正。我会为整个表单使用一个减速器:

    const initialState = {
        password: '',
        passwordCheck: '',
        // ....
    }
    
    export const signupReducer = (state=initialState, action) => {
        const { payload, type } = action;
    
        switch(type) {
            case CHANGE_PASSWORD:
                return { ...state, password: action.password}
            case CHANGE_PASSWORDCHECK:
                const passwordCheck = payload;
                if (state.password != state.passwordCheck) 
                    return { ...state, passwordCheck, error: "..."}; // or something like this
    
                return {
                    ...state,
                    passwordCheck
                };
            default: 
                return state;
        }
    };
    
    

    如果你想把事情分开,你总是可以定义减速器,并从一个父减速器调用它们,传递整个父减速器状态。比如:

    import passwordReducer from './passwordReducer'
    import passwordCheckReducer form './passwordCheckReducer'
    
    export const signupReducer(state = initialState, action) => {
        state = passwordReducer(state, action)
        state = passwordCheckReducer(state, action)
        return state
    }
    

    【讨论】:

      【解决方案2】:

      如果你正在组合 reducer,那么只有一个 store 对象存储来自每个 reducer 的所有状态。

      所以你可以像这样从一个组件访问多个reducer:

      const mapStateToProps = state => ({
        password: state.passwordChange.password,
        passwordCheck: state.passwordCheckChange.passwordCheck,
        passwordsMatch: state.passwordCheckChange.passwordsMatch
      })
      export default connect(mapStateToProps, mapDispatchToProps)(SignUp)

      每次更新 passwordCheckpassword 时,组件的 props 都会更新。

      因此,最好的解决方案实际上是将 passwordsMatch 处理为从两个单独的 reducer 的状态派生的自定义 prop。类似的东西:

      const mapStateToProps = state => {
        const passwordsMatch = state.passwordChange.password === state.passwordCheckChange.passwordCheck
        return {
          password: state.passwordChange.password, 
          passwordCheck: state.passwordCheckChange.passwordCheck,
          passwordsMatch: passwordsMatch
        }
      }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-10-16
        • 2021-07-17
        • 1970-01-01
        • 1970-01-01
        • 2016-01-29
        • 1970-01-01
        • 2011-09-07
        • 2020-05-04
        相关资源
        最近更新 更多