首页 文章

React,Redux:更新状态并重新渲染子项

提问于
浏览
1

我面临的情况是我将一系列作业存储为Redux状态 . 我有一个容器,它使用Redux connect访问数据并使用this.props.params中的参数然后找到适当的Job,然后将其作为prop传递给它的子项 .

在子组件中,作业会触发更新作业的操作,然后合并并更新存储中的作业 . 这似乎工作正常,但当容器重新渲染时,孩子没有 . 我可以看到,这与我不把工作存放为道具或国家这一事实有关 .

我的问题是什么是最好的(Redux)方法来处理这个问题?

因此,如果我将JobShow更改为包含jobs = ,则会在作业更新后重新呈现 . 这似乎表明状态没有变异,我也可以确认容器本身重新渲染甚至重新运行renderView()但不重新渲染JobShow .

容器:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../actions';
import JobShow from './job_show';


class JobContainer extends Component {
  constructor(props){
    super(props);
  }

  renderView(job, customer){
    let viewParam = this.props.params.view;
    switch(viewParam){
      case "edit": return <JobEdit customer={customer} job={job}/>
      case "notes": return <JobShow customer={customer} activeTab={"notes"} job={job}/>
      case "quote": return <JobShow customer={customer} activeTab={"quote"} job={job}/>
      case "invoice": return <JobShow customer={customer} activeTab={"invoice"} job={job}/>
      default: return <JobShow customer={customer} activeTab={"notes"} job={job}/>
    }
  }
  render() {
    let { jobs, customers } = this.props;

    if (jobs.length < 1 || customers.length < 1){
      return <div>Loading...</div>;
    }
    let job = jobs.find(jobbie => jobbie.displayId == this.props.params.jobId);
    let customer = customers.find(customer => customer._id.$oid == job.customers[0]);

    return (
      <div className="rhs">
        {this.renderView(job, customer)}
      </div>
    );
  }
}
JobContainer.contextTypes = {
  router: React.PropTypes.object.isRequired
};
function mapStateToProps(state) {
  return  { 
    jobs: state.jobs.all,
    customers: state.customers.all
  };
}

export default connect(mapStateToProps, actions )(JobContainer);

Reducer片段:

import update from 'react-addons-update';
import _ from 'lodash';

export default function(state= INITIAL_STATE, action) {
  switch (action.type) {
    case FETCH_ALL_JOBS:     
      return { ...state, all: action.payload, fetched: true };

    case UPDATE_JOB_STATUS:

      let newStatusdata = action.payload;

      let jobToUpdate = state.all.find(jobbie => jobbie.displayId == newStatusdata.displayId);
      jobToUpdate.status = newStatusdata.newStatus;
      jobToUpdate.modifiedAt = newStatusdata.timeModified;

      let updatedJobIndex = _.indexOf(state.all, state.all.find(jobbie => jobbie.displayId == newStatusdata.displayId));
      let updatedState = update(state.all, {$merge: {[updatedJobIndex]: jobToUpdate}});

      return { ...state, all: updatedState}

2 回答

  • 1

    看起来你自己想出来了,但你可能会发现轻微的重构可以提高你所做的事情的清晰度 . 以下是如何使用对象分配操作更改Reducer结构的一些示例:

    case ActionTypes.EDIT_TODO:
      return Object.assign({}, 
        state, 
        { text: action.text }
      )
    

    来自:https://github.com/mjw56/redux/blob/a8daa288d2beeefefcb88c577a7c0a86b0eb8340/examples/todomvc/reducers/todos.js

    官方redux文档中还有更多内容(redux.js.org/docs/recipes/UsingObjectSpreadOperator.html)

    您也可能会发现编写测试并使用像deepFreeze这样的软件包很有用,因为如果您意外地改变状态而没有意识到,它会告诉您抛出错误 .

  • 1

    @markerikson在评论中指出的问题是我正在改变状态 . 使用react-addons-update中的$ set函数,我成功更新了内容 .

    新的reducer片段如下所示:

    case UPDATE_JOB_STATUS:
    
      let newStatusdata = action.payload;
    
      let jobToUpdate = state.all.find(jobbie => jobbie.displayId == newStatusdata.displayId);
      let updatedJob = update(jobToUpdate, {status:{$set: newStatusdata.newStatus}})
      updatedJob = update(updatedJob, {modifiedAt:{$set: newStatusdata.timeModified}})
    
      let updatedJobIndex = _.indexOf(state.all, state.all.find(jobbie => jobbie.displayId == newStatusdata.displayId));
      let updatedState = update(state.all, {$merge: {[updatedJobIndex]: updatedJob}});
    
      return { ...state, all: updatedState}
    

相关问题