Redux-form - 从状态初始化错误并集成到发布数据的操作?

时间:2017-09-07 16:49:45

标签: reactjs redux redux-form

我是redux-form的新手 - 我现在正在尝试掌握预填充数据概念。

http://redux-form.com/6.0.0-rc.1/examples/initializeFromState/

当我测试这段代码时 - 它会中断。

“TypeError:无法读取未定义的属性'数据'”

enter image description here

此示例编写连接/ redux部分的方式与我过去与其他组件的定义方式不同。

// Decorate with reduxForm(). It will read the initialValues prop provided by connect()
InitializeFromStateForm = reduxForm({
  form: 'initializeFromState'  // a unique identifier for this form
})(InitializeFromStateForm)

// You have to connect() to any reducers that you wish to connect to yourself
InitializeFromStateForm = connect(
  state => ({
    initialValues: state.account.data // pull initial values from account reducer
  }),
  { load: loadAccount }               // bind account loading action creator
)(InitializeFromStateForm)

export default InitializeFromStateForm

-

所以我工作的其他形式 - 看起来像这样。

// EditUserForm.js

import React from 'react'
import { Field, reduxForm } from 'redux-form'
import { Row, Col } from 'antd';

import renderField from '../_SharedFormComponents/renderField'
import validate from './validateEditUser'
import warn from './warnEditUser'

const EditUserForm = props => {
  const { handleSubmit, pristine, reset, submitting } = props
  return (
    <form onSubmit={handleSubmit}>
      <Row>
        <Col xs={24} sm={24} md={12}>
          <Field name="firstName" type="text" component={renderField} label="First Name" />
        </Col>
        <Col xs={24} sm={24} md={12}>
          <Field name="lastName" type="text" component={renderField} label="Last Name" />
        </Col>
      </Row>  

      <div>
        <button type="submit" disabled={submitting}>
          Submit
        </button>
        <button type="button" disabled={pristine || submitting} onClick={reset}>
          Clear Values
        </button>
      </div>
    </form>
  )
}

export default reduxForm({
  form: 'syncValidationEditUser', // a unique identifier for this form
  validate, // <--- validation function given to redux-form
  warn // <--- warning function given to redux-form
})(EditUserForm)

^然后我有一个shell父母。

// EditProfile.js

import React, { Component } from 'react'
import { withRouter, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchEditProfile } from '../../actions/editProfileAction';

import { Row, Col, Button, Tabs } from 'antd';

// components
import EditUserForm from './EditUserForm'

// this is a class because it needs state
class EditProfile extends Component {

  constructor(props, context) {
    super(props, context);
    this.submitEditProfile = this.submitEditProfile.bind(this);
  }

  componentDidMount() {    
    // console.log('this', this)
  }

  submitEditProfile(data) {
    this.props.fetchEditProfile(data);
  }

  render() {

    return (
      <div>                 
                    <div className="form-components light">
                        <Row>
                          <Col xs={24} sm={24} md={10}>
                            <p>Edit Profile</p>
                          </Col>
                          <Col xs={24} sm={24} md={24}>
                            <Row>
                              <Col xs={24} sm={24} md={24}>
                                <EditUserForm onSubmit={this.submitEditProfile} />
                              </Col>
                            </Row>
                          </Col>
                        </Row>
                    </div>
      </div>
    )
  }

}

function mapStateToProps(state) {
  return {
    editProfileData: state.editProfile
  };
}

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

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(EditProfile))

-

所以根据我的理解,他们在该演示中编写连接方面的方式是这样的吗?

function mapStateToProps(state) {
  return {
    initialValues: state.account.data
  };
}

function mapDispatchToProps(dispatch) {
 return bindActionCreators({ load: loadAccount }, dispatch);
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(EditProfile))

-

但我仍然希望保留收集和处理数据......

function mapStateToProps(state) {
  return {
    initialValues: state.initProfile,
    editProfileData: state.editProfile
  };
}

function mapDispatchToProps(dispatch) {
 return bindActionCreators({ fetchInitProfile, fetchEditProfile}, dispatch);
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(EditProfile))

