【问题标题】:Pass state to another components function with props使用 props 将状态传递给另一个组件函数
【发布时间】:2018-08-31 03:45:30
【问题描述】:

我正在使用 Google Maps api 创建一个简单的天气 api,我几乎完成了。但是,当我创建 Google 地图时,我需要将 Lat 和 Long 道具传递给我的子组件函数。我设法成功地将状态传递给子组件。但是,在我的子组件中,我有另一个包含我的谷歌代码的函数。当我尝试将其 lat,lng 坐标插入 API 时,它返回 0,0 原因是我无法访问此子组件函数中的道具。但是,我可以访问 return 和 render 中的道具。

所以我的问题是如何从我的父组件访问子组件函数中的道具?

父组件

这是我的代码:

/*eslint-disable no-unused-vars*/

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

import Weathermodule from './weatherModule';

class Weather extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            city: '',
            state: '',
            country: '',
            weatherCity: '',
            weatherState: '',
            weatherLongitude: '',
            weatherLatitude: '',
            weatherDays: [],
            weatherDate: [],
            weatherIcons: [],
            weatherAlt: [],
            weatherTemp: [],
            weatherpresentTemp: [],
            errors: '',
            showweatherComponent: false,
        }
    }

    onChange(e){
        this.setState({
            [e.target.name]: e.target.value
        })
    }

    async onSubmit(e){
        e.preventDefault();

        const APIkey = 'hiddenfortest';
        const city = this.state.city;
        const state = this.state.state;
        const country = this.state.country;

        if(this.state.city === '' || this.state.state === '') {
            this.setState({errors: 'Please fill out all required fields.'})
        } else {
            this.setState({
                showweatherComponent: true,
            });
            const res = await fetch(`http://api.wunderground.com/api/${APIkey}/forecast/geolookup/conditions/q/${country}/${state}/${city}.json`);
            const json = await res.json();

            // For logging response
            // console.log(json);

            this.setState({
                weatherCity: json.location.city,
                weatherState: json.location.state,
                weatherLatitude: json.location.lat,
                weatherLongitude: json.location.lon,
                weatherZip: json.location.zip,
                // Weather Days ex. Tuesday, Wednesday, Thursday etc..
                weatherDays: [
                    json.forecast.simpleforecast.forecastday[0].date.weekday,
                    json.forecast.simpleforecast.forecastday[1].date.weekday,
                    json.forecast.simpleforecast.forecastday[2].date.weekday,
                    json.forecast.simpleforecast.forecastday[3].date.weekday,
                ],
                // Weather Dates
                weatherDate: [
                    json.forecast.simpleforecast.forecastday[0].date.month,
                    json.forecast.simpleforecast.forecastday[0].date.day,
                    json.forecast.simpleforecast.forecastday[1].date.month,
                    json.forecast.simpleforecast.forecastday[1].date.day,
                    json.forecast.simpleforecast.forecastday[2].date.month,
                    json.forecast.simpleforecast.forecastday[2].date.day,
                    json.forecast.simpleforecast.forecastday[3].date.month,
                    json.forecast.simpleforecast.forecastday[3].date.day,
                ],
                // Weather Icons generated for the weather dates
                weatherIcons: [
                    json.forecast.simpleforecast.forecastday[0].icon_url,
                    json.forecast.simpleforecast.forecastday[1].icon_url,
                    json.forecast.simpleforecast.forecastday[2].icon_url,
                    json.forecast.simpleforecast.forecastday[3].icon_url,
                ],
                // Weather Alt Attributes appended to the jsx img tag
                weatherAlt: [
                    json.forecast.simpleforecast.forecastday[0].icon,
                    json.forecast.simpleforecast.forecastday[1].icon,
                    json.forecast.simpleforecast.forecastday[2].icon,
                    json.forecast.simpleforecast.forecastday[3].icon,
                ],
                // High/Low Fahrenheit temperature for the weather dates
                weatherpresentTemp: [
                    json.forecast.simpleforecast.forecastday[0].high.fahrenheit,
                    json.forecast.simpleforecast.forecastday[0].low.fahrenheit,
                    json.forecast.simpleforecast.forecastday[1].high.fahrenheit,
                    json.forecast.simpleforecast.forecastday[1].low.fahrenheit,
                    json.forecast.simpleforecast.forecastday[2].high.fahrenheit,
                    json.forecast.simpleforecast.forecastday[2].low.fahrenheit,
                    json.forecast.simpleforecast.forecastday[3].high.fahrenheit,
                    json.forecast.simpleforecast.forecastday[3].low.fahrenheit,
                ],
                // Today temperature fahrenheit, and celsius
                weatherTemp: [
                    json.current_observation.temp_f,
                    json.current_observation.temp_c,
                ]
            })
            // console.log(this.state);
        }
    }

    render(){
        const latitude = parseFloat(this.state.weatherLatitude).toFixed(2) === NaN ? '' : parseFloat(this.state.weatherLatitude).toFixed(2)
        const longitude = parseFloat(this.state.weatherLongitude).toFixed(2) === NaN ? '' : parseFloat(this.state.weatherLongitude).toFixed(2)
        return (
            <div className="container">
                <h1>Weather Demo</h1>
                {this.state.errors !== '' ? <p style={{color:'#E2231A'}}>Please fill out all required fields</p> : ''}
                <form
                    method="POST"
                    onSubmit={e => this.onSubmit(e)}
                >
                    <label>City</label>
                    <input
                        type="text"
                        className="form-control"
                        name="city"
                        placeholder="City"
                        onChange={e => this.onChange(e)}
                        value={this.state.city}
                    />
                    <label>State</label>
                    <input
                        type="text"
                        className="form-control"
                        name="state"
                        placeholder="State"
                        onChange={e => this.onChange(e)}
                        value={this.state.state}
                    />
                    <label>Country</label>
                    <input
                        type="text"
                        className="form-control"
                        name="country"
                        placeholder="Country"
                        onChange={e => this.onChange(e)}
                        value={this.state.country}
                    />
                    <button
                        type="submit"
                        className="btn btn-regular"
                        onClick={e => this.onSubmit(e)}
                    >
                    Get Weather
                    </button>
                </form>
                {/* Don't show component until submit button clicked, once clicked, pass state down to props for other component */}
                {
                    this.state.showweatherComponent ?
                    <Weathermodule
                        city={this.state.city}
                        state={this.state.state}
                        country={this.state.country}
                        weatherCity={this.state.weatherCity}
                        weatherState={this.state.weatherState}
                        weatherLongitude={this.state.weatherLongitude}
                        weatherLatitude={this.state.weatherLatitude}
                        weatherDays={this.state.weatherDays}
                        weatherDate={this.state.weatherDate}
                        weatherIcons={this.state.weatherIcons}
                        weatherAlt={this.state.weatherAlt}
                        weatherTemp={this.state.weatherTemp}
                        weatherpresentTemp={this.state.weatherpresentTemp}
                        longitude={longitude}
                        latitude={latitude}
                />
                    :
                    null
                }
            </div>
        )
    }
}

