2015-11-29 13 views
3

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

У меня есть компонент <Budget />, который отображает объект бюджета, содержащийся в массиве объектов бюджета, которые являются частью моего состояния/хранилища. Мой магазин имеет следующую форму:

departmentBudgets : { 
    isFetching : false, 
    budgets : [ { 
     department : 'String', 
     owner  : { 
      name : 'String', 
      email : 'String', 
      title : 'String' 
     }, 
     budget  : 'Number' 
    } ] 
} 

Я хотел бы <Budget /> компонента для повторной визуализации и обновить отображение объекта бюджета, когда один из его свойств редактируются. Функциональность, над которой я работаю, позволяет пользователю редактировать и обновлять свойство бюджета. Мой редуктор redux выглядит следующим образом:

import * as types from '../constants/actionTypes'; 
import union from 'lodash/array/union'; 
import uniq from 'lodash/array/uniq'; 

const initialState = { 
    isFetching : false, 
    budgets : [] 
}; 

export default function budgets(state = initialState, action = {}) { 
    const { type, payload, meta } = action; 

    switch (type) { 
     case types.FETCH_CURRENT_BUDGETS: 
      return Object.assign({}, state, { 
       isFetching : true 
      }); 
     case types.RECEIVE_CURRENT_BUDGETS: 
      return Object.assign({}, state, { 
       isFetching : false, 
       budgets : uniq(union(state.budgets, payload), '_id') 
      }); 
     case types.UPDATE_DEPARTMENT_BUDGET: 
      const changedIndex = state.budgets.findIndex((budget) => { 
       return budget._id === payload._id; 
      }); 
      const newBudgets = [ ...state.budgets.slice(0, changedIndex), 
       Object.assign({}, state.budgets[ changedIndex ], { 
        budget : payload.budget 
       }), 
       ...state.budgets.slice(changedIndex + 1) ]; 
      return Object.assign({}, state, { 
       budgets : newBudgets 
      }); 
     default: 
      return state; 
    } 
} 

Я правильно обрабатываю обновление в редукторе выше? Я считаю, что это не мутирует объект государства, но, может быть, нет?

Мои реагировать дерево компонентов выглядит следующим образом, чтобы сделать эти данные:

DepartmentBudgetsContainer 
    DepartmentBudgets 
    Budget 

Элемент контейнера захватывает текущие данные из базы данных и связывает его в магазин с среагировать-Redux и выглядит следующим образом:

import React, { Component, PropTypes } from 'react'; 
import { connect } from 'react-redux'; 
import { fetchBudgets, updateBudget } from '../../actions/departmentBudget.actions'; 
import DepartmentBudgets from '../../components/administration/department_budgets/DepartmentBudgets'; 

const displayName = 'DepartmentBudgetContainer'; 
const propTypes = { 
    budgets : PropTypes.object 
}; 

class DepartmentBudgetContainer extends Component { 
    constructor(props, context) { 
     super(props, context); 
     this.budgetDidchange = this.budgetDidchange.bind(this); 
    } 

    componentDidMount() { 
     let { dispatch } = this.props; 
     dispatch(fetchBudgets()); 
    } 

    budgetDidchange(id, budget) { 
     let { dispatch } = this.props; 
     const newBudget = { 
      _id : id, 
      budget : budget 
     }; 
     dispatch(updateBudget(newBudget)); 
    } 

    render() { 
     const { budgets } = this.props; 
     return (
      <DepartmentBudgets updateBudget={this.budgetDidchange} budgets={budgets.budgets} /> 
     ); 
    } 
} 

DepartmentBudgetContainer.displayName = displayName; 
DepartmentBudgetContainer.propTypes = propTypes; 

function mapStateToProps(state) { 
    return { 
     budgets : state.departmentBudgets.budgets 
    } 
} 

export default connect(mapStateToProps)(DepartmentBudgetContainer); 

и то компонент DepartmentBudgets отвечает за создание каждого из компонентов бюджета и выглядит следующим образом:

import React, { Component, PropTypes } from 'react'; 
import TableComps from '../../../../node_modules/material-ui/lib/table'; 
import Budget from './Budget'; 

const Table = TableComps.Table; 
const TableHeader = TableComps.TableHeader; 
const TableRow = TableComps.TableRow; 
const TableHeaderColumn = TableComps.TableHeaderColumn; 
const TableBody = TableComps.TableBody; 
const TableRowColumn = TableComps.TableRowColumn; 

const displayName = 'DepartmentBudgets'; 
const propTypes = { 
    budgets  : PropTypes.arrayOf(PropTypes.object).isRequired, 
    updateBudget : PropTypes.func.isRequired 
}; 

export default class DepartmentBudgets extends Component { 
    constructor(props) { 
     super(props);  
    } 

