【问题标题】:Update child's props from parent node从父节点更新孩子的道具
【发布时间】:2018-08-05 17:03:23
【问题描述】:

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

最初我的所有组件都被渲染了,但是当我对过滤器进行选择时,我只想渲染与所做选择相关的组件。 为此,我认为我应该有一个由我的组件填充的数组和一个容器,仅当组件安装时才会与此方法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;

【问题讨论】:

  • 你能贴一些你自己试过的代码吗?

标签: javascript reactjs


【解决方案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 -&gt; componentDidMount -&gt; getElementById 找到容器-&gt; ReactDOM.render 到那个容器`

-- React 已经过时了,现在你需要忘记所有与命令式 DOM 更改相关的事情(你好,jQuery 和再见!),把这一切都留在 2014 年,潜入显式状态管理和声明式 UI 的美妙世界.

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

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

并且,在过滤器更改的情况下:

filterHandler 调用 setState -&gt; setState 触发 render -> render 读取更新的 this.state 并使用更新的 Event 渲染 Event 的 props 987654353@ 和 @9876545p >

由于现在Event组件一直从父组件接收实际的props,我们不需要它有本地状态,所以它变得很简单:

const Event = props => props.showUnmapped && (
  <div className="w3-container">
    <div className="eventPanel w3-panel">
      <h1>name: {props.name}</h1>
      <h6>description: {props.description}</h6>
      <h6>{props.periods[0]}</h6>
      <h6>{props.tag[0]}</h6>
    </div>
  </div>
)

PS:不确定你是如何分离草稿/映射事件的,因为你的代码没有清楚地反映它

【讨论】:

  • 我理解你的建议,但是我无法更新componentDidMount中的事件状态,你有什么建议吗?
  • 实际上我正在使用循环和这个sintax来更新状态'events:[...prevState.events,eventsArray[i]]',但不起作用
  • 为什么不能更新cDM 中的事件状态?您可以从localStorage 阅读它们并致电setState 吗? for 循环对于这个任务是多余的
  • 我正在尝试,但在调用 setState 之后,我调用了 console.log(this.state.events.length),结果为零。我确定在 eventsArray 中有一些东西,因为我在控制台中打印了它的内容
  • 如果您的console.log(this.state.events.length)componentDidMount 内部,那么它当然会呈现为零,因为setState 更新是异步的(它在React 上,何时应用新状态)。取而代之的是,您应该将 console.log 放在 render 方法中,该方法以更新状态调用。
猜你喜欢
  • 1970-01-01
  • 2019-11-24
  • 2019-04-17
  • 1970-01-01
  • 1970-01-01
  • 2018-02-08
  • 2021-09-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多