首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何修复没有重新渲染的子组件(由于作为属性传递的数据更改,而不是状态)?

如何修复没有重新渲染的子组件(由于作为属性传递的数据更改,而不是状态)?
EN

Stack Overflow用户
提问于 2018-10-11 06:30:53
回答 1查看 1.5K关注 0票数 6

背景

我正在开发一个流星应用程序,它使用ReactJS作为渲染库。

目前,在更新数据时,即使父组件正在访问更新的数据&应该将其传递给子组件,我也无法让子组件重新呈现。

父组件是数据表。子组件是一个单击可编辑的日期字段。

它的工作方式(理论上):父组件将date的现有数据作为道具传递给子组件。子组件获取现有的props数据,处理它并使用它设置一些状态,然后有两个选项:

  • default: display data
  • if user click on data field:更改为输入并允许用户选择日期(使用react-datepicker),更改状态--当用户在字段之外单击时,触发返回到仅显示并将更新后的数据从状态保存到数据库

我在表中每行使用子组件两次,每次使用它时,它都需要访问数据库中最新的日期数据。因此,如果数据在一个字段中发生更改,则第二个字段应反映该更改。

Problem

第二个字段不会反映数据库中的更改,除非我手动刷新页面并强制使子组件使用新数据呈现。编辑后的字段反映的是数据的变化,因为它反映的是状态中存储的内容。

在阅读React文档之后,我确信问题是因为日期是作为一个道具传入的,然后作为一个状态被处理--并且因为组件不会从道具更改中重新呈现。

我的问题

我该怎么做才能解决这个问题?

我对文档所做的所有阅读都强烈建议远离forceUpdate()和getDerivedStateFromProps()之类的东西,但结果是我不确定如何让数据以我想要的方式传递。

有什么想法?

我的代码

我稍微缩短了代码,删除了特定于我的项目的变量名,但如果有用的话,我可以提供更多的实际内容。我认为我的问题比直接的调试更具概念性。

父级

代码语言:javascript
复制
ParentComponent () {
    //Date comes as a prop from database subscription
    var date1 = this.props.dates.date1 
    var date2 = this.props.dates.date2
    return(
        <ChildComponent 
            id='handle-date-1'
            selected={[date1, date2]} />
        <ChildComponent 
            id='handle-date-2'
            selected={[date1, date2]} />
    )
}

孩子

代码语言:javascript
复制
ChildComponent() {
    constructor(props) {
        super(props);
        this.state = {
            date1: this.props.selected[0],
            date2: this.props.selected[1],
            field: false,
        };
    }

    handleDatePick() {
        //Handles the event listeners for clicks in/out of the div, handles calling Meteor to update database.
    }
    renderDate1() {
        return(
            <div>
                {this.state.field == false &&
                    <p onClick={this.handleClick}>{formatDate(this.state.date1)}</p>}
                {this.state.field == true &&
                    <DatePicker
                        selected={this.state.date1}
                        startDate={this.state.date1}
                        onChange={this.handleDatePick}
                    />
                }
            </div>
        )
    }
    renderDate2() {
        return(
            <div>
                {this.state.field == false &&
                    <p onClick={this.handleClick}>{formatDate(this.state.date2)}</p>}
                {this.state.field == true &&
                    <DatePicker
                        selected={this.state.date2}
                        startDate={this.state.date2}
                        onChange={this.handleDatePick}
                    />
                }
            </div>
        )
    }
    render() {
        return(
            //conditionally calls renderDate1 OR renderDate2
        )
    }
}

(如果这段代码/我的解释很粗糙,那是因为我仍然是一个相当初级/低级的开发人员。我没有接受过正式的培训,所以我在工作中学习,同时开发了一个相当困难的应用程序。作为一个单独的开发人员。说来话长。请温文点!)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-11 07:54:52

React文档中有一节介绍了constructor()的最佳实践用法。阅读这篇文章,密切关注黄色突出显示的"Note“部分,应该会阐明您遇到的确切问题。

本质上,constructor()只运行一次,最常用于初始化内部/本地状态(或绑定方法)。这意味着,当为该子组件调用时,该子组件将使用selected prop 中的值来设置constructor()date1。在调用constructor()时,无论selected的值是什么,都将被设置为子对象的状态,即使该值继续更改,该值也将保持不变。

因此,对传递给子组件的selected属性的任何后续更新都不会反映在该组件的内部状态中,这意味着将不会重新呈现该组件。您需要在子组件中的其他位置使用React的setState()方法来正确更新子组件的状态并触发重新呈现。

使用React生命周期方法的组合来正确更新子组件是可行的。下面的代码片段为您提供了在componentDidMount()componentDidUpdate()中对实现进行哪些更改的主要思路

代码语言:javascript
复制
class Child extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date1: 0,
      date2: 0,
    };
  }

  /*
    Any time the child mounts to the DOM, 
    you can use the method below to set 
    your state using the current value of your 
    selected prop from the parent component...
  */

  componentDidMount() {
    this.setState({
      date1: this.props.selected[0],
      date2: this.props.selected[1]
    });
  }

  /* 
   When the child receives an update from its parent, 
   in this case a new date selection, and should 
   re-render based on that update, use the method below 
   to make a comparison of your selected prop and then 
   call setState again...
  */

  componentDidUpdate(prevProps) {
    if (prevProps.selected !== this.props.selected) {
      this.setState({
        date1: this.props.selected[0],
        date2: this.props.selected[1]
      });
    }
  }

  render() {
    const { date1, date2 } = this.state;
    return (
      <div style={{ border: `4px dotted red`, margin: 8, padding: 4 }}>
        <h1 style={{ fontWeight: 'bold' }}>Child</h1>
        <h2>The value of date1 is {date1}</h2>
        <h2>The value of date2 is {date2}</h2>
      </div>
    );
  }
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      valOne: 0,
      valTwo: 0
    };
  }

  incrementOne = () => {
    this.setState(prevState => ({ valOne: (prevState.valOne += 1) }));
  };

  incrementTwo = () => {
    this.setState(prevState => ({ valTwo: (prevState.valTwo += 1) }));
  };

  render() {
    const { valOne, valTwo } = this.state;
    return (
      <div style={{ border: `4px solid blue`, margin: 8, padding: 4 }}>
        <h1 style={{ fontWeight: 'bold', fontSize: 18 }}>Parent</h1>
        <button onClick={() => this.incrementOne()}>Increment date1</button>
        <button onClick={() => this.incrementTwo()}>Increment date2</button>
        <Child selected={[valOne, valTwo]} />
      </div>
    );
  }
}

ReactDOM.render(<Parent />, document.querySelector('#app'));
代码语言:javascript
复制
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

既然您正在为您的孩子使用React组件模式,那么很好地利用React生命周期方法将真正帮助您走出这一步。我不能强烈建议你学习the React component lifecyle。随着您继续使用React,它在这样的情况下将变得至关重要。componentDidMount()componentDidUpdate()是很好的起点。

希望这能有所帮助。让我们知道结果如何。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52749644

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档