更新子组件的状态后如何调用父组件的setState方法?

时间:2018-08-10 11:08:46

标签: reactjs

我有一个带有子组件的组件。子组件具有许多复选框。每个复选框的onClick都将复选框的状态设置为true,并且整个组件都会更新。每次单击checkbox时,我都需要在父组件中选中复选框的标签,以便将函数从Parent传递给子组件。在componentDidUpdate()中,当我调用从父级通过props传递的函数时,它可以很好地工作。此刻,我获得了子组件的更新状态,即选中的复选框的标签,并且可以通过console.log看到它们。但是,如果我不是使用console.log(),而是使用setState({SelectedLabels:selected}),它将进入无限循环,并在几分钟后显示错误:超出最大限制。我搜了很多。 React文档指出,您不得在setState(),componentWillUpdate甚至componentDidUpdate()中调用shouldComponentUpdate()。有人可以告诉我该在哪里使用吗? 这是我的代码:

父组件:

    class BuildingsModal extends React.Component {
  state = {
    open: false,
    breadcrumbEntries: [{ title: "World" }],
    disabled: true
  };

  handleClickOpen = () => {
    this.setState({ open: true });
  };

  handleClose = () => {
    this.setState({ open: false });
  };
// This is my function that goes to child to get run after child gets updated so the received array can be used to set the disabled state of this component. If I do not call setState of this component and only console.log() function, it work fine. There is an issue with the state update. Please help!! 
  handleSelectedItems = selectedArray => {
    selectedArray.length > 0 && this.setState({disabled:false});
      console.log(
        "SelectedArray:",
        selectedArray,
        "disabled",
        this.state.disabled
      );
  };

  render() {
    const { fullScreen } = this.props;
    const { open, breadcrumbEntries, disabled } = this.state;
    return (
      <div>
        <PageHeader
          title="Dashboard"
          subtitle="33 Irving Place, New York, NY 10003"
          icon
          onClick={this.handleClickOpen}
        />
        <Dialog
          open={open}
          onClose={this.handleClose}
          scroll="body"
          fullScreen={fullScreen}
          maxWidth="sm"
          PaperProps={{
            style: {
              paddingLeft: 77.5,
              paddingRight: 77.5,
              paddingTop: 20,
              paddingBottom: 44,
              borderRadius: 23
            }
          }}
        >
          <DialogHeader>
            <Title>33 Irving Place</Title>
            <DialogActions>
              <LinkButton onClick={this.handleClose} type="danger">
                Cancel
              </LinkButton>
              <LinkButton onClick={this.handleClose} type="success">
                Save
              </LinkButton>
              <LinkButton onClick={this.handleNext} disabled={disabled}>
                Next
              </LinkButton>
            </DialogActions>
          </DialogHeader>
          <ContentWrapper>
            <Breadcrumb
              entries={breadcrumbEntries}
              getIndex={index => console.log("index is: ", index)}
            />
            <Content type="world" getSelectedItems={this.handleSelectedItems} />
          </ContentWrapper>
        </Dialog>
      </div>
    );
  }
}

export default BuildingsModal;

子组件:

class Contents extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null,
      checkedItems: new Map(),
      filteredItems: []
    };
    this.handleChange = this.handleChange.bind(this);
  }

  componentDidUpdate() {
    var filteredItems = [];
    const filterItems = (value, key, map) => {
      value === true && filteredItems.push(key);
    };
    this.state.checkedItems.forEach(filterItems);
    this.props.getSelectedItems(filteredItems);
  }

  getWorldData() {
    this.setState({
      data: [
        "United State",
        "United Kingdom",
        "China",
        "Korea",
        "Japan",
        "Pakistan",
        "India",
        "Bangladesh"
      ]
    });
  }

  getCountryData() {
    this.setState({
      data: [
        "New York",
        "Los Angeles",
        "Chicago",
        "Houston",
        "Phoenix",
        "Philadilphia",
        "Dallas",
        "Reno"
      ]
    });
  }

  getBuildingData() {
    this.setState({
      data: [
        "33 Irving Place",
        "22 Irving Place",
        "11 Irving Place",
        "3344 Irving Place",
        "44 Irving Place",
        "77 Irving Place",
        "55 Irving Place",
        "66 Irving Place"
      ]
    });
  }

  componentDidMount() {
    const { type } = this.props;
    type === "world"
      ? this.getWorldData()
      : type === "country"
        ? this.getCountryData()
        : type === "building"
          ? this.getBuildingData()
          : alert("No Data to show");
  }

  handleChange(e) {
    const label = e.target.value;
    const isChecked = e.target.checked;
    this.setState(prevState => ({
      checkedItems: prevState.checkedItems.set(label, isChecked)
    }));
  }
  render() {
    const {
      data,
      checkedItems
    } = this.state;
    return (
      <Content type={data === null ? "progress" : null}>
        {data === null ? (
          <ActivityIndicator size={100} />
        ) : (
          <FlexColumn>
            {data.map(item => (
              <Label
                control={
                  <Checkbox
                    checked={checkedItems.get(item)}
                    value={item}
                    color="default"
                    onChange={this.handleChange}
                  />
                }
                label={item}
                key={item}
              />
            ))}
          </FlexColumn>
        )}
      </Content>
    );
  }
}

export default Contents;

可能有些人建议我,为什么需要在componentDidUpdate()中而不是在handleChange(e)中调用来自prop的函数。 回答:当我设置子组件的State时,它不会立即更新,因此无法通过props传递具有更新状态的函数。我需要通过此功能发送更新的状态。帮帮我吧!

1 个答案:

答案 0 :(得分:0)

在您的职能中:

handleChange(e) {
    const label = e.target.value;
    const isChecked = e.target.checked;
    this.setState(prevState => ({
      checkedItems: prevState.checkedItems.set(label, isChecked)
    }));
  }

尝试调用传入的prop函数:

handleChange(e) {
const { getSelectedItem } = this.props;
    const label = e.target.value;
    const isChecked = e.target.checked;
    getSelectedItems(label, isChecked);
  }

您的子组件应该是“无状态”或“ PureComponent”,并且本质上应该没有逻辑或状态限制。您可以通过使用props,redux,Mobx等或新的上下文API提供程序/消费者技术来传递所有内容。我鼓励您使用Google中的某些条款。

*键从上面共享的链接中删除*

React应用程序中任何更改的数据都应该有一个“真相来源”。通常,首先将状态添加到需要呈现的组件。然后,如果其他组件也需要它,则可以将其提升到最接近的共同祖先。与其尝试在不同组件之间同步状态,不如依靠自上而下的数据流。