export default Weather;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

子组件

/*eslint-disable no-unused-vars*/

import React from 'react';
import ReactDOM from 'react-dom';

class Weathermodule extends React.Component {
    componentDidMount(){
        var locations = {
            lat: Number(this.props.weatherLatitude),
            lng: Number(this.props.weatherLongitude)
        };
        console.log(locations);
        let map = new window.google.maps.Map(document.getElementById('map'), {
            center: locations,
            zoom: 13,
            mapTypeId: 'roadmap',
        });
        console.log(this.props);
    }
    render(){
        return (
            <div className="container">
                <h1>Weather</h1>
                <div className="row" id="weather-description">
                    <div className="col-md-6">
                        <h2>{this.props.weatherCity}, {this.props.weatherState}</h2>
                        <img src={this.props.weatherIcons[0]} alt={this.props.weatherAlt[0]} />
                        <h3>{this.props.weatherTemp[0]}<sup>o</sup>F</h3>
                        <h4>({this.props.weatherTemp[1]}<sup>o</sup>C)</h4>
                    </div>
                    <div className="col-md-6">
                        <p>Latitude: {this.props.latitude}, Longitude: {this.props.longitude}</p>

                        <div id="map" className="map-alignment"></div>
                    </div>
                </div>
                <div className="row">
                    <div className="col-md-3" id="red">
                        <h3>{this.props.weatherDays[0]}</h3>
                        <p>{this.props.weatherDate[0] + "/" + this.props.weatherDate[1]}</p>
                        <img src={this.props.weatherIcons[0]} alt={this.props.weatherAlt[0]} />
                        <p>{this.props.weatherpresentTemp[0]}<sup>o</sup> | {this.props.weatherpresentTemp[1]}<sup>o</sup>F</p>
                    </div>
                    <div className="col-md-3" id="blue">
                        <h3>{this.props.weatherDays[1]}</h3>
                        <p>{this.props.weatherDate[2] + "/" + this.props.weatherDate[3]}</p>
                        <img src={this.props.weatherIcons[1]} alt={this.props.weatherAlt[1]} />
                        <p>{this.props.weatherpresentTemp[2]}<sup>o</sup> | {this.props.weatherpresentTemp[3]}<sup>o</sup>F</p>
                    </div>
                    <div className="col-md-3" id="black">
                        <h3>{this.props.weatherDays[2]}</h3>
                        <p>{this.props.weatherDate[4] + "/" + this.props.weatherDate[5]}</p>
                        <img src={this.props.weatherIcons[2]} alt={this.props.weatherAlt[2]} />
                        <p>{this.props.weatherpresentTemp[4]}<sup>o</sup> | {this.props.weatherpresentTemp[5]}<sup>o</sup>F</p>
                    </div>
                    <div className="col-md-3" id="green">
                        <h3>{this.props.weatherDays[3]}</h3>
                        <p>{this.props.weatherDate[6] + "/" + this.props.weatherDate[7]}</p>
                        <img src={this.props.weatherIcons[3]} alt={this.props.weatherAlt[3]} />
                        <p>{this.props.weatherpresentTemp[6]}<sup>o</sup> | {this.props.weatherpresentTemp[7]}<sup>o</sup>F</p>
                    </div>
                </div>
            </div>
        )
    }
}

