2016-08-03 51 views
0

我试图仅显示从状态映射到我的容器组件(使用mapStateToProps)的状态的查询数组的一段。未捕获的不变违规:在调度之间检测到状态突变,

为此,我使用spread运算符Array.slice,然后遍历子数组以创建组件。在我的应用程序中,我可以成功地显示完整数组的段和子页面,但是每当我触发一个操作来洗牌或替换数组中的元素时,我总是会在将适当的操作分配给我减速器:

未捕获不变冲突:分派之间检测到状态突变,>在路径querys.0.submit_time._isValid。这可能导致不正确的行为。

我只在第一次点击时出现此错误。如果我显示整个数组,这个错误也不会发生。在这个数组中,每个元素(一个查询)有一个时刻1属性。上面的错误是在应用程序上没有显示的第一个元素上引发的(在这种情况下,查询0被跳过了,如果我显示查询0-9,那么错误将会是查询10)。由于submit_time被认为是变异的,我用moment.clone()来深层复制它,但仍然出错。有谁知道如何显示数组切片并避免此错误?


编辑:

这里是我的部件,操作和减速器的简化代码。我的组件最初是从redux商店通过querys作为道具。然后它将这个数组的一部分传递给一个为每个元素创建一个tr的子组件(通过迭代)。在应用程序中,您可以通过切换单选按钮来触发onSortChange事件处理程序。这会触发SORT_QUERIES_BY_FIELD操作,这会导致queryReducer使用List.sort对数组进行排序。当我触发首次和右onSortChange行动SORT_QUERIES_BY_FIELD动作被派遣之前出现的错误:

组件:

import React, {PropTypes} from 'react'; 
    import {connect} from 'react-redux'; 
    import {bindActionCreators} from 'redux'; 
    import moment from 'moment'; 
    import * as queryActions from '../../actions/queryActions'; 
    import QueryList from './QueryList'; 
    import RadioGroup from 'react-radio'; 

    class TroubleshootPage extends React.Component { 
     constructor(props, context) { 
     super(props, context); 
     this.onSortChange = this.onSortChange.bind(this); 
     this.state = {querys: [...this.props.querys]}; 
     } 
     componentWillReceiveProps(nextProps) { 
     this.setState({querys: nextProps.querys}); 
     } 
     onSortChange(value, event) { 
     this.props.actions.sortQueriesByField(value); 
     } 

     render() { 
     const {querys, radioGroupValue} = this.state; 
     let subList = [...querys].slice(0,9); 
     return (
      <div> 
      <RadioGroup name="sorts" defaultValue={null} onChange={this.onSortChange.bind(this)}> 
      <input type="radio" value="total_elapsed_time" />Elapsed Time 
      </RadioGroup> 
      <QueryList selectedQuery={this.selectedQuery} 
         selectedQueryStep={this.selectedQueryStep} 
         querys={subList} /> 
      </div> 
     ); 
     } 
    } 
    TroubleshootPage.propTypes = { 
     querys: PropTypes.array.isRequired, 
     actions: PropTypes.object.isRequired 
    }; 
    function mapStateToProps(state, ownProps) { 
     return {querys: state.querys}; 
    } 
    function mapDispatchToProps(dispatch) { 
     return {actions: bindActionCreators(queryActions, dispatch)}; 
    } 
    export default connect(mapStateToProps, mapDispatchToProp)(TroubleshootPage); 

操作:

import * as types from './actionTypes'; 
    import queryApi from '../api/mockQueryApi'; 

    export function sortQueriesByField(field) { 
     return { type: types.SORT_QUERIES_BY_FIELD, field}; 
    } 

减速机:

import * as types from '../actions/actionTypes'; 
    import initialState from './initialState'; 

    export default function queryReducer(state = initialState.querys, action) { 
     switch(action.type) { 
     case types.SORT_QUERIES_BY_FIELD: 
      let {field} = action; 
      var querys = [...state]; 
      querys.sort(function(a,b) {return a[field]-b[field]}) 
      return querys; 

     default: 
      return state; 
     } 
    } 
+0

请张贴您的减速器,动作,mapStateToProps的一些代码... – Majky

回答

0

我有同样的问题,但最终得到它的工作时,我crea在我的课程外面添加一个变量并更新变量和状态。这是代码。这是非常敏感的,我知道这是一种反模式,但它的工作原理!

import React, {PropTypes} from 'react'; 
import {connect} from 'react-redux'; 
import { Row, Col } from 'react-bootstrap'; 
import {bindActionCreators} from 'redux'; 
import DatePicker from 'react-datepicker'; 
import * as actions from '../actions/checkoutActions'; 
import moment from 'moment'; 

import 'react-datepicker/dist/react-datepicker.css'; 

let date = moment(); 

class AppointmentPage extends React.Component{ 
    constructor(props, context){ 
    super(props, context); 
    this.createAppt = this.createAppt.bind(this); 
    this.updateDate = this.updateDate.bind(this); 
    this.updateTime = this.updateTime.bind(this); 
    this.printTimeRange = this.printTimeRange.bind(this); 
    } 

    printTimeRange(appt){ 
    let active = ""; 
    if(this.props.apptTime === appt) 
     active = "active"; 
    return (
     <li key={appt} className={"list-group-item appt-item "+active} id={"time_"+appt} onClick={this.updateTime}> 
     {moment(appt+":00", ["H:mm"]).format("h:mm A")+' - '+moment((appt+1)+":00", ["H:mm"]).format("h:mm A")} 
     </li> 
    ); 
    } 


    updateDate(apptDate){ 
    date = apptDate; 
    return this.setState({apptDate}); 
    } 

    updateTime(e){ 
    const id = Number(e.target.id.substring(5)); 
    this.props.actions.updateTime(id); 
    } 

    createAppt(e){ 
    e.preventDefault(); 
    this.props.actions.createAppt(); 
    } 

    render(){ 
    return (
     <Row> 
     <Col md={2}/> 
     <Col md={8}> 
      <h2> 
      Schedule An Appointment 
      <button className="btn btn-primary pull-right" onClick={this.createAppt}>Make Appointment</button> 
      </h2><hr/> 
      <Row> 
      <Col md={6}> 
       <DatePicker inline 
       selected={date} 
       onChange={this.updateDate} /> 
      </Col> 
      <Col md={6}> 
       <ul className="list-group"> 
       {this.props.appointments && this.props.appointments.map(this.printTimeRange)} 
       </ul> 
      </Col> 
      </Row> 
     </Col> 
     </Row> 
    ); 
    } 
} 

AppointmentPage.propTypes = { 
    actions: PropTypes.object.isRequired, 
    user: PropTypes.object.isRequired, 
    appointments: PropTypes.array, 
    apptTime: PropTypes.number 
}; 

export default connect(
    (s)=>{return { 
    user:s.user, 
    appointments:s.checkout.appointments, 
    apptTime: s.checkout.apptTime 
    };}, 
    d=>{return {actions:bindActionCreators(actions,d)};} 
)(AppointmentPage); 
0

我以前有同样的问题,在我的情况下,这是由浅拷贝引起的。每当我返回一个新的状态时,旧状态也会改变。

我使用了一个棘手的方法,通过执行JSON.parse(JSON.stringify(temp))来创建一个深度克隆。

你也可以尝试var querys = JSON.parse(JSON.stringify(state));

希望它有效。

相关问题