Реакция индексации массива состояний невозможна - PullRequest
0 голосов
/ 05 октября 2018

У меня есть компонент реагирования:

export default class Detail extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: null,
      description: null,
      address: null,
      coordinates: null
    };
  }
  componentDidMount() {
    const apiUrl = `http://localhost:8000/api/frontend/listing/${
      this.props.match.params.id
    }`;
    fetch(apiUrl)
      .then(response => response.json())
      .then(response =>
        this.setState({
          name: response.name,
          description: response.description,
          address: response.address,
          coordinates: response.coordinates
        })
      );
  }

  render() {
    return (
      <div>
        <MapComponent
          isMarkerShown
          googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
          loadingElement={<div style={{ height: `100%` }} />}
          containerElement={<div style={{ height: `400px` }} />}
          mapElement={<div style={{ height: `100%` }} />}
          coords={this.state.coordinates}
          />
      </div>
    );
  }
}

, который использует следующий компонент:

const MapComponent = withScriptjs(
  withGoogleMap(props => (
    <GoogleMap
      defaultZoom={8}
      defaultCenter={{ lat: +props.coords[0], lng: +props.coords[1] }}
    >
      {props.isMarkerShown && (
        <Marker position={{ lat: +props.coords[0], lng: +props.coords[1] }} />
      )}
    </GoogleMap>
  ))
);

Не удается скомпилировать, с ошибкой

Невозможно прочитать свойство '0' с нулевым значением

, когда оно пытается проиндексировать массив координат.Чтобы отладить это, я попытался удалить индексирование (то есть, lat и lng оба равны props.coords).Очевидно, что в этом нет логического смысла, и Google API жаловался, но реагировать не стал.Кроме того, использование инструментов реакции Chrome показало, что props.coords действительно существует и представляет собой массив, содержащий две координаты, как и ожидалось.Так почему же javascript не позволяет мне индексировать массив?

Ответы [ 3 ]

0 голосов
/ 05 октября 2018

В жизненном цикле компонента React рендер вызывается перед componentDidMount.

Это означает, что при первом вызове рендеринга this.state.coordinates имеет значение null и, следовательно, не имеет индекса 0.

Измените ваш конструктор, чтобы установить координаты, чтобы быть пустым массивом.например,

this.state = {
  name: null,
  description: null,
  address: null,
  coordinates: []
};
0 голосов
/ 05 октября 2018

Конкретное решение будет выглядеть следующим образом.

Причина, по которой вы получаете Cannot read property '0' of null, потому что вы инициализировали координаты с нулевым значением, поэтому при начальном рендеринге компонента вы отправляете нулевые координаты в MapComponent и получаете доступ к данным.Поэтому создайте координаты с пустым массивом и сделайте условные проверки, а затем выполните рендеринг.

Вам нужно позаботиться о загрузке сообщения пользователю, когда вы получите успешный ответ, вам нужно прекратить показывать загрузку сообщения и визуализировать ответ как мудрыйвам также нужно показать сообщение об ошибке пользователю, если вызов fetch api завершится неудачно.В приведенном ниже коде все эти условные проверки выполняются

Функциональность должна работать всегда, поэтому вам нужно позаботиться о сбросе значений состояния, чтобы они работали каждый раз, когда ваш компонент заново отображает, показывая загрузку или успешный ответ или ответ об ошибкеесли выборка не удалась

Приведенный ниже код подробно объясняет конкретное решение

export default class Detail extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: null,
      description: null,
      address: null,
      coordinates: [],
      error: null
    };
  }
  componentDidMount() {
    this.setState({
       loading: true,
       name: null,
      description: null,
      address: null,
      coordinates: [],
      error: null
    });
    const apiUrl = `http://localhost:8000/api/frontend/listing/${
      this.props.match.params.id
    }`;
    fetch(apiUrl)
      .then(response => response.json())
      .then(response =>
        this.setState({
          loading: false,
          name: response.name,
          description: response.description,
          address: response.address,
          coordinates: response.coordinates,
          error: ""
        })
      )
      .catch(err =>
        this.setState({
          loading: false,
          name: null,
          description: null,
          address: null,
          coordinates: [],
          error: "Error occurred while fetching data"
        })
      );
  }

  render() {
    const { coordinates, error, loading } = this.state;
    return (
      <div>
        {loading && <div>Fetching data, please wait</div>}
        {!loading && coordinates.length == 0 && <div>{error}</div>}
        {!loading && error == null && coordinates.length > 0 && (
        <MapComponent
          isMarkerShown
          googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
          loadingElement={<div style={{ height: `100%` }} />}
          containerElement={<div style={{ height: `400px` }} />}
          mapElement={<div style={{ height: `100%` }} />}
          coords={coordinates}
          />)}
      </div>
    );
  }
}
0 голосов
/ 05 октября 2018

Проблема не в массиве, проблема в том, что ваши данные выбираются асинхронно.MapComponent отображается перед извлечением данных.

Обычной практикой для обработки этих случаев в React является проверка состояния в методе рендеринга, рендеринг счетчика или сообщения «пожалуйста, подождите» и т. Д. КакПока данные извлекаются.

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

Пример:

export default class Detail extends Component {
    constructor(props) {
        super(props);
        this.state = {
            name: null,
            description: null,
            address: null,
            coordinates: null
        };
    }
    componentDidMount() {
        const apiUrl = `http://localhost:8000/api/frontend/listing/${
            this.props.match.params.id
            }`;
        fetch(apiUrl)
            .then(response => response.json())
            .then(response =>
                this.setState({
                    name: response.name,
                    description: response.description,
                    address: response.address,
                    coordinates: response.coordinates
                })
            );
    }

    render() {
        if (!this.state.coordinates) {
            return <div>Fetching data, please wait…</div>;
        }
        return (
            <div>
                <MapComponent
                    isMarkerShown
                    googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
                    loadingElement={<div style={{ height: `100%` }} />}
                    containerElement={<div style={{ height: `400px` }} />}
                    mapElement={<div style={{ height: `100%` }} />}
                    coords={this.state.coordinates}
                />
            </div>
        );
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...