【问题标题】:react this.props undefined or empty object反应 this.props 未定义或空对象
【发布时间】:2017-01-21 11:55:50
【问题描述】:

构建一个小的 react 应用程序,将地理位置(由浏览器确定为 props 的子组件)传递。

第一个组件:App.jsx

import React, {Component} from 'react';

import DateTime from './components/dateTime/_dateTime.jsx';
import Weather from './components/weather/_weather.jsx';
import Welcome from './components/welcome/_welcome.jsx';

require ('../sass/index.scss');

export default class App extends Component {

  constructor() {
    super();
    this.state = {
      latitude: '',
      longitude: ''
    };
    this.showPosition = this.showPosition.bind(this);
  }

  startApp () {
    this.getLocation();
  }

  getLocation() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(this.showPosition);
    } else {
        console.log("Geolocation is not supported by this browser.");
    }
  }

  showPosition(position) {
    this.setState({
        latitude: position.coords.latitude,
        longitude: position.coords.longitude
    })
  }

  componentWillMount () {
    this.startApp();
  }

  render() {
    return (
        <div className="container">
            <div className="header-container">
                <Weather latitude={ this.state.latitude } longitude={ this.state.longitude } />
            <DateTime />
            </div>
            <div className="welcome-container">
                <Welcome name="Name" />
            </div>
      </div>
    );
  }
}

该组件确定位置,将纬度和经度保存到 state 并通过 props 将此信息传递给 Weather.jsx 组件,如下图所示:

在 weather.jsx 组件中,我尝试访问这些道具并获得未定义或空对象。

import React, {Component} from 'react';
import Fetch from 'react-fetch';

export default class Weather extends Component {

    constructor(props) {
        super(props);
        this.state = {
          forecast: {},
          main: {},
          weather: {},
        };
        this.setWeather = this.setWeather.bind(this);
    }

    getWeather (latitude, longitude) {
        var self = this;

        fetch('http://api.openweathermap.org/data/2.5/weather?lat=' + latitude + '&lon=' + longitude + '&units=metric&APPID=ed066f80b6580c11d8d0b2fb71691a2c')  
            .then (function (response) {  
                if (response.status !== 200) {  
                    console.log('Looks like there was a problem. Status Code: ' + response.status);  
                    return;  
                }

                response.json().then(function(data) {  
                    self.setWeather(data);
                });
            })

            .catch (function (err) {  
                console.log('Fetch Error :-S', err);  
            });
    }

    setWeather (forecast) {
        var main = forecast.main;
        var weather = forecast.weather[0];

        this.setState({
            main: main,
            weather: weather,
            forecast: forecast
        });
    }

    startApp () {
        this.getWeather(this.props.latitude, this.props.longitude);
    }

    componentWillMount () {
        this.startApp();
    }

    componentDidMount () {
        // window.setInterval(function () {
    //          this.getWeather();
    //  }.bind(this), 1000);
    }

  render() {
    return (
        <div className="">
            <div className="weather-data">
                <span className="temp">{Math.round(this.state.main.temp)}&#176;</span>
                <h2 className="description">{this.state.weather.description}</h2>
            </div>
        </div>
    )
  }
}

真的不确定问题是什么,因为 react 开发工具显示天气组件确实在传递给该组件的道具中设置了位置。

编辑**已解决:

所以问题是状态是异步设置的,并且我的天气组件是在状态更新之前呈现的。

在渲染方法期间对状态值的简单检查解决了这个问题。

render() {

    if (this.state.latitude != '' && this.state.longitude != '') {
      var weatherComponent = <Weather latitude={ this.state.latitude } longitude={ this.state.longitude } />
    } else {
      var weatherComponent = null;
    }

    return (
        <div className="container">
            <div className="header-container">
                {weatherComponent}
            <DateTime />
            </div>
            <div className="welcome-container">
                <Welcome name="Name" />
            </div>
      </div>
    );
  }

【问题讨论】:

  • 如果将初始化逻辑转换为componentDidMount 而不是componentWillMount 会怎样。由于元素尚未安装在 DOM 中,因此 props 可能尚未到达组件。一旦安装,然后做工作。 facebook.github.io/react/docs/component-specs.html
  • 感谢您的建议,遗憾的是这并没有什么不同。但是我刚刚意识到,如果我只是在渲染函数中返回道具,它就可以工作,并且我会在页面上看到渲染的道具。所以仍然不确定为什么startApp() 函数无法访问它们。

标签: reactjs components state


【解决方案1】:

您必须将startApp()getWeather() 绑定到组件,否则this 将是undefined

export default class Weather extends Component {

    constructor(props) {
        super(props);
        this.state = {
          forecast: {},
          main: {},
          weather: {},
        };
        this.setWeather = this.setWeather.bind(this);
        this.getWeather = this.getWeather.bind(this);
        this.startApp = this.startApp.bind(this);
    }
    ...
}

【讨论】:

  • 好的,这是有道理的。通过此更改,我现在可以访问道具。但是,由于某种原因,纬度和经度道具返回为空字符串,即使现在反应开发工具显示道具中的实际值。因此,如果我在构造函数中 console.log(this.props)componentWillMount 上,我会得到:Object {latitude: "", longitude: ""}
  • 您还必须在您的App 组件中绑定startApp() 和getLocation()`。
【解决方案2】:

我认为问题如下。 SetState 异步发生。因此,您的渲染函数会在纬度和经度道具有数据之前触发。如果您在渲染 Weather 组件之前有一些 if 检查,您可能不会遇到此问题。这是我的意思的一个例子。

render() {
    let myComponent;
    if(check if props has val) {
        myComponent = <MyComponent />
    } else {
        myComponent = null
    }
    return (
        <div>
            {myComponent}
        </div>
    )
}

【讨论】:

  • 美丽而简单,这行得通。不敢相信我以前没有想到这一点!谢谢。
  • 是的,这可能是一个真正的哥特式!
【解决方案3】:

您需要保持渲染尽可能干净。避免在渲染中执行 if else,而是直接使用三元运算符或 && 运算符进行 if else 检查。像下面这样进行条件检查,然后才调用 MyComponent 如下所示

render() {
    return (
        <div>
            {this.state.latitude != '' && this.state.longitude != '' ? <Weather latitude={ this.state.latitude } longitude={ this.state.longitude } />: null}
            {this.state.latitude != '' && this.state.longitude != '' && <Weather latitude={ this.state.latitude } longitude={ this.state.longitude } />}
        </div>
    )
}

【讨论】:

    猜你喜欢
    • 2020-03-21
    • 1970-01-01
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    • 1970-01-01
    相关资源
    最近更新 更多