export default Weathermodule;

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    Weather 组件中的onSubmit() 函数中,调用this.setState({showweatherComponent: true,});,然后调用异步函数来获取所有地图数据。

    当您第一次调用setState 时,您的render() 函数条件将使用当前状态值呈现您的Weathermodule 组件,此时该值将是自异步API 调用以来的默认值尚未返回数据,您尚未使用新数据设置状态。

    当您的 api 调用返回数据并设置状态时,您的 Weathermodule 组件早已挂载。您没有在孩子身上检查 componentWillReceiveProps 以查看是否应该更新您的地图。

    您试图不在Weathermodule 中使用状态,但如果您这样做会更容易管理。添加一个功能来设置您的地图,而不是直接在compenentDidMount 中使用您的地图功能。这样,您可以根据需要从生命周期中的多个位置调用地图函数。

    想想你想通过哪种方式解决。您可以在onSubmit() 中更改您的第一个setState() 调用的位置,或向您的子组件添加更多生命周期事件,或两者兼而有之。

    在父级中

    async onSubmit(e){
        e.preventDefault();
    
        const APIkey = 'hiddenfortest';
        const city = this.state.city;
        const state = this.state.state;
        const country = this.state.country;
    
        if(this.state.city === '' || this.state.state === '') {
            this.setState({errors: 'Please fill out all required fields.'})
        } else {
            // no need to start rendering your map until you have data
            const res = await fetch(`http://api.wunderground.com/api/${APIkey}/forecast/geolookup/conditions/q/${country}/${state}/${city}.json`);
            const json = await res.json();
    
            // For logging response
            // console.log(json);
    
            this.setState({
                weatherCity: json.location.city,
                weatherState: json.location.state,
                weatherLatitude: json.location.lat,
                weatherLongitude: json.location.lon,
                weatherZip: json.location.zip,
                // Weather Days ex. Tuesday, Wednesday, Thursday etc..
                weatherDays: [
                    json.forecast.simpleforecast.forecastday[0].date.weekday,
                    json.forecast.simpleforecast.forecastday[1].date.weekday,
                    json.forecast.simpleforecast.forecastday[2].date.weekday,
                    json.forecast.simpleforecast.forecastday[3].date.weekday,
                ],
                // Weather Dates
                weatherDate: [
                    json.forecast.simpleforecast.forecastday[0].date.month,
                    json.forecast.simpleforecast.forecastday[0].date.day,
                    json.forecast.simpleforecast.forecastday[1].date.month,
                    json.forecast.simpleforecast.forecastday[1].date.day,
                    json.forecast.simpleforecast.forecastday[2].date.month,
                    json.forecast.simpleforecast.forecastday[2].date.day,
                    json.forecast.simpleforecast.forecastday[3].date.month,
                    json.forecast.simpleforecast.forecastday[3].date.day,
                ],
                // Weather Icons generated for the weather dates
                weatherIcons: [
                    json.forecast.simpleforecast.forecastday[0].icon_url,
                    json.forecast.simpleforecast.forecastday[1].icon_url,
                    json.forecast.simpleforecast.forecastday[2].icon_url,
                    json.forecast.simpleforecast.forecastday[3].icon_url,
                ],
                // Weather Alt Attributes appended to the jsx img tag
                weatherAlt: [
                    json.forecast.simpleforecast.forecastday[0].icon,
                    json.forecast.simpleforecast.forecastday[1].icon,
                    json.forecast.simpleforecast.forecastday[2].icon,
                    json.forecast.simpleforecast.forecastday[3].icon,
                ],
                // High/Low Fahrenheit temperature for the weather dates
                weatherpresentTemp: [
                    json.forecast.simpleforecast.forecastday[0].high.fahrenheit,
                    json.forecast.simpleforecast.forecastday[0].low.fahrenheit,
                    json.forecast.simpleforecast.forecastday[1].high.fahrenheit,
                    json.forecast.simpleforecast.forecastday[1].low.fahrenheit,
                    json.forecast.simpleforecast.forecastday[2].high.fahrenheit,
                    json.forecast.simpleforecast.forecastday[2].low.fahrenheit,
                    json.forecast.simpleforecast.forecastday[3].high.fahrenheit,
                    json.forecast.simpleforecast.forecastday[3].low.fahrenheit,
                ],
                // Today temperature fahrenheit, and celsius
                weatherTemp: [
                    json.current_observation.temp_f,
                    json.current_observation.temp_c,
                ],
                //now you have data, show your component
                showweatherComponent: true
            })
    

    在孩子身上

    componentDidMount(){
        var locations = {
            lat: Number(this.props.weatherLatitude),
            lng: Number(this.props.weatherLongitude)
        };
        this.renderMap(locations);
    }
    componentWillReceiveProps(nextProps){
    
        //ideally this is why giving this component state is important
        //you only would call renderMap if you received new lat/lon coords
        //that is, you would compare state with nextProps
    
        var locations = {
            lat: Number(nextProps.weatherLatitude),
            lng: Number(nextProps.weatherLongitude)
        };
        this.renderMap(locations);
    }
    renderMap = locations => {
        let map = new window.google.maps.Map(document.getElementById('map'), {
            center: locations,
            zoom: 13,
            mapTypeId: 'roadmap',
        });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-02
      • 2019-07-14
      • 1970-01-01
      • 1970-01-01
      • 2017-11-07
      相关资源
      最近更新 更多