【问题标题】:React render function keeps being calledReact 渲染函数不断被调用
【发布时间】:2019-01-29 13:17:30
【问题描述】:

我的 React 应用程序中的渲染函数不断被调用,这会导致问题。我有一个显示一些状态对象的函数,但它失败了,因为它一直被调用。至少我认为是这样的。

其他错误包括未捕获的承诺和更新未安装组件的状态。我认为这些只是不断重新渲染的症状,但我不能确定。我已将所有相关代码粘贴在下面,希望有人能弄清楚并帮助我。

代码

import React, { Component } from 'react';
import './style.css';
import { FlexyFlipCard } from 'flexy-flipcards';
import Bingo from '../utils/Bingo';

class Card extends Component {
  constructor(props) {
    super();

    console.log('constructor - This happens 1st.');

    this.state = {
      loading: 'initial',
      data: '',
      card: {},
      tiles: {}
    };

  }

  componentWillMount() {

    console.log('componentWillMount - This happens 2nd.');

    this.setState({ profile: {} });
    const { userProfile, getProfile } = this.props.auth;
    if (!userProfile) {
      getProfile((err, profile) => {
        this.setState({
          profile,
          loading: 'profile'
        });
      });
    } else {
      this.setState({ profile: userProfile });
    }
  }

  componentDidMount() {

    console.log('componentDidMount - This happens 5th.');

    const cardId = 14;

    this.setState({ loading: 'true' });
    this.fetchCard(cardId)
    .then((card) => {
      console.log('componentDidMount - This happens 9th.');
      this.setState({ tiles: card }, function() {
        this.setState({ loading: 'complete' })
      });
    });
  }

  fetchCard(cardId) {

    const promise = new Promise((resolve, reject) => {
      Bingo.getTiles(cardId).then(card => {
        console.log('fetchCard - This happens 8th (after Bingo.getTiles).');
        resolve(card);
      });
    });

    console.log('fetchCard - This happens 6th.');
    return promise;
  }

  renderCards() {

    console.log('renderCards');

    if (this.state.tiles.length > 0) {
      return this.state.tiles.map(tile => {
        return (
          <div
            className="item"
            key={tile[0].id}>
              <FlexyFlipCard
                  frontBackgroundColor="#000034"
                  backBackgroundColor="#000034"
              >
                <div ref="flipper">
                  <h3>{tile[0].name}</h3>
                  <br />
                  <button className="select">Select artist</button>
                </div>

                <div>
                  <h4>
                    <input type="radio"
                      name="artist1"
                      value={tile[0].artist_1}
                    />
                    {tile[0].artist_1}
                    <br />
                    <br />
                    <input type="radio"
                      name="artist2"
                      value={tile[0].artist_2}
                    />
                    {tile[0].artist_2}
                    <br />
                    <br />
                    <input type="radio"
                      name="artist3"
                      value={tile[0].artist_3}
                    />
                    {tile[0].artist_3}
                    <br />
                    <br />
                    <div ref="flipper">
                      <button className="select"
                        onClick={this.submitArtist}>
                        Save artist
                      </button>
                    </div>
                  </h4>
                </div>
              </FlexyFlipCard>

          </div>
        );
      });
    }
  }

  render() {

    console.log('render - This happens 3rd - after componentWillMount');

    const { profile } = this.state;

    if (this.state.loading === 'initial') {
      console.log('render - This happens 4th - after the class is constructed.');
      return <h2>Intializing...</h2>;
    }


    if (this.state.loading === 'true') {
      console.log('render - This happens 7th - when waiting for data.');
      return (
        <div className="Card">
          <h2>Preparing your bingo card - please wait one moment</h2>
        </div>
      );
    }


    if (this.state.loading === 'complete') {
      console.log('render - This happens when???');
      return (
        <div className="Card">
          <h2>{profile.nickname + String.fromCharCode(39)}s Radio Bingo Board</h2>
          <div className="tileCard">
            <div className="item-list">
              {this.renderCards()}
            </div>
          </div>
         </div>
      );
    }

    console.log('render - This happens 8th - after I get data.');
    return (
      <div className="Card">
        Blank space
       </div>
    );
  }
}

export default Card;

【问题讨论】:

  • React 文档 (reactjs.org/docs/react-component.html) 说 componentwillreceiveprops 是遗留的,不应该使用。也就是说,我注意到 componentWillMount 现在也是遗留的。

标签: reactjs state render


【解决方案1】:

每次你使用 setState 它都会渲染。并非总是如此,有时 React 会同时执行多个 setState 操作。

我无法读取所有错误,但第一个错误是因为页面是在对象不存在的那一刻呈现的,所以它说无法读取未定义的属性 id。您可以在渲染 id 对象之前先询问是否存在。例如。 if(title) title.id 等

如果您需要向用户显示的所有步骤,则必须假设对象在某些情况下不存在,并且您始终必须在调用属性之前检查对象是否存在。

【讨论】:

  • 问题是一旦我从我的数据库中得到响应,渲染就会发生,而不仅仅是当我 setState 时。
  • 是的,但是我从你的代码中看到,当你从 DB 获取数据时你 setState。我只会使用 componentDidMount,会删除 componentWillMount,然后把你需要设置的所有东西放在那里。
  • 感谢您的帮助,但事实证明我没有使用正确的数据结构。我试图通过一个对象而不是一个数组来映射。一旦我解决了这个问题,所有系统都运行了。
【解决方案2】:

问题是我的获取响应是一个对象而不是一个数组,所以我无法映射它。错误消息让我认为这是渲染被调用太多次的问题。

这段简单的代码通过将 JSON 输入到数组中来解决了这个问题。可惜我花了大约一个星期才弄明白。

Bingo.getTiles(cardId).then(response => {

  const card = Object.keys(response).map((index) => {
    const tile = [];
    tile.push(response[index]);
    return tile;
  });

【讨论】:

    猜你喜欢
    • 2021-01-07
    • 2020-11-24
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    • 2019-03-21
    • 2017-07-11
    • 1970-01-01
    • 2020-08-30
    相关资源
    最近更新 更多