【问题标题】:Even after passing updated value from parent to child, child is not rendered即使将更新的值从父级传递给子级后,子级也不会呈现
【发布时间】:2018-12-27 14:17:57
【问题描述】:

在父组件中,我从服务器接收数据,然后将这些数据映射成 jsx 格式。在此映射中,我有一个子组件,并尝试将值从父状态传递给子组件作为属性,但是当我更新此值的状态时,不会执行子组件的渲染函数。

预期行为:作为用户,我看到一个项目列表。如果我点击一个项目,它应该成为选中状态。

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>);
  }
}

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    我发现了几个问题。

    toggleSelection 中,您没有对mapItems 的结果做任何事情。如果你只是从状态中删除mappedItems,而只是在你的渲染方法中调用mapItems,这种错误会更容易避免。

    另一个问题是您将this.state.clickedTripId 作为ticked 属性传递。我假设您打算传递更像this.state.clickedTripId === trip.id 的东西。

    【讨论】:

    • 感谢 Ryan 的重播。最初,我在渲染函数中完成了映射,但后来我从官方文档中读到 render 函数应该尽可能保持清洁。这就是我将“映射”移到另一个地方的原因。但是你是对的,我对映射的项目什么都不做。我的地图类函数返回一个结果,我必须在 toggleSelection 函数中调用地图函数时调用 setState 才能更新 mappedItems
    【解决方案2】:

    正如 Ryan 已经说过的,问题在于 mappedItems 在单击 toggleSelection 时未更新。从代码中可以明显看出,mapItems 返回 jsx 格式的数据。要更新它,我必须调用this.setState({mappedItems: this.mapItems(this.state.items)}),这意味着我调用mapItems,然后将结果分配给状态。在这种情况下,我的列表将被更新,Tick 组件将接收this.state.clickedItemId 作为tick 属性。要使此代码正常工作,还需要解决一个问题: 这个映射列表需要在this.state.clickedItemId 更新后更新。方法setState 是异步的,这意味着只有在更新this.state.clickedItemId 之后才必须调用this.setState({mappedItems: this.mapItems(this.state.items)})。为此,setState 方法可以接收回调函数作为第二个参数。代码sn-p如下:

    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)}));
      }
    }
    

    在这种情况下,在执行 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>
        );
      });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-04
      • 1970-01-01
      • 2018-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多