简体   繁体   English

即使将更新的值从父级传递给子级,也不会呈现子级

[英]Even after passing updated value from parent to child, child is not rendered

In the parent component, I receive data from the server and then map this data into a jsx format. 在父组件中,我从服务器接收数据,然后将此数据映射为jsx格式。 Inside this mapping I have a child component and try to pass a value from state of parent to child as a property, however when I update state of this value, the render function for child is not executed. 在此映射内部,我有一个子组件,并尝试将值从父状态传递给子状态作为属性,但是,当我更新此值的状态时,不会执行子项的渲染功能。

Expected behavior: As a user I see a list of items. 预期的行为:作为用户,我看到一个项目列表。 If I click on an item it should become as checked. 如果我单击某个项目,则它应变为选中状态。

export class ReactSample extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      items: [],
      mappedItems: [],
      selectedIds: [],
      isSelected: false,
      clickedTripId: null
    };

    this.toggleSelection = this.toggleSelection.bind(this);
  }

  componentWillMount(){
    console.log("Component mounting")
  }

  toggleSelection (id, e) {
    if(!_.includes(this.state.selectedIds, id)) {
      this.setState((state) => ({selectedIds: 
state.selectedIds.concat(id)}));
      this.setState(() => ({clickedTripId: id}));
      this.mapItems(this.state.items);
    }
  }

  componentDidMount() {
    const self = this;
    MyService.getItems()
      .then(res => {
        self.setState(() => ({ items: res.allItems }));
        self.setState(() => ({ mappedItems: 
this.mapItems(res.allItems) }));
      }
    )
  }

  mapItems (items) {
return items.map(trip => {
  return (
    <li key={trip.id} onClick={(e) => (this.toggleSelection(trip.id, 
e))}>
      <span>{trip.title}</span>
      <Tick ticked={this.state.clickedTripId}/>
      <span className="close-item"></span>
    </li>
  );
});
  }

  getItems() {

  }

  render() {
    return (
      <div>
        <a className="title">This is a react component!</a>
        <Spinner showSpinner={this.state.items.length <= 0}/>
        <div className="items-container">
          <ul id="itemsList">
            {this.state.mappedItems}
          </ul>
        </div>
      </div>
    );
  }
}


export class Tick extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    console.log('RENDER');
    return (<span className={this.props.ticked ? 'tick display' : 
'tick hide' }></span>);
  }
}

I see a couple issues. 我看到几个问题。

In toggleSelection you aren't doing anything with the result of mapItems. toggleSelection您不会对mapItems的结果做任何事情。 This kind of bug would be much easier to avoid if you just remove mappedItems from state and instead just call mapItems within your render method. 如果您mappedItems状态中删除mappedItems ,而只是在render方法中调用mapItems ,则可以避免这种错误。

The other issue is you are passing this.state.clickedTripId as the ticked property. 另一个问题是您正在传递this.state.clickedTripId作为已ticked属性。 I assume you meant to pass something more like this.state.clickedTripId === trip.id . 我假设您打算传递类似this.state.clickedTripId === trip.id

As Ryan already said, the problem was that mappedItems where not updated when toggleSelection was clicked. 莱恩已经说了,问题是, mappedItems在哪里都不更新toggleSelection被点击。 As it is obvious from the code mapItems returns data in jsx format. 从代码中可以明显mapItems ,mapItems以jsx格式返回数据。 To update it I had to call this.setState({mappedItems: this.mapItems(this.state.items)}) which means that I call mapItems and then I assign the result to the state. 要对其进行更新,我必须调用this.setState({mappedItems: this.mapItems(this.state.items)}) ,这意味着我调用了mapItems ,然后将结果分配给该状态。 In this case my list will be updated and Tick component will receive this.state.clickedItemId as a tick property. 在这种情况下,我的列表将被更新, Tick组件将收到this.state.clickedItemId作为tick属性。 There is one more issue that needs to be done to make this code working: this mapped list needs to be updated after this.state.clickedItemId is updated. 要使此代码正常工作,还需要解决另一个问题:在this.state.clickedItemId更新后,需要更新此映射列表。 The method setState is asynchronous which means that this.setState({mappedItems: this.mapItems(this.state.items)}) has to be called only after this.state.clickedItemId is updated. setState方法是异步的,这意味着仅在this.state.clickedItemId更新之后this.state.clickedItemId必须调用this.setState({mappedItems: this.mapItems(this.state.items)}) To achieve this, the setState method can receive a callback function as a second parameter. 为此, setState方法可以接收回调函数作为第二个参数。 The code snippet is the following: 代码段如下:

toggleSelection (id, e) {
  if(!_.includes(this.state.selectedIds, id)) {
    this.setState((state) => ({
      clickedItemId: id,
      selectedIds: state.selectedIds.concat(id)
    }), () => this.setState({mappedItems: this.mapItems(this.state.items)}));
  }
}

In this case, at the time the mapItems function is executed all data from the state that is needed here will be already updated: 在这种情况下,在执行mapItems函数时,来自此处所需状态的所有数据都将已更新:

mapItems (items) {
  return items.map(item => {
    return (
      <li key={item.id} onClick={(e) => (this.toggleSelection(item.id, e))}>
        <span>{item.title}</span>
        <span>{this.state.clickedItemId}</span>
        <Tick ticked={this.state.clickedItemId === item.id}/>
        <span className="close-item"></span>
      </li>
    );
  });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM