2016-06-27 2 views
1

Сценарий, с которым я столкнулся, есть массив заданий, сохраненных как состояние Redux. У меня есть контейнер, который обращается к данным с помощью соединителя Redux и использует параметр this.props.params, чтобы затем найти соответствующий Job, а затем передать его детям в качестве опоры.React, Redux: обновить состояние и повторно отобразить дочерние объекты

Внутри дочернего компонента задание запускает действие, которое обновляет задание, а затем объединяется и обновляет задания в хранилище. Кажется, что это работает нормально, но когда контейнер повторно отображает ребенка, нет. Я вижу, что это связано с тем, что я не храню работу как реквизит или состояние.

Мой вопрос - лучший способ (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); 

Редуктор Отрывок:

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

Если ничего другого, похоже, вы мутируете свое состояние с помощью строк 'jobToUpdate.status = ....'. Случайная мутация почти всегда является причиной того, что компоненты не перерисовываются. См. Http://redux.js.org/docs/FAQ.html#react-not-rerendering. Кроме того, как выглядят работы и ваше начальное состояние? – markerikson

+0

Итак, если я сменил JobShow на включение заданий = {jobs}, он повторно отображает по мере обновления заданий, но передача реквизита, который ребенок не нужен, кажется неправильным. Это, по-видимому, указывает на то, что состояние не мутирует, я также могу подтвердить, что сам контейнер повторно отображает и даже повторно запускает функцию renderView, но просто не перерисовывает JobShow. –

+0

Поиск большего кода может помочь, но ваши строки 'jobToUpdate' в фрагменте редуктора напрямую мутируют этот объект задания, а не делают копию, только изменяя копию и возвращая эту копию. Так что да, если вы пытаетесь передать этот объект задания самому дочернему компоненту в качестве опоры, сама ссылка не изменилась, а дочерний компонент не будет обновляться. – markerikson

ответ

1

Проблема, как указано в комментариях @markerikson было то, что я мутирует состояние. Используя функцию $ set из update-addons-update, я успешно обновил содержимое.

Новый редуктор фрагмент выглядит следующим образом:

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

Похоже, вы поняли это сами, но вы можете найти небольшой рефакторинг улучшает ясность того, что вы делаете. Вот некоторые примеры того, как можно изменить структуру ваших редукторов с помощью операции объекта присвойте:

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, полезный, так как он скажет ошибку, если вы случайно измените состояние, не осознавая.

Смежные вопросы