我面临的情况是我将一系列作业存储为Redux状态。我有一个容器,它使用Redux connect访问数据并使用this.props.params中的参数然后找到适当的Job,然后将其作为prop传递给它的子项。
在子组件中,作业会触发更新作业的操作,然后合并并更新商店中的作业。这似乎工作正常,但当容器重新渲染时,孩子没有。我可以看到,这与我不把工作存放为道具或国家这一事实有关。
我的问题是最好的(Redux)处理这个问题的方法是什么?
因此,如果我将JobShow更改为包含jobs = {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 Snippet:
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}
答案 0 :(得分: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}
答案 1 :(得分:1)
看起来你自己想出来了,但你可能会发现轻微的重构可以提高你所做的事情的清晰度。以下是一些如何使用对象分配操作更改Reducer结构的示例:
case ActionTypes.EDIT_TODO:
return Object.assign({},
state,
{ text: action.text }
)
官方redux文档中还有更多内容(redux.js.org/docs/recipes/UsingObjectSpreadOperator.html)
您可能还会发现编写测试并使用像deepFreeze这样的包很有用,因为如果您意外地改变了状态而没有意识到它会告诉您错误。