Redux状态更改后,React组件不会重新呈现

时间:2019-06-07 07:50:41

标签: javascript reactjs redux

在Redux状态下,我具有以下结构:

"equipment" : {
  "l656k75ny-r7w4mq" : {
    "id" : "l656k75ny-r7w4mq",
    "image" : "cam.png",
    "isChecked" : false,
    "list" : {
      "2taa652p5-mongp0" : {
        "id" : "2taa652p5-mongp0",
        "image" : "dst.png",
        "isChecked" : false,
        "name" : "Dst"
      },
      "y3ds1rspk-ftdg2t" : {
        "id" : "y3ds1rspk-ftdg2t",
        "image" : "flm.png",
        "isChecked" : false,
        "name" : "Flm"
      }
    },
    "name" : "EQ 1"
  },
  "lpbixy0f7-bmiwzl" : {
    "image" : "prm.png",
    "isChecked" : false,
    "list" : {
      "l40snp2y6-o7gudg" : {
        "image" : "tlp.png",
        "isChecked" : false,
        "name" : "Tlp"
      },
      "qmxf9bn3v-9x1nky" : {
        "image" : "prm.png",
        "isChecked" : false,
        "name" : "Prm"
      }
    },
    "name" : "EQ 2"
  }
}

我有一个Equipment组件(某种高阶组件),在其中我订阅了状态的这一部分,并将其数据传递给CustomExpansionPanel组件:

class Equipment extends Component {
  //...different methods
  render() {
    const { data } = this.props;

    let content = error ? <p>Oops, couldn't load equipment list...</p> : <Spinner />;

    if ( data.length > 0 ) {
      content = (
        <Fragment>
          <CustomExpansionPanel data={data}/>
        </Fragment>
      );
    }

    return (
      <SectionContainer>
        {content}
      </SectionContainer>
    );
  }
}

const mapStateToProps = state => {
  return {
    data: state.common.equipment,
  };
};

connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(Equipment));

在我的CustomExpansionPanel中,我映射接收到的数据并为每个部分创建一个扩展面板,同时将该部分传递给CustomTable组件,该组件显示为ExpansionPanelDetails内容。

class CustomExpansionPanel extends Component {
  //... different methods
  render() {
    const { data } = this.props;

    return (
      <Fragment>
        {
          data.map((section, index) => {
            return (
              <ExpansionPanel defaultExpanded={false} key={section.id} disabled={!section.hasOwnProperty('list')} >
                <ExpansionPanelSummary expandIcon={<StyledIcon classes={{root: classes.expansionIcon}} />}>
                  <Avatar
                    alt={section.name}
                    src={images('./' + section.image)}
                    classes={{root: classes.avatar}}
                  />
                  <Typography variant='body1' classes={{root: classes.summaryText}}>{section.name}</Typography>
                </ExpansionPanelSummary>
                <ExpansionPanelDetails>
                  <CustomTable data={section} imageVariant={imageVariant} parentId={section.id} />
                </ExpansionPanelDetails>
              </ExpansionPanel>
            );
          })
        }
      </Fragment>
    );
  }
}

然后在我的CustomTable组件中,映射接收到的节的list属性并显示其数据。单击该行时,我将使用适当的字段构建一个Form组件,并将其显示出来以编辑列表项对象:

class CustomTable extends Component {
  //...local state
  //...some methods
  cellClickHandler = (object, index) => {
    this.setState({
      editedObject: object,
      editedObjectIndex: index
    }, () => {
      this.setFormData(object);
    });
  };

  handleSaveClicked = data => {
    data.id = this.state.editedObject.id;
    if(this.props.parentId) {
      data.parentId = this.props.parentId;
    }
    if ( this.state.editedObject && this.state.editedObject.list ) data.list = this.state.editedObject.list;
    this.props.onSaveItemEditClicked(this.props.updatedSection, data, this.state.editItemLevel, this.state.editedObjectIndex, () => {
      this.handleDialogState();
    });
  };

  componentWillMount() {
    if ( this.props.data.list ) {
      if ( Array.isArray(this.props.data.list) ) {
        this.setState({rows: [...this.props.data]});
      } else {
        let transformedData = [];
        for (let [key, value] of Object.entries(this.props.data.list)) {
          let obj = value;
          obj['id'] = key;
          transformedData.push(obj);
        }
        this.setState({
          rows: [...transformedData],
          sortedProperties: sortProperties(Object.keys(transformedData[0]))
        });
      }
    } else if (Array.isArray(this.props.data) && this.props.data.length) {
      this.setState({
        rows: [...this.props.data],
        sortedProperties: sortProperties(Object.keys(this.props.data[0]))
      });
    }

    if (this.props.parentId) {
      this.setState({editItemLevel: 'inner'})
    }
  }

