Javascript 以Redux状态存储数据:API对象的反射与简化表单状态
假设我的后端有一个Javascript 以Redux状态存储数据:API对象的反射与简化表单状态,javascript,reactjs,redux,react-redux,Javascript,Reactjs,Redux,React Redux,假设我的后端有一个Report模型,它有一个date属性,类型为date。React表单由两个输入组成,用于修改它:带有月份的,以及格式的日期年份的。我不在乎日期,因为我将使用矩.utc(…).endOf('month')将日期设置为所选年份中所选月份的结束日期 对于此任务,我看到两个选项: 我的Redux状态保存最终计算的日期对象,该对象将被发布到后端,或者 该状态有两个属性:month和year,然后,当报告准备发布到后端时,这两个属性将被删除并转换为日期对象 选项(2)看起来很脏,需要大量
Report
模型,它有一个date
属性,类型为date
。React表单由两个输入组成,用于修改它:带有月份的
,以及
格式的日期年份的
。我不在乎日期,因为我将使用矩.utc(…).endOf('month')
将日期设置为所选年份中所选月份的结束日期
对于此任务,我看到两个选项:
日期
对象,该对象将被发布到后端,或者month
和year
,然后,当报告
准备发布到后端时,这两个属性将被删除并转换为日期
对象报告
对象销毁为不属于后端的属性,以及在发布到服务器之前构造所需的属性
但是,选项(2)允许通过组件的onChange
和value
属性将React的组件更清晰地绑定到状态
选项(1)似乎更合理,因为Redux状态是后端状态的表示,但是我发现自己编写了很多黑客逻辑:
import React,{Component,PropTypes}来自'React';
从'react redux'导入{connect};
从“力矩”中导入力矩;
从“../actions”导入{reportChange};
常量月=[“一月”、“二月”、“三月”、“四月”、“五月”、“六月”、“七月”、“八月”、“九月”、“十月”、“十一月”、“十二月”];
类报表扩展组件{
建造师(道具){
超级(道具);
this.handleMonthChange=this.handleMonthChange.bind(this);
}
handleMonthChange(事件){
const{dispatch,report}=this.props,
{target:{value}}=event,
日期=utc时刻(报告日期),
年份=this.yearInput.value,
月份=价值;
日期。月。年。结束(‘月’);
调度(报告更改)({
日期:date.toDate()
}));
}
render(){
const{report}=this.props;
返回(
{months.map((月,索引)=>({month}))}
this.yearInput=input}//非受控组件
/>
);
}
静态类型={
调度:需要PropTypes.func.isRequired,
报告:PropTypes.object.isRequired
}
}
常量mapStateToProps=状态=>({
报告:state.report
});
导出默认连接(MapStateTops)(报告);
这是一个简短的版本,删除了所有不必要的内容。现在,正如您所看到的,我使用了一个for the year输入。这是因为如果我通过value={moment.utc(Report.date).format('YYYY')}
和onChange
属性将其绑定到Redux存储中Report
对象中的原始date
属性,则组件将始终绑定到该YYYY
格式,因此,您无法删除任何数字-当您点击backspace从2017
中删除7
时,它会自动更新为0201
,而不是201
此外,由于这是一个不受控制的组件,我必须在所有重要事件中手动提取它的值,例如表单
的onSubmit
事件处理程序,以便在提交正确的日期之前更新报表对象,等等
我觉得我错过了什么,应该有更简单的方法。非常感谢您的任何帮助或建议
选项(1)似乎更合理,因为Redux状态是后端状态的表示
我会争辩。Redux状态应该表示应用程序的状态(不管它是什么,包括未存储在后端的UI状态)。所以,选择(2)是一条路要走。此外,它使组件可重用,因为它们不依赖于后端数据格式
选项(1)似乎更合理,因为Redux状态是后端状态的表示
我会争辩。Redux状态应该表示应用程序的状态(不管它是什么,包括未存储在后端的UI状态)。所以,选择(2)是一条路要走。此外,它使组件可重用,因为它们不依赖于后端数据格式。我强烈不同意组件状态应该紧密映射相关的
Redux
(Flux
,无论哪个)状态的观点。将视图逻辑与域逻辑混合在一起总是会导致这种复杂性
几乎总是在视图代码中使用便于查看逻辑的数据格式,在域逻辑代码中使用另一种数据格式。并实现必要的桥接代码,以将一个代码转换为另一个代码(具有适当的验证等)<您当前使用的code>react-redux为这种转换提供了两个位置:MapStateTrops
和mapDispatchToProps
如果您让您的视图代码(React组件)拥有自己的生命和自己的状态,您将解决您提到的另一种复杂问题,即与不需要的年份字段更新作斗争
我修复了您的代码,使其看起来像我描述的那样,但是请注意,实际上我没有运行它,因此可能需要一些修复:
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
import { reportChange } from '../actions';
const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ];
class Report extends Component {
constructor(props) {
super(props);
this.state = { month: props.month, year: props.year };
}
componentWillReceiveProps(nextProps) {
this.setState({ month: nextProps.month });
}
handleMonthChange(month) {
this.setState({ month });
props.onChange(month, this.state.year);
}
handleYearChange(year) {
this.setState({ year });
props.onChange(this.state.month, year);
}
render() {
return (
<div>
<select
name="month"
value={this.state.month}
onChange={e => this.handleMonthChange(e.target.value)}
>
{months.map((month, index) => (<option key={index} value={index + 1}>{month}</option>))}
</select>
<input
name="year"
type="text"
value={this.state.year}
onChange={e => handleYearChange(e.target.value)}
/>
</div>
);
}
static propTypes = {
onChange: PropTypes.func.isRequired,
month: PropTypes.string.isRequired,
year: PropTypes.string.isRequierd,
}
}
const mapStateToProps = state => {
const date = state.report.date;
return {
month: moment.utc(date).format('M'),
year: moment.utc(date).format('YYYY'),
};
});
const mapDispatchToProps = dispatch => ({
onChange: (month, year) => {
const date = date.month(month).year(year).endOf('month').toDate();
dispatch(reportChange({ date })),
},
});
export default connect(mapStateToProps, mapDispatchToProps)(Report);
import React,{Component,PropTypes}来自'React';
从'react redux'导入{connect};
从“力矩”中导入力矩;
从“../actions”导入{reportChange};
常量月=[“一月”、“二月”、“三月”、“四月”、“五月”、“六月”、“七月”、“八月”、“九月”、“十月”、“十一月”、“十二月”];
类报表扩展组件{
建造师(道具){
超级(道具);
this.state={month:props.month,year:props.year};
}
组件将接收道具(下一步){
this.setState({month:nextProps.month});
}
手月琴
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
import { reportChange } from '../actions';
const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ];
class Report extends Component {
constructor(props) {
super(props);
this.state = { month: props.month, year: props.year };
}
componentWillReceiveProps(nextProps) {
this.setState({ month: nextProps.month });
}
handleMonthChange(month) {
this.setState({ month });
props.onChange(month, this.state.year);
}
handleYearChange(year) {
this.setState({ year });
props.onChange(this.state.month, year);
}
render() {
return (
<div>
<select
name="month"
value={this.state.month}
onChange={e => this.handleMonthChange(e.target.value)}
>
{months.map((month, index) => (<option key={index} value={index + 1}>{month}</option>))}
</select>
<input
name="year"
type="text"
value={this.state.year}
onChange={e => handleYearChange(e.target.value)}
/>
</div>
);
}
static propTypes = {
onChange: PropTypes.func.isRequired,
month: PropTypes.string.isRequired,
year: PropTypes.string.isRequierd,
}
}
const mapStateToProps = state => {
const date = state.report.date;
return {
month: moment.utc(date).format('M'),
year: moment.utc(date).format('YYYY'),
};
});
const mapDispatchToProps = dispatch => ({
onChange: (month, year) => {
const date = date.month(month).year(year).endOf('month').toDate();
dispatch(reportChange({ date })),
},
});
export default connect(mapStateToProps, mapDispatchToProps)(Report);