【问题标题】:Use parent component to re-render child in React在 React 中使用父组件重新渲染子组件
【发布时间】:2018-11-12 16:58:08
【问题描述】:

我正在创建一个简单的应用程序,但在重新渲染子组件时遇到了问题。在父组件(App)中调用 setState 时,传递给子组件(CardContainer)的道具不会导致它重新渲染。我知道我需要以某种方式在 App 中使用一个函数来调用 CardContainer 中的 setState,但我对如何做到这一点感到困惑。 App 中的状态肯定会发生变化(它显示在 console.logs 中),但是 我需要 CardContainer 来重新渲染它在 App 状态发生变化后映射的数组。有任何想法吗?谢谢!

这里是App代码(父组件):

import React, { Component } from 'react';
import Header from './Header';
import AddButton from './AddButton';
import CardContainer from './CardContainer';
import style from '../style/App.css';



class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      cards: [{id: 1, title: 'first', text: 'Random stuff that is on the paage.'},
        {id: 2, title: 'second', text: 'More text goes here'},
        {id: 3, title: 'third', text: 'to doooo'}],
      cardSelected: false,
      selectedCard: []
    };
    this.addCard = this.addCard.bind(this);
    this.deleteCard = this.deleteCard.bind(this);
    this.openSelectedCard = this.openSelectedCard.bind(this);
    this.closeSelectedCard = this.closeSelectedCard.bind(this);
    this.editExistingCard = this.editExistingCard.bind(this);
  }

  openSelectedCard(card) {
    this.setState({
      cardSelected: true,
      selectedCard: card
    })
  }

  closeSelectedCard() {
    this.setState({
      cardSelected: false
    })
  }

  addCard() {
    let newId = this.state.cards.length + 2;
    this.openSelectedCard({id: newId, title: 'Untitled', text: 'Just start typing here.'});
    // this.state.cards.push('New Post It');
    // this.setState({
    //   cards: this.state.cards
    // })
  }

  editExistingCard(cardToEdit) {
    for (let i = 0; i < this.state.cards.length; i++) {
      if(this.state.cards[i].id === cardToEdit.id) {
        this.state.cards.splice(i, 1);
        this.state.cards.splice(i, 0, cardToEdit);
      }
    }
    this.setState({
      cards: this.state.cards
    }, () => {this.closeSelectedCard()})
  }

  deleteCard(index) {
    console.log(this.state.cards[index])
    this.state.cards.splice(index, 1);
    this.setState({
      cards: this.state.cards
    })
  }

  render() {
    return (
        <div className={style.appContainer}>
          <Header addCard={this.addCard}/>
          <CardContainer openSelectedCard={this.openSelectedCard} closeSelectedCard={this.closeSelectedCard} cards={this.state.cards} deleteCard={this.deleteCard} selectedCard={this.state.selectedCard} cardSelected={this.state.cardSelected} editExistingCard={this.editExistingCard}/>
        </div>
    );
  }
}

export default App;

这里是 CardContainer 代码(子组件):

import React, { Component } from 'react';
import Card from './Card';
import SelectedCard from './SelectedCard';
import style from '../style/CardContainer.css';



class CardContainer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      selecedCard: [],
      cards: []
    };
  }

  componentWillMount() {
    this.setState({
      cards: this.props.cards
    })
  }

  render() {
    return (
        <div className={style.cardContainer}>
          {this.state.cards.map((card, index) => (
            <Card card={card} key={card.id} index={index} title={card.title} text={card.text} openSelectedCard={() => this.props.openSelectedCard(card)} deleteCard={this.props.deleteCard}/>
          ))}
          {this.props.cardSelected &&
            <div className={style.selectedCardComponentContainer}>
              <SelectedCard card={this.props.selectedCard} closeSelectedCard={this.props.closeSelectedCard} editExistingCard={this.props.editExistingCard}/>
            </div>
          }
        </div>
    );
  }
}

export default CardContainer;

【问题讨论】:

    标签: javascript reactjs rendering setstate


    【解决方案1】:

    不要在子组件的状态中使用cards。用户 this.props.cards 相反,只要道具发生变化,它就会重新渲染您的组件。如果还是不行,请使用component.forceUpdate()

    class CardContainer extends Component {
      render() {
        return (
            <div className={style.cardContainer}>
              {this.props.cards.map((card, index) => (
                <Card card={card} key={card.id} index={index} title={card.title} text={card.text} openSelectedCard={() => this.props.openSelectedCard(card)} deleteCard={this.props.deleteCard}/>
              ))}
              {this.props.cardSelected &&
                <div className={style.selectedCardComponentContainer}>
                  <SelectedCard card={this.props.selectedCard} closeSelectedCard={this.props.closeSelectedCard} editExistingCard={this.props.editExistingCard}/>
                </div>
              }
            </div>
        );
      }
    }

    【讨论】:

    • 谢谢,Zohaib!我实际上已经尝试过了,它也不起作用。也许这是一个异步问题?
    • 你永远不应该使用 component.forceUpdate() 因为如果你在使用它,这意味着你的代码有问题,将来可能会导致错误
    【解决方案2】:

    您在componentWillMount 中调用 setState,这样组件就不会重新渲染,因为您调用的组件内部的方法甚至还没有渲染。您应该始终在 React Docs 上的 componentDidMount 上设置状态...

    希望有帮助:)

    【讨论】:

    • 谢谢,曼努埃尔!不幸的是,我也已经尝试过了,但没有成功。
    • 您是否尝试过使用 componentDidReceiveProps() 生命周期方法?
    • 是的,我在发布之前也尝试过。我被难住了。
    【解决方案3】:

    这是CardContainer 生命周期的问题。 处于组件状态的cards 变量仅在组件第一次挂载后设置。每当组件道具更新时,您也需要设置它。

    修复: 您需要在 CardContainer 组件中添加类似这样的内容:

    componentWillReceiveProps(nextProps) {
      this.setState({
        cards: nextProps.cards
      });
    }

    编辑: 另一个解决方法是只使用组件 CardContainer 道具中已有的卡片。

    【讨论】:

      【解决方案4】:

      子组件不会重新渲染,因为 componentWillMount(已弃用,因此请停止使用它)和 componentDidMount 仅在初始启动时触发。此外,我看到您在 CardContainer 组件中声明了一个空数组,即使您将 props 作为构造函数的参数引入。此外,SelectedCard 组件正在接收 props.selectedCard。看起来你的卡片数组根本没有使用。

      我希望你不介意我没有给你答案,但我认为你应该稍微看看这些点并重新评估你的代码结构。

      【讨论】:

        【解决方案5】:

        感谢大家的帮助!我发现我实际上需要在 CardContainer 的子 Card 组件中调用 setState。卡片是我想要重新渲染的实际组件,所以我应该考虑确保它也得到一个 setState。我认为更新填充卡片的数组就足够了。

        【讨论】:

          猜你喜欢
          • 2019-02-26
          • 1970-01-01
          • 2019-06-01
          • 2019-01-31
          • 2018-08-12
          • 2018-10-07
          • 2020-08-18
          • 2020-05-01
          • 2020-02-13
          相关资源
          最近更新 更多