我的this.props在handleSubmit和其他函数上未定义

时间:2019-06-30 05:27:56

标签: reactjs redux react-redux

我不知道为什么我的this.props在handleSubmit上显示未定义。我已尽一切可能。当我在mapStateToProps中记录状态时,我看到了动作已调度的内容,但是this.props没有采取该动作。

当我输入错误的详细信息时,这就是我在记录器中得到的(https://imgur.com/a/AXixWn9) 我已经在网上搜索,但没有任何线索。我已经调试了几个小时

Login.js

import React from 'react';
import { NavLink } from 'react-router-dom';
import { Redirect } from 'react-router';
import qs from 'qs';
import { connect } from 'react-redux';
import Outer from '../templates/outer';
import history from '../../_helpers/history';
import routes from '../../services/urls';
import apiRequest from '../../services/api';
import loginUser from '../../redux/actions/authentication.action';
import { LOGIN_FAILURE, LOGIN_SUCCESS } from '../../redux/constants/authentication.constants';
import alertActions from '../../redux/actions/alert.actions';


class LoginComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            fields: {},
            errors: {},
            loginError: '',
            submitted: false,
        };
        const { dispatch } = this.props;
        dispatch(alertActions.clear());
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(field, e) {
        const { fields } = this.state;
        fields[field] = e.target.value;
        this.setState({ fields });
    }

    handleValidation() {
        const { fields } = this.state;
        const errors = {};
        let formIsValid = true;

        // Login code
        if (!fields.code) {
            formIsValid = false;
            errors.code = 'This field is required';
        }

        // Password
        if (!fields.password) {
            formIsValid = false;
            errors.password = 'This field is required';
        }

        this.setState({ errors });
        return formIsValid;
    }

    handleSubmit(e) {
        e.preventDefault();
        const { code, password } = this.state.fields;
        this.setState({ submitted: true });
        if (this.handleValidation()) {
            this.setState({ submitted: true });
            const payload = {
                email: code,
                // level: 'SYSTEM',
                password,
            };
            const { dispatch } = this.props;
            dispatch(loginUser(payload));
        } else {
            this.setState({ submitted: false });
        }
    }

    render() {
        const { loginError, submitted } = this.state;
        return (
            <Outer>
                <form onSubmit={this.handleSubmit}>
                    <div className="mt-5" />
                    {loginError
                    && <div className="alert alert-danger">{loginError}</div>
                    }
                    <label>Login Code</label>
                    <input type="text" className="form-control" onChange={this.handleChange.bind(this, 'code')} value={this.state.fields.code || ''} />
                    <div className="text-danger mt-1 mb-1">{this.state.errors.code}</div>
                    <br />

                    <label>Password</label>
                    <input type="password" className="form-control" onChange={this.handleChange.bind(this, 'password')} value={this.state.fields.password || ''} />
                    <div className="text-danger mt-1 mb-1">{this.state.errors.password}</div>
                    <br />
                    <button
                        className="btn btn-primary btn-block text-uppercase"
                        type="submit"
                        disabled={submitted}
                    >
                        { !submitted ? 'Login to manage my cards' : 'loading...' }
                    </button>
                    <div className="row no-gutters mt-4">
                        <div className="col-md-12">
                            <NavLink to="/reset-password" className="grey">I have forgotten my password</NavLink>
                        </div>
                    </div>
                </form>
            </Outer>
        );
    }
}

function mapStateToProps(state) {
    console.error(state);
    const { auth } = state.authentication;
    const { alert } = state.alert;
    return { auth, alert };
}

export default connect(mapStateToProps)(LoginComponent);

store.js


export const store = createStore(
    rootReducer,
    applyMiddleware(
        thunkMiddleware,
        loggerMiddleware,
    ),
);

authentication.reducer.js

function loginReducer(state = {}, action) {
    switch (action.type) {
    case LOGIN_REQUEST:
        return {
            user_status: LOGIN_REQUEST,
            user_data: action,
        };
    case LOGIN_SUCCESS:
        return {
            user_status: LOGIN_SUCCESS,
            user_data: action,
        };
    case LOGIN_FAILURE:
        return {
            user_status: LOGIN_FAILURE,
            user_data: action,
        };
    default:
        return state;
    }
}

export default loginReducer;

authentication.action.js

function loginUser(payload) {
    function request(user) { return { type: LOGIN_REQUEST, user }; }
    function success(response) { return { type: LOGIN_SUCCESS, response }; }
    function failure(error) { return { type: LOGIN_FAILURE, error }; }

    return (dispatch) => {
        // const request = apiRequest(routes.LOGIN, 'POST', qs.stringify(payload));
        // const ah = loginUser(qs.stringify(payload));
        // console.log(ah);
        dispatch(request(payload));
        const fetch = apiRequest(routes.LOGIN, 'POST', qs.stringify(payload));
        return fetch.then((response) => {
            switch (response.status) {
            case 400:
                dispatch(failure(response));
                dispatch(alertActions.error(response.data.description));
                break;
            case 200:
                if (response.data.code === 0) {
                    localStorage.setItem('qwplx44', JSON.stringify(response.data));
                    dispatch(success(response.data));
                    history.push('/dashboard');
                    break;
                }
                dispatch(failure(response.data.description));
                dispatch(alertActions.error(response.data.description));
                break;
            default:
                return {};
            }
        }).catch((error) => {
            dispatch(failure(error.response.data.message));
            dispatch(alertActions.error(error.response.data.message.toString()));
            // return false;
        });

减根剂


const rootReducer = combineReducers({
    authentication: loginReducer,
    alert: alertReducer,
});

export default rootReducer;

1 个答案:

答案 0 :(得分:1)

您没有正确连接组件。您正在尝试从不存在的状态中破坏键。在您的loginReducer上没有看到名为auth的键。
因此,此行const { auth } = state.authentication;将返回未定义。这就是为什么在记录道具auth时未定义的原因。

取而代之的只是摘取您想要从状态中获取的内容,并且可以在销毁时将authentication别名为auth:)

const mapStateToProps = ({authentication: auth, alert}) => ({
    auth,
    alert
})

如果在发出请求后尝试使用化简器中存储的数据,则应使用componentDidUpdate生命周期方法

componentDidUpdate(prevProps) {
  const { auth: prevAuth } = prevProps
  const { auth } = this.props

  if (auth.user_status && ((!prevAuth.user_status && auth.user_status) || prevAuth.user_status !== auth.user_status)) {
    // TODO handle response from api here
    /* ex
      if (auth.user_status === LOGIN_FAILURE) {
        this.setState({loginFailure: auth.user_data})
      }
    */
  }
}

别的东西。

您没有将handleValidation绑定到该类,但是正在尝试访问状态。
您正在this.setState({ submitted: true });中两次致电handleSubmit。第二个是多余的,不需要。
我将重构您的apiRequest来处理qs.stringify和错误/ auth /响应状态处理,因此您不必为每个api调用写同样的东西:)