从父节点更新孩子的道具

时间:2018-08-05 17:03:23

标签: javascript reactjs

我正在尝试为具有不同布尔属性的一组组件(例如DropDown菜单)实现过滤器。

最初我的所有组件都被渲染,但是,当我在过滤器上进行选择时,我只想渲染与所做选择相关的组件。 为此,我认为我应该有一个由我的组件填充的数组和一个容器,只有在组件挂载后,容器才会与该方法ReactDOM(array,container)一起使用。

问题是: 如果我已经渲染了一组组件,它们全部是同一父级的子级,是否可以从父节点动态更新它们的道具? 我想这样做是为了实现有条件的渲染,以决定哪个组件渲染。

 class EventsPlanned extends Component{ //the parent
    constructor(props){
    super(props);
    this.state={
        showAllEvents: true,
        showUnmappedEvents: false,
    }
}

componentDidMount(){
    var container = document.getElementById("eventToShowContainer");
    var arr=[];
    var eventsArrayJSON = localStorage.getItem("eventsArray");
    var eventsArray = JSON.parse(eventsArrayJSON);

    if(eventsArray.length !==0){
        for(let i=0; i<eventsArray.length; i++){
            arr.push(<Event key={i}
                        eventName={eventsArray[i].name} 
                        eventPhoto={eventsArray[i].photo} 
                        eventPeriods={eventsArray[i].periods} 
                        eventDescription={eventsArray[i].description}
                        eventTag={eventsArray[i].tag}
                        eventIsDraft={this.state.showAllEvents}
                        eventIsMapped={this.state.showUnmappedEvents}/>);
        }
        ReactDOM.render(arr, container);
    } else {
        ReactDOM.render(this.nothingToShow(), container);
    }
}

filterHandler = (item) =>{  //callback function for dropdown child
    switch(item){
        case "Events Planned":
            this.setState({
                showAllEvents: true,
                showUnmappedEvents: false,
            });
            break;
        case "Unmapped Events":
            this.setState({
                showAllEvents: false,
                showUnmappedEvents: true,
            });
            break;

nothingToShow = () =>{ //in case there aren't event
    return <div className="w3-container">
                <div className="w3-panel">
                    <h1>Nessun Evento da mostrare</h1>
                </div>
            </div>
}

render(){
    return(
            <div>
                <EventsHeader filterHandler={this.filterHandler}/>
                <div id="eventToShowContainer"/>
            </div>
        );
    }
}

export default EventsPlanned;


class Event extends Component{ // the child
    state={
        name: this.props.eventName,
        photo: this.props.eventPhoto,
        periods: this.props.eventPeriods,
        description: this.props.eventDescription,
        tag: this.props.eventTag,
        isDraft: this.props.eventIsDraft,
        showUnmapped: this.props.showUnmapped
    }

    render(){
        if(this.state.showUnmapped){
            return(
                <div className="w3-container">
                    <div className="eventPanel w3-panel">
                        <h1>name: {this.state.name}</h1>
                        <h6>description: {this.state.description}</h6>
                        <h6>{this.state.periods[0]}</h6>
                        <h6>{this.state.tag[0]}</h6>
                    </div>
                </div>
            );
        }
    }

    export default Event;

1 个答案:

答案 0 :(得分:1)

为此,首先,您需要使用父级的render方法渲染所有子级。

componentDidMount删除任何渲染逻辑,并直接在render方法中渲染所有标记:

// EventsPlanned component
state = {
  events: [],
  showEvents: false,
  showUnmappedEvents: false,
}

componentDidMount() {
  const eventsArrayJSON = localStorage.getItem("eventsArray");
  const events = JSON.parse(eventsArrayJSON);
  if (events.length > 0) this.setState({ events })
}

filterHandler = filter => ...

nothingToShow() {
  return (
    <div className="w3-container">
      <div className="w3-panel">
        <h1>Nessun Evento da mostrare</h1>
      </div>
    </div>
  )
}

render() {
  const { events, showAllEvents, showUnmappedEvents } = this.state
  return (
    <div>
      <EventsHeader filterHandler={this.filterHandler}/>
      <div id="eventToShowContainer">
        {events.map(e => (
          <Event
            key={e.name}
            eventName={e.name} 
            eventPhoto={e.photo} 
            eventPeriods={e.periods} 
            eventDescription={e.description}
            eventTag={e.tag}
            eventIsDraft={showAllEvents}
            eventIsMapped={showUnmappedEvents}
          />
        ))}
        {events.length === 0 && this.nothingToShow()}
      </div>
    </div>
  )
}

这样,每次父母状态更改时,孩子都会获得更新的eventIsDrafteventIsMapped道具,因为每次状态更改都意味着重新渲染。


您现在的操作方式:

  

初始父级的render将容器div -> componentDidMount -> getElementById渲染到容器-> ReactDOM.render中`

-React已经过时了,现在您需要忘记与命令式DOM更改相关的所有内容(您好,jQuery和Bye!),将其保留在2014年,并深入了解显式状态管理和声明性UI的美好世界

接下来是我提出的解决方案逻辑:

  

如果nothingToShow -> componentDidMount中有任何事件,则初始渲染将渲染setState localStorage ->setState现在触发render ->,如果事件处于状态,则render将绘制我们的Event组件数组

而且,在发生过滤器更换事件时:

  

filterHandler调用setState -> setState触发render-> render读取更新的this.state并呈现{{1} }带有更新的EventEventIsDraft道具

因为现在EventIsMapped组件一直都在从父级接收实际的道具,所以我们不需要它具有局部状态,因此它变得简单:

Event

PS:由于您的代码无法清楚地反映出事件,因此不确定如何分隔草稿/映射事件