Реагирующая таблица компонентов обрабатывается несколько раз или дублируется после обновления состояния - PullRequest
0 голосов
/ 19 января 2019

Я обновляю состояние с изменениями в реквизитах, заменяя старое состояние. При рендеринге данные либо дублируются, либо воспроизводятся несколько раз из состояния после сброса с новыми реквизитами. Это происходит после первого рендера.

Это рабочий процесс приложения - выборка происходит в первую очередь, когда пользователь ищет местоположение. Это получает "рекомендуемые места" вокруг местоположения пользователей. Это помещает данные в избыточное хранилище как «рекомендуемые места». Компоненты, о которых идет речь, визуализируют данные из хранилища [первая картинка], что происходит хорошо. Когда нажимаются кнопки фильтра, на этот раз он выбирает данные о местоположении пользователя и фильтре и помещает данные в хранилище избыточных данных, например, restaurant = [], bars = [] и т. Д. Компоненты должны получать новые данные из хранилища и повторная визуализация. Вот где моя проблема. При повторном рендеринге данные дублируются [вторая картинка].

Это рассматриваемый компонент-

import React, { Component } from "react";
import PropTypes from "prop-types";

export default class Results extends Component {
  state = {
    places: []
  };

getSnapshotBeforeUpdate(prevProps) {

  const {places, restaurant, bar, coffee, bank, park} = 
  this.props.results;

  if (prevProps.results.places !== places) {
      this.setState({ places });
  }
  if (prevProps.results.restaurant !== restaurant) {
      this.setState({ places: restaurant });
  }
  if (prevProps.results.bar !== bar) {
      this.setState({ places: bar });
  }
  if (prevProps.results.coffee !== coffee) {
      this.setState({ places: coffee });
  }
  if (prevProps.results.bank !== bank) {
      this.setState({ places: bank });
  }
  if (prevProps.results.park !== park) {
      this.setState({ places: park });
  }
}

renderPlaces = () => this.state.places.map((place, i) => {
  if (place.type || place.type === "Recommended Places") {
      return place.items.map((item, i) => (
          <tbody key={item.venue.id}>
              <tr className="table-secondary">
                  <th scope="row">{item.venue.name}</th>
                  <td>
                      <h6>
                          {`${(item.venue.location.distance / 
                           1609.344).toFixed(2)}`}{" "}
                          <cite>miles</cite>
                      </h6>
                  </td>
              </tr>
          </tbody>
      ));
  }
  return this.state.places.map((place, i) => (
      <tbody key={place.id}>
          <tr className="table-secondary">
              <th scope="row">{place.name}</th>
              <td>
                  <h6>
                      {`${(place.location.distance / 
                      1609.344).toFixed(2)}`}{" "}
                      <cite>miles</cite>
                  </h6>
              </td>
          </tr>
      </tbody>
   ));
})

render() {
  return (
      <React.Fragment>
          {this.renderPlaces()}
      </React.Fragment>
  );
 }
}

Results.propTypes = {
  places: PropTypes.array,
  restaurant: PropTypes.array,
  coffee: PropTypes.array,
  bar: PropTypes.array,
  banks: PropTypes.array,
  parks: PropTypes.array
};

Ниже представлен родительский компонент-

import React, { Component } from "react";
import PropTypes from "prop-types";

import { connect } from "react-redux";
import Results from "./Results";

class ResultList extends Component {
  state = {
    places: [],
    restaurant: [],
    bar: [],
    coffee: [],
    bank: [],
    park: []
  };

  getSnapshotBeforeUpdate(prevProps) {
    const {
      recommendedPlaces,
      restaurants,
      coffee,
      bars,
      banks,
      parks
    } = this.props;

    if (prevProps.recommendedPlaces !== recommendedPlaces) {
      this.setState({ places: recommendedPlaces });
      // returning a snapshot just in case I want to use..⬇
      // componentDidUpdate in the future
      return recommendedPlaces;
    }
    if (prevProps.restaurants !== restaurants) {
      this.setState({ restaurant: restaurants });
      // returning a snapshot just in case I want to use..⬇
      // componentDidUpdate in the future
      return restaurants;
    }
    if (prevProps.bars !== bars) {
      this.setState({ bar: bars });
      // returning a snapshot just in case I want to use..⬇
      // componentDidUpdate in the future
      return bars;
    }
    if (prevProps.coffee !== coffee) {
      this.setState({ coffee });
      // returning a snapshot just in case I want to use..⬇
      // componentDidUpdate in the future
      return coffee;
    }
    if (prevProps.banks !== banks) {
      this.setState({ bank: banks });
      // returning a snapshot just in case I want to use..⬇
      // componentDidUpdate in the future
      return banks;
    }
    if (prevProps.parks !== parks) {
      this.setState({ park: parks });
      // returning a snapshot just in case I want to use..⬇
      // componentDidUpdate in the future
      return parks;
    }

    return null;
  }