  componentWillReceiveProps(nextProps, nextContext) {
    if ( nextProps.data.list ) {
      if ( Array.isArray(nextProps.data.list) ) {
        this.setState({rows: [...nextProps.data]});
      } else {
        let transformedData = [];
        for (let [key, value] of Object.entries(nextProps.data.list)) {
          let obj = value;
          obj['id'] = key;
          transformedData.push(obj);
        }
        this.setState({
          rows: [...transformedData],
          sortedProperties: sortProperties(Object.keys(transformedData[0]))
        });
      }
    } else if (Array.isArray(nextProps.data) && nextProps.data.length) {
      this.setState({
        rows: [...nextProps.data],
        sortedProperties: sortProperties(Object.keys(nextProps.data[0]))
      });
    }
  }

  render() {
    // Table, TableHead, TableRow, TableCell, TableFooter definitions...
    <FormDialog
      open={this.state.dialogOpen}
      title={this.state.dialogTitle}
      content={this.state.dialogContentText}
      handleClose={this.handleDialogState}
      formElements={this.state.formElements}
      action={this.handleSaveClicked}
      onCancelClicked={this.handleDialogState} />
  }
}

const mapStateToProps = state => {
  return {
    updatedSection: state.control.Update.updatedSection
  };
};

const mapDispatchToProps = dispatch => {
  return {
    onSaveItemEditClicked: (updatedSection, object, level, index, callback) => dispatch(commonActions.onSaveEdit(updatedSection, object, level, index, callback))
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(CustomTable));

窗体打开,例如,我可以更改对象的名称,然后单击保存按钮,该按钮将触发onSaveItemEditClicked方法,该方法将调度onSaveEdit操作。

onSaveEdit = (updatedSection, object, level='root', index, callback) => {
    return dispatch => {
      dispatch(controlActions.onSetSnackbarMessage(SnackbarMessages.PROCESS.UPDATING + ' \'' + capitalize(object.name) + '\''));
      dispatch(controlActions.DBProcessStart());
      let parentId = null;
      let url = '/' + updatedSection + '/' + object.id;
      if (level === 'inner') {
        url = '/' + updatedSection + '/' + object.parentId + '/list/' + object.id;
        parentId = object.parentId;
        delete object.parentId;
      }
      updateData(url, object)
        .then(response => {
          dispatch(controlActions.onSetSnackbarMessage('\'' + capitalize(object.name) + '\' ' + SnackbarMessages.SUCCESS.UPDATED_SUCCESSFULLY));
          dispatch(controlActions.DBProcessSuccess());
          if (parentId) {
            object.parentId = parentId;
          }
          dispatch(this[saveEditSuccess](updatedSection, object, level, index));
          if (callback != null) {
             callback();
          }
        })
        .catch(error => {
          console.error('onSaveEdit error', error);
        });
    }
  };
  [saveEditSuccess] = (updatedSection, object, level='root', index) => {
    return {
      type: CommonCommands.UPDATE.SUCCESS,
      section: updatedSection,
      object: object,
      level: level,
      index: index
    };
  };

最后那是我的减速器:

const onUpdateSuccess = (state, action) => {
  switch (action.level) {
    case 'root':
      let section = [...state[action.section]];
      section = [
        ...section.slice(0, action.index),
        action.object,
        ...section.slice(action.index + 1),
      ];
      return updateObject(state, {
        [action.section]: section
      });
    case 'inner':
      console.log('inner update success', action);
      section = [...state[action.section]];
      let parentId = action.object.parentId;
      let subsectionIndex = state[action.section].findIndex(member => member.id === parentId);
      delete action.object.parentId;
      let updatedObject = {...section[subsectionIndex].list[action.object.id], ...action.object};
      section[subsectionIndex].list[action.object.id] = updatedObject;
      return updateObject(state, {
        [action.section]: [...section]
      });
    default:
      return state;
  }
};

这是updateObject方法:

const updateObject = (oldObject, updatedProperties) => {
  return {
    ...oldObject,
    ...updatedProperties
  };
};

现在,如果我使用Debug Redux工具检查状态,则可以在对象上看到新名称,并且看到状态确实发生了变化。但是CustomTable组件不会重新呈现,我仍然看到旧名称。

在所有其他情况下,完全相同的方法对我都有效。如果我在state属性中有一个数组或对象,并且将其显示在同一CustomTable中-我可以对其进行编辑并立即查看结果(因此我具有这些“根”和“内部”分隔)。但是在这种情况下不是。

我尝试使用Object.assign({}, state, {[action.section]:section});而不是updateObject方法,但这也无济于事。

有什么主意如何使用更改后的属性重新渲染该组件?

0 个答案:

没有答案