【问题标题】:React state array indexing not possible反应状态数组索引不可能
【发布时间】:2018-10-05 14:10:31
【问题描述】:

我有一个反应组件:

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>
  ))
);

编译失败,报错

无法读取 null 的属性“0”

当它试图索引坐标数组时。为了调试这个,我尝试删除索引(即 lat 和 lng 都等于 props.coords)。显然,这在逻辑上是没有意义的,Google API 抱怨了,但 react 没有。此外,使用 chrome react 工具显示 props.coords 确实存在,并且是一个包含预期的两个坐标的数组。那么为什么 javascript 不让我索引一个数组呢?

【问题讨论】:

    标签: javascript reactjs state react-props


    【解决方案1】:

    问题不在于数组,问题在于您的数据是异步获取的。 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>
            );
        }
    }
    

    【讨论】:

      【解决方案2】:

      在 React 组件生命周期中,render 在 componentDidMount 之前被调用。

      这意味着第一次调用render时,this.state.coordinates为null,因此没有0索引。

      更改您的构造函数以将坐标设置为空数组。 例如

      this.state = {
        name: null,
        description: null,
        address: null,
        coordinates: []
      };
      

      【讨论】:

        【解决方案3】:

        具体的解决方案是这样的。

        之所以获得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>
            );
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2021-11-28
          • 1970-01-01
          • 2020-03-29
          • 2016-07-06
          • 2019-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-12
          相关资源
          最近更新 更多