    render() { 
     const { budgets, updateBudget } = this.props; 

     const budgetsElements = budgets.map((budget) => { 
      return <Budget updateBudget={updateBudget} key={budget._id} budget={budget} /> 
     }); 

     return (
      <Table> 
       <TableHeader adjustForCheckbox={false} 
          displaySelectAll={false}> 
        <TableRow onCellClick={this.handleCellClick}> 
         <TableHeaderColumn>Department</TableHeaderColumn> 
         <TableHeaderColumn>Budget</TableHeaderColumn> 
         <TableHeaderColumn>Owner</TableHeaderColumn> 
        </TableRow> 
       </TableHeader> 
       <TableBody stripedRows={false}> 
        {budgetsElements} 
       </TableBody> 
      </Table> 
     ); 
    } 
} 

DepartmentBudgets.displayName = displayName; 
DepartmentBudgets.propTypes = propTypes; 

Наконец, компонент бюджета отвечает за предоставление фактического бюджета. Я также хотел включить возможность редактирования бюджета в строке, какие функции включены в этот компонент. Однако, когда я изменить бюджет, компонент повторно не рендеринг:

import React, { Component, PropTypes } from 'react'; 
import Table from '../../../../node_modules/material-ui/lib/table'; 
import numeral from 'numeral'; 
import InlineEdit from 'react-edit-inline'; 

const TableRow = Table.TableRow; 
const TableRowColumn = Table.TableRowColumn; 

const displayName = 'Budget'; 
const propTypes = { 
    budget  : PropTypes.object.isRequired 
}; 

export default class Budget extends Component { 
    constructor(props, context) { 
     super(props, context); 
     console.log('Budget this:', this.props); 
     this.handleBudgetChange = this.handleBudgetChange.bind(this); 
    } 

    validateBudget(num) { 
     return (Number(num) > 0 && Number(num) < 100 && !Number.isNaN(num)); 
    } 

    handleBudgetChange(num) { 
     const inputNum = Number(num.budget) > 1 ? Number(num.budget)/100 : Number(num.budget); 
     const budgetId = this.props.budget._id; 
     this.props.updateBudget(budgetId, inputNum); 
    } 

    render() { 
     const cellStyle = { 
      textAlign : 'center' 
     }; 
     const editCellStyle = { 
      cursor   : 'pointer', 
      textDecoration : 'underline' 
     }; 
     const { department, owner, budget } = this.props.budget; 
     const editControl = (
      <InlineEdit 
       validate={this.validateBudget} 
       change={this.handleBudgetChange} 
       text={numeral(this.props.budget.budget).format('0.0%')} 
       paramName="budget" 
       activeClassName="editing" 
      /> 
     ); 

     return (
      <TableRow style={cellStyle} 
         displayBorder={false}> 
       <TableRowColumn>{department}</TableRowColumn> 
       <TableRowColumn style={editCellStyle}>{editControl}</TableRowColumn> 
       <TableRowColumn>{owner.name}</TableRowColumn> 
       <TableRowColumn style={editCellStyle}>Edit</TableRowColumn> 
      </TableRow> 
     ); 
    } 
} 

Budget.displayName = displayName; 
Budget.propTypes = propTypes; 

Когда я редактирую бюджет в линии, изменяется значение для государства, но компонент повторно не делает его.

Следует ли подключать компонент <Budget /> к магазину и слушать песни здесь?

Или есть лучший подход к тому, что я пытаюсь сделать?

Благодарим за помощь!

+0

Я приехал сюда, потому что у меня такая же проблема (или, по крайней мере, симптом). Я ожидал, что ваш бюджет соединится сам по себе, но это то, что я делаю.Ваш подключенный компонент подключается к 'state.departmentBudgets.budgets', но я не вижу' departmentBudgets' в вашем состоянии, поэтому кажется, что он должен ассоциироваться с 'state.budgets'. – Josh

ответ

2

С кратким взглядом, это просто, что вы не передаете правую опору до вашего детского компонента? Для вашего департаментаBudgets в контейнере, следует ли сопоставлять бюджеты только с «бюджетами», а не с «budgetgets.budgets»?

0

Вы уверены, что this.props.updateBudget(budgetId, inputNum); правильно выполняет функцию родительского компонента? Когда он будет передан из контейнера, вы захотите сделать что-то вроде <DepartmentBudgets updateBudget={this.budgetDidchange.bind(this)} ... />. Я не верю, что привязка конструктора компенсирует это, но вы всегда можете бросить console.log("test") в функцию, чтобы увидеть, является ли проблема самой функцией и не имеет ничего общего с Redux.

См: https://facebook.github.io/react/tips/communicate-between-components.html

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