并在“compentDidMount或compentWillMount或componentDidUpdate”中调用? this.fetchInitProfile();

.. 我的initProfile操作会是这样的吗?

// InitProfile.js

import axios from 'axios';

export const FETCH_INIT_PROFILE_SUCCESS = 'FETCH_INIT_PROFILE_SUCCESS'
export const FETCH_INIT_PROFILE_FAILURE = 'FETCH_INIT_PROFILE_FAILURE'

export function initProfileSuccess(response) {
  return {
    type: FETCH_INIT_PROFILE_SUCCESS,
    payload: response
  }
}

export function initProfileFail(response) {
  return {
    type: FETCH_INIT_PROFILE_FAILURE,
    payload: response
  }
}

export function fetchInitProfile(data) {
  let url = 'https://api.github.com/users/theoldcounty';
  return function (dispatch) {     
    axios.get(url)
      .then(function (response) {
        //console.log(response);
        dispatch(initProfileSuccess(response));
      })
      .catch(function (error) {
        //console.log(error);
        dispatch(initProfileFail(error));
      });
  }
}

1 个答案:

答案 0 :(得分:0)

以下是制作表单的解决方案 - 具有initialValues - 然后能够调用存储数据。

享受。

// EditProfile.js - 将其称为shell -

import React, { Component } from 'react'
import { withRouter, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchEditProfile } from '../../actions/editProfileAction';
import { fetchInitProfile } from '../../actions/initProfileAction';

import { Row, Col, Button, Tabs } from 'antd';

// components
import EditUserSyncValidationForm from './EditUserSyncValidationForm'

// this is a class because it needs state
class EditProfile extends Component {

  constructor(props, context) {
    super(props, context);
    this.submitEditProfile = this.submitEditProfile.bind(this);
    this.props.fetchInitProfile(null);//maybe you will send data like the user id here or it may be stored on server side already if they have logged in
  }

  submitEditProfile(data) {
    this.props.fetchEditProfile(data);
  }

  render() {
    const initialValues = this.props.initProfileData.data;

    return (
      <div>                 
                    <div className="form-components light">
                        <Row>
                          <Col xs={24} sm={24} md={10}>
                            <p>Edit Profile</p>
                          </Col>
                          <Col xs={24} sm={24} md={24}>
                            <Row>
                              <Col xs={24} sm={24} md={24}>
                                <EditUserSyncValidationForm initialValues={initialValues} onSubmit={this.submitEditProfile} />
                              </Col>
                            </Row>
                          </Col>
                        </Row>
                    </div>
      </div>
    )
  }

}

function mapStateToProps(state) {
  return {
    editProfileData: state.editProfile,
    initProfileData: state.initProfile
  };
}

function mapDispatchToProps(dispatch) {
 return bindActionCreators({fetchInitProfile, fetchEditProfile}, dispatch);
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(EditProfile))

// EditUserSyncValidation - 这是表单本身

import React from 'react'
import { Field, reduxForm } from 'redux-form'
import { Row, Col } from 'antd';

import renderField from '../_SharedFormComponents/renderField'
import validate from './validateEditUser'
import warn from './warnEditUser'

const EditUserSyncValidationForm = props => {
  const { handleSubmit, pristine, reset, submitting } = props
  return (
    <form onSubmit={handleSubmit}>
      <Row>
        <Col xs={24} sm={24} md={12}>
          <Field name="firstName" type="text" component={renderField} label="First Name" />
        </Col>
        <Col xs={24} sm={24} md={12}>
          <Field name="lastName" type="text" component={renderField} label="Last Name" />
        </Col>
      </Row>

      <Row>
        <Col xs={24} sm={24} md={12}>
          <Field name="pin" type="text" component={renderField} label="Pin" />
        </Col>
        <Col xs={24} sm={24} md={12}>
          <Field name="email" type="email" component={renderField} label="Email" />
        </Col>
      </Row>

      <Row>
        <Col xs={24} sm={24} md={12}>
          <Field name="password" type="password" component={renderField} label="Password" />
        </Col>
        <Col xs={24} sm={24} md={12}>
          <Field name="confirmPassword" type="password" component={renderField} label="Confirm Password" />
        </Col>
      </Row>

      <Row>
        <Col xs={24} sm={24} md={12}>
          <Field name="phoneNumber" type="text" component={renderField} label="Phone Number" />
        </Col>
        <Col xs={24} sm={24} md={12}>
        </Col>
      </Row>      

      <div>
        <button type="submit" disabled={submitting}>
          Submit
        </button>
        <button type="button" disabled={pristine || submitting} onClick={reset}>
          Clear Values
        </button>
      </div>
    </form>
  )
}

