Используйте родительский компонент для повторного рендеринга дочернего элемента в React - PullRequest
0 голосов
/ 03 июня 2018

Я создаю простое приложение и у меня возникают проблемы при повторном рендеринге дочернего компонента.Когда setState вызывается в родительском компоненте (App), реквизиты, передаваемые дочернему компоненту (CardContainer), не вызывают его повторную визуализацию.Я знаю, что мне нужно каким-то образом использовать функцию в App для вызова setState в CardContainer, но я не знаю, как это сделать.Состояние в App определенно изменяется (оно отображается в console.logs), но Мне нужен CardContainer для повторного рендеринга массива, который он отображает после изменения состояния приложения .Есть идеи?Спасибо!

Вот код приложения (родительский компонент):

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;

Ответы [ 5 ]

0 голосов
/ 03 июня 2018

Спасибо за помощь!Я понял, что мне действительно нужно вызвать setState в дочернем элементе CardContainer, компоненте Card.Карта была именно тем компонентом, который я хотел повторно визуализировать, поэтому я должен был подумать, чтобы убедиться, что он также получает setState.Я думал, что обновления массива, который заполняет карты, будет достаточно.

0 голосов
/ 03 июня 2018

Дочерний объект не выполняет повторную визуализацию, поскольку componentWillMount (который устарел, поэтому прекратите его использовать) и componentDidMount запускается только при первоначальном запуске.Также я вижу, что вы объявили пустой массив в компоненте CardContainer, даже если вы вносите реквизиты в качестве параметров конструктора.Также компонент SelectedCard получает props.selectedCard.Похоже, ваш массив карт в состоянии не используется вообще.

Надеюсь, вы не возражаете, что я не передал вам ответ, но я думаю, что вам следует немного рассмотреть эти моменты и пересмотреть структуру кода.

0 голосов
/ 03 июня 2018

Вы вызываете setState в componentWillMount, поэтому компонент не будет повторно визуализироваться, потому что вы вызываете метод внутри компонента, который еще даже не отображается.Вы должны всегда устанавливатьState на componentDidMount, который находится на React Docs ...

Надежда помогает:)

0 голосов
/ 03 июня 2018

Это проблема жизненного цикла CardContainer.Переменная cards, находящаяся в состоянии компонента, устанавливается только после первого монтирования компонента.Вы должны установить это также всякий раз, когда реквизиты компонента обновляются.

Исправление: вам нужно добавить что-то подобное в вас CardContainer компонент:

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

Редактировать: Еще одним исправлением было бы просто использовать карты, которые у вас уже есть в компоненте CardContainer.

0 голосов
/ 03 июня 2018

Не используйте 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>
    );
  }
}
...