Когда я изменяю данные для объекта бюджета в моем хранилище редукта, компоненты, ответственные за визуализацию этого объекта, рендеринг компонента при изменении данных.Родительский компонент подключен к хранилищу 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 />
к магазину и слушать песни здесь?
Или есть лучший подход к тому, что я пытаюсь сделать?
Благодарим за помощь!
Я приехал сюда, потому что у меня такая же проблема (или, по крайней мере, симптом). Я ожидал, что ваш бюджет соединится сам по себе, но это то, что я делаю.Ваш подключенный компонент подключается к 'state.departmentBudgets.budgets', но я не вижу' departmentBudgets' в вашем состоянии, поэтому кажется, что он должен ассоциироваться с 'state.budgets'. – Josh