使用表单输入中的数据调用操作创建者时未捕获的TypeError

时间:2017-01-30 16:57:51

标签: redux react-redux redux-form

我是新人,非常感谢你的帮助。我有一个包含四个输入(firstName,lastName,position和email)的表单,并希望将用户放入的数据传递给状态以创建用户对象。但是我总是收到这个错误:Uncaught TypeError:无法读取未定义的属性'firstName'

也许我确实把状态映射错了?老实说,我不知道。

这是我的代码:

我创建的表单,用于输入用户:

import React, { Component } from 'react';
import TextField from 'material-ui/TextField';
import { Field, FieldArray, reduxForm} from 'redux-form';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
import validate from './validate';
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin(); //Needed, otherwise an error message is shown in the console

//Texteingabefeld
const renderTextField = ({input, label, meta: {touched, error}, ...custom}) => (
  <TextField
    hintText={label}
    floatingLabelText={label}
    errorText={touched && error}
    {...input}
    {...custom}
  />
);

const renderUsers = ({fields, meta: { touched, error }}) => (
  <div>
    <div>
      <button className="btn btn-primary"
              type="button" onClick={() => fields.push({})}>
        <span className="glyphicon glyphicon-plus-sign"/>Add User
      </button>
      {touched && error && <span>{error}</span>}
    </div>

      <Field name="firstName" component={renderTextField} label="First Name"/>

      <Field name="lastName" component={renderTextField} label="Last Name"/>

      <Field name="position" component={renderTextField} label="Position"/>

      <Field name="email" component={renderTextField} label="Email"/>


    {fields.map((user, index) =>
    <div key={index}>
        <Field name={`firstName${index}`} component={renderTextField} label="First Name"/>

        <Field name={`lastName${index}`} component={renderTextField} label="Last Name"/>

        <Field name={`position${index}`} component={renderTextField} label="Position"/>

        <Field name={`email${index}`} component={renderTextField} label="Email"/>

        <button className="btn btn-xs btn-danger"
                type="button"
                title="Remove User"
                onClick={() => fields.remove(index)}>
          <span className="glyphicon glyphicon-minus-sign"/>
        </button>
    </div>
  )}
</div>
);

const UserCreation = props => {
  const { handleSubmit, pristine, reset, submitting} = props;

  return (
    <form onSubmit={handleSubmit}>

        <FieldArray name="users" component={renderUsers}/>

      <div>
        <button className="btn btn-primary btn-success"
                type="submit"
                disabled={pristine || submitting}>
          <span className="glyphicon glyphicon-send" />
          Submit
        </button>
        {' '}
        <button type="button"
                className="btn btn-primary btn-danger"
                disabled={pristine || submitting}
                onClick={reset}>
          Cancel
        </button>
      </div>
    </form>
  );
}

export default reduxForm({
  form: 'UserCreationForm',
  validate
})(UserCreation);

用户提交表单时触发操作的Component:

import React, {Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import UserCreation from '../components/UserCreation';
import { addUser } from '../actions/UserActions';

class UserControlPage extends Component {
  componentWillMount() {

  }

  handleSubmit=(values) => {
    addUser(values);
  }

  render() {
    return (
          <div>
            <legend>
                <span className="glyphicon glyphicon-user" aria-hidden="true"></span> User creation
            </legend>
            <UserCreation onSubmit={this.handleSubmit}/>
          </div>
        );
    }
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({addUser}, dispatch);
}

function mapStateToProps(state) {

  return {
    users: state.users
  }
}

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

动作创建者:

import axios from 'axios';
import {ADD_USER} from './index';

export const addUser = (user) => {
  return {
    type: ADD_USER,
    payload: {
//      id: id,
      firstName: user.payload.firstName,
      lastName: user.payload.lastName,
      position: user.payload.position,
      email: user.payload.email
    }
  };
}

减速器:

import {ADD_USER} from '../actions/index';

const INITIAL_STATE = {};

export default function UserReducer(state = INITIAL_STATE, action) {

  switch (action.type) {
    case ADD_USER:
      return [...state, {
//        id: action.id,
        firstName: action.firstName,
        lastName: action.lastName,
        position: action.position,
        email: action.email
      }];

    default:
      return state;
  }
}

3 个答案:

答案 0 :(得分:0)

我发现有些事情是错的。首先,您将数据附加到操作中的payload对象,但是您没有从reducer中的该对象中读取数据。因此,在reducer中,例如,action.firstName,它应该是action.payload.firstName

其次,你从减速机返回的是不对的。您的初始状态是一个对象,但您正在返回一个数组。因此,一旦你改变状态,你的状态就会被搞砸。试试这个:

import {ADD_USER} from '../actions/index';

const INITIAL_STATE = {};

export default function UserReducer(state = INITIAL_STATE, action) {

  switch (action.type) {
    case ADD_USER:
      return {
        ...state,
        user: action.payload
      };

    default:
      return state;
  }
}

<强>更新

我看到另一个问题。在此代码中,您引用的user.payload不存在。

export const addUser = (user) => {
  return {
    type: ADD_USER,
    payload: {
//      id: id,
      firstName: user.payload.firstName,
      lastName: user.payload.lastName,
      position: user.payload.position,
      email: user.payload.email
    }
  };
}

应该是user.firstNameuser.lastName

答案 1 :(得分:0)

动作创建者必须在没有payload的情况下获取数据,如下所示:

export const addUser = (user) => {
  return {
    type: ADD_USER,
    payload: {
      firstName: user.firstName,
      lastName: user.lastName,
      position: user.position,
      email: user.email
    }
  }
}

答案 2 :(得分:0)

谢谢你们。将动作创建者更改为

    export const addUser = (user) => {
    return {
    type: ADD_USER,
    payload: {
       firstName: user.firstName,
       lastName: user.lastName,
       position: user.position,
       email: user.email
    }
  };
}

和减速器

const INITIAL_STATE = [];

export default function UserReducer(state = INITIAL_STATE, action) {

  switch (action.type) {
    case ADD_USER:
      return [action.payload, ...state];

    default:
      return state;
  }
}

解决了错误。