Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/464.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 以Redux状态存储数据:API对象的反射与简化表单状态_Javascript_Reactjs_Redux_React Redux - Fatal编程技术网

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')
将日期设置为所选年份中所选月份的结束日期

对于此任务,我看到两个选项:

  • 我的Redux状态保存最终计算的
    日期
    对象,该对象将被发布到后端,或者
  • 该状态有两个属性:
    month
    year
    ,然后,当
    报告
    准备发布到后端时,这两个属性将被删除并转换为
    日期
    对象
  • 选项(2)看起来很脏,需要大量的预处理:将收到的
    报告
    对象销毁为不属于后端的属性,以及在发布到服务器之前构造所需的属性

    但是,选项(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);