Redux状态的更改未反映在组件中

时间:2019-03-29 14:25:05

标签: reactjs redux react-redux

我正在构建一个显示登录表单的原型。 Submit事件触发从数据库中的查找。如果查找失败,我希望将表单更改为a)显示错误消息,b)放弃先前输入的用户ID和密码。

我的reducer更改了Redux中的状态,但是我不确定如何将数据传输回组件状态。

这是我的表格:

import React from 'react';
import { NavLink } from 'react-router-dom';
import { connect } from 'react-redux';

export class LoginForm extends React.Component {
    constructor(props) {
        super(props);
        console.log("Login form props", props);
        this.state = {
            userName:  props.user ? props.user.userName : '',
            password:  props.user ? props.user.password : '',
            error: props.error ? props.error : ''
        }

    }

    onUserNameChange = (event) => {
        const userName = event.target.value;
        this.setState(() => ({ userName }));
    };

    onPasswordChange = (event) => {
        const password = event.target.value;
        this.setState(() => ({ password }));
    };

    onSubmit = (event) => {
        event.preventDefault();

        if (!this.state.userName || !this.state.password) {
            this.setState(() => ({ error:  'User name and password are required.'}));
        } else {
            this.setState(() => ({ error:  '' }));
            this.props.onSubmit({
                userName:  this.state.userName,
                password:  this.state.password
            })
        }
    };

    render() {
        console.log("Login form render() this.state", this.state);
        // console.log("Login form render() this.props", this.props);
        return (
            <div>
                {this.props.error && <p>{this.props.error}</p>}
                <form onSubmit={this.onSubmit}>
                    <input
                        type="text"
                        placeholder="User name"
                        autoFocus
                        value={this.state.userName}
                        onChange={this.onUserNameChange}
                    />
                    <input
                        type="password"
                        placeholder="Password"
                        value={this.state.password}
                        onChange={this.onPasswordChange}
                    />
                    <button>Sign In</button>
                </form>
                <NavLink to="/passwordRecovery" activeClassName="is-active" exact={true}>Forgot Password?</NavLink>
                <NavLink to="/newUser" activeClassName="is-active">New User?</NavLink>
            </div>
        )
    }
}

const mapStateToProps = (state) => {
    console.log('in LoginForm state.authentication:  ', state.authentication);
    if (state.authentication.user)
    {
        return {
            error:  state.authentication.error,
            userName:  state.authentication.user.userName,
            password:  state.authentication.user.password
        }
    } else {
        return {
            error:  state.authentication.error,
            user:  state.authentication.user
        }
    }

}

export default connect(mapStateToProps, undefined)(LoginForm);

这是显示表单的页面:

import React from 'react';
import { connect } from 'react-redux';
import LoginForm from './LoginForm';
import { login, resetForm } from '../actions/authentication';

export class LoginPage extends React.Component {
    onSubmit = (user) => {
        console.log('LoginPage onSubmit user:  ', user);
        console.log('props ', this.props);
        this.props.login(user);
        if (this.props.user) {
             this.props.history.push("/userHome");
        }
    }

    render() {
        console.log("LoginPage.render()", this.props)
        return (
            <div>
                <LoginForm 
                    onSubmit={this.onSubmit} error={this.props.error}
                />
            </div>
        );
    }
}

const mapDispatchToProps = (dispatch) => ({
    login:  (user) => dispatch(login(user)),
    resetForm:  () => dispatch(resetForm())
});

const mapStateToProps = (state) => {
    console.log('state.authentication:  ', state.authentication);
    return {
        error:  state.authentication.error,
        user:  state.authentication.user
    };
}

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

这是减速器:

// reducer for authentication actions
const authenticationReducerDefaultState = {
    userName:  '',
    password:  ''
};

export default (state = authenticationReducerDefaultState, action) => {
    console.log('in reducer, state: ', state);
    console.log('in reducer, action: ', action);
    switch (action.type) {
        case 'LOGIN_REQUEST':
            return {
                user:  action.user,
                error:  '',
                loggedIn:  false,
                loggingIn:  true
            };
        case 'LOGIN_SUCCESS':
            return {
                user:  action.user,
                error:  '',
                loggedIn:  true,
                loggingIn:  false
            }
        case 'LOGIN_FAILURE':
            return {
                user:  authenticationReducerDefaultState,
                error:  action.error,
                loggedIn:  false,
                loggingIn:  false
            }
        case 'LOGOUT':
            return {
                user:  authenticationReducerDefaultState,
                error:  '',
                loggedIn:  false,
                loggingIn:  false
            };
        default:
            return state;
    };
};

这是动作:

import database from '../firebase/firebase';

const request = (user) => ({
    type:  'LOGIN_REQUEST',
    user
});

const success = (user) => ({
    type:  'LOGIN_SUCCESS',
    user
});

const failure = (error) => {
    // console.log('failure with error ', error);
    return {
    type:  'LOGIN_FAILURE',
    user:  { userName:  '', password:  '' },
    error
}};

export const login = (user) => {
    return (dispatch) => {
        const { userName, password } = user;
        // console.log(`login function for ${userName} password ${password}`);
        dispatch(request(user));
        let matchedUser = undefined;
        return database.ref(`users`).once('value').then((snapshot) => { 
            snapshot.forEach((childSnapshot) => {
                const user = childSnapshot.val();
                if (user.userName === userName &&
                    user.password === password) {
                        matchedUser = user;
                }; 
            });
            return matchedUser;
        }).then((matchedUser) => {
            console.log('matched user', matchedUser);
            if (matchedUser) {
                dispatch(success(user));
            } else {
                // console.log('dispatching failure');
                dispatch(failure(`An error occurred looking up user ID ${userName}`));
            };
            console.log('end of login function');
        });
    }    
}

// action generator for logout action
export const logout = () => ({
    type:  'LOGOUT'
});

这是我的根减少剂:

export default () => {
// Store creation
    const store = createStore(
        combineReducers({
            authentication:  authenticationReducer
        }),
        composeEnhancers(applyMiddleware(thunk))
    );
    return store;
}

我希望有人已经走了这条路。预先感谢。

2 个答案:

答案 0 :(得分:1)

问题在于,即使道具发生了变化(redux存储已更新),您仍在使用LoginForm内的本地状态。您只能将值映射到props一次(LoginForm.constructor)。 如果要对redux存储更改做出反应,则需要编写一些代码,以便在存储发生更改时更新本地状态。

static getDerivedStateFromProps (props) {
   return {
      userName:  props.user ? props.user.userName : '',
      password:  props.user ? props.user.password : '',
      error: props.error ? props.error : ''
   }
}

使用此方法返回的所有内容最终都会更新本地组件状态。

这种情况很难维护。您正在混合使用受控制和不受控制的组件的概念。您将从props获取初始值,将其映射到本地状态,然后在本地(当输入更改时)处理状态更改,而且还要对商店中的更改做出反应。

提示:如果您使用默认的道具,则不必检查this.props.user是否可用。

static defaultProps = {
   user: {
      userName: '',
      password: '''
   },
   error: ''
}

答案 1 :(得分:0)

您是否尝试过从mapStateToProps中删除逻辑

if (state.authentication.user)
{
    return {
        error:  state.authentication.error,
        userName:  state.authentication.user.userName,
        password:  state.authentication.user.password
    }
} else {
    return {
        error:  state.authentication.error,
        user:  state.authentication.user
    }
}
}

收件人:

return {
            error:  state.authentication.error,
            userName:  state.authentication.user.userName,
            user:  state.authentication.user
            password:  state.authentication.user.password
        }