  render() {
    const { address, filterBy } = this.props;
    return (
      <table className="primary table table-hover">
        <thead>
          <tr>
            <th scope="col">
              {filterBy === null ? "Places" : filterBy.toUpperCase()}
              {
                // eslint-disable-next-line
              }{" "}
              near
              {
                // eslint-disable-next-line
              }{" "}
              {address.toUpperCase()}
            </th>
            {/* this.showPlaces(recommendedPlaces, restaurants, bars, parks) */}
            <th scope="col">Distance</th>
          </tr>
        </thead>
        <Results results={this.state} />
      </table>
    );
  }
}

ResultList.propTypes = {
  address: PropTypes.string,
  filterBy: PropTypes.string,
  recommendedPlaces: PropTypes.array,
  restaurants: PropTypes.array,
  coffee: PropTypes.array,
  bars: PropTypes.array,
  banks: PropTypes.array,
  parks: PropTypes.array
};

const mapStateToProps = state => ({
  recommendedPlaces: state.places.recommendedPlaces,
  restaurants: state.places.restaurants,
  coffee: state.places.coffee,
  bars: state.places.bars,
  banks: state.places.banks,
  parks: state.places.parks
});

export default connect(mapStateToProps)(ResultList);

Следующие две картинки являются отображаемой страницей.

Первый - первый рендер при поиске места. Рендеринг отлично. Он выбирает и отображает только «рекомендуемые места».

enter image description here

Второй - это рендеринг, который происходит после сброса состояния, когда появляются новые реквизиты при нажатии на кнопку фильтра слева. Он не фильтрует данные о местах. Вместо этого он выбирает и отображает новые данные с использованием местоположения и фильтра.

enter image description here

Любая помощь очень ценится!

https://codesandbox.io/s/zw33318484 Найдите адрес в поле поиска автозаполнения. Он должен отображать середину страницы (ResultList.js и Result.js) с «рекомендуемыми местами». Затем выберите «ресторанный» фильтр. Теперь следует перерисовать рестораны, которые находятся в магазине. Вместо этого он просто продолжает добавлять ресторан на визуализации. Я думаю, что это повторный рендеринг и объединение ресторанного массива в реквизитах. Он делает это столько раз, сколько перерисовывает.

1 Ответ

0 голосов
/ 20 января 2019

Проблема в вашей функции renderPlaces.Ниже приведена упрощенная версия, облегчающая просмотр структуры.

renderPlaces = () => {
    this.state.places.map((place, i) => {
      if (place.type || place.type === "Recommended Places") {
          // When first selecting a location from the autocomplete search,
          // you execute this code
          return place.items.map((item, i) => (
              <tbody key={item.venue.id}>
                  {/* stuff to render a place */}
              </tbody>
          ));
      }
      // When you select a filter, you hit this condition instead.
      return this.state.places.map((place, i) => (
          <tbody key={place.id}>
              {/* stuff to render a place */}
          </tbody>
       ));
    })
};

При первом выборе местоположения в this.state.places имеется одна запись с place.type «Рекомендуемые места».Этот place имеет массив items, который управляет рендерингом.Когда вы выбираете фильтр (например, «Рестораны»), places имеет несколько записей (10 в случае, который я видел), и ни одна из них не имеет type, поэтому он соответствует второму условию.Второй возврат выполняет this.state.places.map вызов, но вы все еще находитесь внутри внешнего вызова this.state.places.map, поэтому вы повторяете все места по одному разу для каждого места.Таким образом, дополнительные копии связаны не с количеством повторных рендеров, а с количеством мест.Если вы удалите второй this.state.places.map, как показано ниже, он будет работать нормально (по крайней мере, в этом аспекте).

renderPlaces = () => {
    this.state.places.map((place, i) => {
      if (place.type || place.type === "Recommended Places") {
          return place.items.map((item, i) => (
              <tbody key={item.venue.id}>
                  {/* stuff to render a place */}
              </tbody>
          ));
      }
      return (
          <tbody key={place.id}>
              {/* stuff to render a place */}
          </tbody>
      );
    })
};

Edit nearby

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...