React Redux如何在Reducer中存储http响应

时间:2016-09-03 11:19:09

标签: reactjs redux react-redux

我有一个数据表" View"链接。单击后,它必须从后端获取数据。但是我在以{React-Redux风格存储response时遇到了麻烦。

这是数据表的片段:

$("#personTable").dataTable({
  "columns" : [
     { "data" : "id", "name":"id" ,
         "render": (data, type, full,meta) => {
            return '<a href="#/person/view?id='+data+'">View</a>;
         }
     }

在我的routes.jsx中,我将其定义为转发到PersonForm.jsx

<Route name='personForm' path='/person/view' component={PersonForm}/>

在我的PersonForm组件中,我有:

componentWillMount() {
  let personId = this.props.location.query.id
  this.props.onInit(personId)
}

在我的PersonFormContainer.jsx中:

export const mapDispatchToProps = (dispatch) => {
  return {
    onInit: (personId) => {
      dispatch(init(personId))
    }
  }
}

这是我的PersonActions.jsx:

export function init(personId) {
  return function (dispatch) {

    httpService.request('/person/view/' + personId, {method: 'get'})
      .then((response) => {

        console.log(response.data) // response.data is correctly returned

        dispatch({
          type: "PERSON_INIT",
          data: response.data
        })
    }).catch(err => console.log(err))
  }
}

在我的PersonReducer.js中:

var Immutable = require('immutable');

let initialState =
  Immutable.fromJS({
    data: {},
    fields: {
      name: field.create('name', [validation.REQUIRED])
    }
  })

export default function (state = initialState, action) {
  switch(action.type) {
    case PERSON_INIT:
      return state.set("data", action.data)
      //return state.set("fields", Immutable.fromJS(action.fields))
    default:
      return state
  }
}

现在,问题出现在我的PersonForm.jsx上了。在调用render()时,数据(在我的reducer中)有一些值,但不是字段。我不知道如何将response.data(在我的PersonActions中)转换为Reducer中的字段。像这样:

if (data) {
  for (let key in fields) {
    fields[key].value = data[key]
  }
}

这是我的PersonForm组件:

render() {

  let store = this.props.person
  let fieldsMap = store.get("fields")

  <ImmutableInputText label="Name" field={fieldsMap.get("name")}/>

注意:ImmutableInputText来自我们的模板,如:

  <input id={field.name} className="form-control" name={field.name}
        value={this.state.value} onBlur={this.handleBlur} onChange={changeHandler}
        disabled={disabled}/>

1 个答案:

答案 0 :(得分:1)

我试图在不知道响应对象结构的情况下回答这个问题,所以我会根据你的回复更新这个答案。

现在,让我们假设这是您从服务器获得的响应

{
  "code": 200,
  "message": "success",
  "person": {
    "name": "John Doe",
    "email": "john.doe@gmail.com",
    "dob": "1980-01-01",
    "gender": "male",
    "status": "active",
  }
}

PersonReducer.js中,您可以执行类似

的操作
export default function (state = initialState, action) {
  switch(action.type) {

    case PERSON_INIT:
      return state.set("fields", Immutable.fromJS(action.data.person) )

    default:
      return state

  }
}

但这样做会将现有的fields对象替换为从服务器收到的数据。

如果您想保留所有现有数据并仅更新已更改或新的数据..,您可以执行类似

的操作
case PERSON_INIT:
  return state.set("fields", Immutable.fromJS({ ...state.get('fields').toObject(), ...action.data.person }) )

如果您只想更新名称字段,可以执行类似

的操作
case PERSON_INIT:
    return state.setIn(['fields', 'name'], action.data.person.name );

但是你必须为每个领域做到这一点并且不会非常有效,所以你可以通过这样做来实现这个动态

PersonActions.jsx文件中(或您想要此动态字段更新功能的任何位置),您可以将调度代码更改为

dispatch({
  type: "PERSON_UPDATE_FIELD",
  payload: { field: 'name', value: response.data.person.name }
})

注意:我在这里使用的是payload而不是data,我认为最好遵循redux命名惯例,但是你的#&#并没有错39;只要你在整个应用程序中坚持使用相同的约定就行了。

在您的PersonReducer.js中,您可以拥有类似

的内容
case PERSON_UPDATE_FIELD:
    return state.setIn(['fields', action.payload.field ], action.payload.value );
祝你好运。