export default reduxForm({
  form: 'syncValidationEditUser', // a unique identifier for this form
  validate, // <--- validation function given to redux-form
  warn // <--- warning function given to redux-form
})(EditUserSyncValidationForm)

然后我们有行动。

// editProfileAction.js

import axios from 'axios';

export const FETCH_EDIT_PROFILE_SUCCESS = 'FETCH_EDIT_PROFILE_SUCCESS'
export const FETCH_EDIT_PROFILE_FAILURE = 'FETCH_EDIT_PROFILE_FAILURE'

export function editProfileSuccess(response) {
  return {
    type: FETCH_EDIT_PROFILE_SUCCESS,
    payload: response
  }
}

export function editProfileFail(response) {
  return {
    type: FETCH_EDIT_PROFILE_FAILURE,
    payload: response
  }
}

export function fetchEditProfile(data) {
  let url = '/apicall/editUser';
  return function (dispatch) {     
    axios.get(url)
      .then(function (response) {
        //console.log(response);
        dispatch(editProfileSuccess(response));
      })
      .catch(function (error) {
        //console.log(error);
        dispatch(editProfileFail(error));
      });
  }
}

// initProfileAction.js

import axios from 'axios';

export const FETCH_INIT_PROFILE_SUCCESS = 'FETCH_INIT_PROFILE_SUCCESS'
export const FETCH_INIT_PROFILE_FAILURE = 'FETCH_INIT_PROFILE_FAILURE'

export function initProfileSuccess(response) {
  return {
    type: FETCH_INIT_PROFILE_SUCCESS,
    payload: response
  }
}

export function initProfileFail(response) {
  return {
    type: FETCH_INIT_PROFILE_FAILURE,
    payload: response
  }
}

export function fetchInitProfile(data) {
  let url = 'api/getInitialProfileData';
  return function (dispatch) {     
    axios.get(url)
      .then(function (response) {
        //console.log(response);

      var response = {
          "firstName": "Johnny",
          "lastName" : "Rockstar",
          "pin" : "1234",
          "email" : "johnny@bmail.com",
          "phoneNumber" : "0202 02002020"
        }

        dispatch(initProfileSuccess(response));
      })
      .catch(function (error) {
        //console.log(error);
        dispatch(initProfileFail(error));
      });
  }
}

...然后是减速器

// initProfileReducer.js

import { FETCH_INIT_PROFILE_SUCCESS, FETCH_INIT_PROFILE_FAILURE } from '../actions/initProfileAction'

export function initProfileReducer (state = {}, action) {
  //console.log('reducer REG act', action)
  switch (action.type) {
    case FETCH_INIT_PROFILE_SUCCESS:
      return {...state, data: action.payload, isProfileInit: true};
    case FETCH_INIT_PROFILE_FAILURE:
      return {...state, data: action.payload, isProfileInit: false}; 
    default:
      return {...state} 
  }
}

// editProfileReducer.js

import { FETCH_EDIT_PROFILE_SUCCESS, FETCH_EDIT_PROFILE_FAILURE } from '../actions/editProfileAction'

export function editProfileReducer (state = {}, action) {
  switch (action.type) {
    case FETCH_EDIT_PROFILE_SUCCESS:
      return {...state, data: action.payload, isProfileEdited: true};
    case FETCH_EDIT_PROFILE_FAILURE:
      return {...state, data: action.payload, isProfileEdited: false}; 
    default:
      return {...state} 
  }
}