【问题标题】:React - passing data between componentsReact - 在组件之间传递数据
【发布时间】:2018-02-15 21:36:34
【问题描述】:

这是我第一次尝试一个简单的 React 应用程序。使用 Openweather API 和 AXIOS。我参加了 Stephen Grider 关于 Udemy 的课程,现在我正在尝试自己创建一些东西,但是在组件之间传递数据时仍然遇到问题。我有一个 SearchBar 组件,我希望能够将输入值传递给父组件的状态,因此我可以在每次搜索时更新它并将其呈现到 DOM 中。但是,我一直遇到错误。我尝试将一个函数作为道具传递给我的 SearchBar 组件,但出现错误:

setState(...):只能更新一个挂载或挂载的组件。这通常意味着您在未安装的组件上调用了 setState()。这是一个无操作。请检查 App 组件的代码。

citySearch 未定义

这让我很困惑,因为我试图从课程中复制确切的步骤,它似乎工作得很好。但同样,我对此很陌生,所以可能只是我犯了某种菜鸟错误。任何提示将不胜感激。

在下面检查我的代码:

App.js

import React, { Component } from 'react';
import './App.css';

//Libraries
import axios from 'axios';

//Components
import SearchBar from './Components/search-bar';
class App extends Component {
  constructor(props){
    super(props);

    this.state = {
      city: 'London',
      country: 'uk',
      temperature: 0,
      humidity: 0,
      pressure: 0
    }

    //Axios call
    let city = this.state.city;
    let country = this.state.country;
    axios
      .get(`http://api.openweathermap.org/data/2.5/weather?APPID=${API_KEY}&q=${city},${country}`)
      .then(function(response) {
        this.setState({
          city: response.data.name,
          country: response.data.name,
          temperature: response.data.main.temp,
          humidity: response.data.main.humidity,
          pressure: response.data.main.pressure
        });
      }.bind(this))
      .catch(function(error) {
        console.log(error);
      });

      this.citySearch('London');
  }

  citySearch(city){
    this.setState({city})
  }

  render() {
    return (
      <div className="container">
        <h1 className="display-1 text-center">Weather App</h1>
        <SearchBar onSearchTermChange={citySearch} />
      </div>
    );
  }
}

export default App;

搜索栏组件:

import React, { Component } from 'react';

class SearchBar extends Component {
  constructor(props) {
    super(props);

    this.state = {
      city: ""
    };
  }

  render() {
    return (
      <input
        value={this.state.city}
        onChange={this.onHandleChange}
        className="form-control mt-3"
        placeholder="Enter a city name..."
        type="text"
      />
    );
  }

  onHandleChange(city) {
    this.setState({ city });
    this.props.onSearchTermChange(city);
  }
}

export default SearchBar;

【问题讨论】:

  • componentDidMount 中调用axios,而不是构造函数。你可以this.state = { city: 'London' } - 不要在那里使用 setState。
  • 你为什么要在构造函数中做所有事情

标签: javascript reactjs dom components


【解决方案1】:

要将数据从子组件传递到父组件,您必须使用回调方法。

看看这个。 (关于如何将数据从父级传递给子级,从子级传递给父级)。

我知道我没有在此处修改您的代码(很抱歉),但如果您对不同的方法感兴趣,这是可行的。

https://medium.com/@ruthmpardee/passing-data-between-react-components-103ad82ebd17

【讨论】:

    【解决方案2】:

    首先,您不应该在构造函数中进行 axios 调用。此时组件尚未安装。在 componentDidMount 中执行此操作以确保组件已安装。

    其次,您没有将 citySearch 绑定到 App 类。所以在 SearchBar 组件中,它并不知道应该从 App 类中调用 citySearch 方法。出于优化原因,建议在 App 类构造函数中进行此绑定。

    最后,我会建议你以更实用的方式编写 React,利用像 ReduxFlux 这样的状态管理框架

    下面的代码应该可以工作

    import React, { Component } from 'react';
    import './App.css';
    
    //Libraries
    import axios from 'axios';
    
    //Components
    import SearchBar from './Components/search-bar';
    class App extends Component {
      constructor(props){
        super(props);
    
        this.state = {
          city: 'London',
          country: 'uk',
          temperature: 0,
          humidity: 0,
          pressure: 0
        }
        this.citySearch = this.citySearch.bind(this);
        this.citySearch('London');
      }
    
      citySearch(city){
        this.setState({city})
      }
    
      componentDidMount() {
        //Axios call
        let {city, country} = this.state;
        axios
          .get(`http://api.openweathermap.org/data/2.5/weather?APPID=${API_KEY}&q=${city},${country}`)
          .then(function(response) {
            this.setState({
              city: response.data.name,
              country: response.data.name,
              temperature: response.data.main.temp,
              humidity: response.data.main.humidity,
              pressure: response.data.main.pressure
            });
          }.bind(this))
          .catch(function(error) {
            console.log(error);
          });
      }
    
      render() {
        return (
          <div className="container">
            <h1 className="display-1 text-center">Weather App</h1>
            <SearchBar onSearchTermChange={citySearch} />
          </div>
        );
      }
    }
    
    export default App;
    

    对于 searchBar 组件,您没有在 SearchBar 组件中绑定 onHandleChange。这将引发错误。您应该在 searchBar 构造函数中执行此操作

    constructor() {
         ...
         this.onHandleChange = this.onHandleChange.bind(this) //Very important you do this
      }
    

    【讨论】:

    • 感谢您的回答。我已经设法让它工作了。而且我同意使用 Flux/Redux 绝对是更优雅的做事方式,我刚刚开始使用 React,所以我真的想先关注核心库,然后再继续使用 Redux/Flux :)
    【解决方案3】:

    setState(...):只能更新一个挂载或挂载的组件。这 通常意味着您在未安装的组件上调用了 setState() 。这是 无操作。请检查 App 组件的代码。

    这是因为您在构造函数中调用了axios。将您的 axios 调用放入 componentDidMount 应该可以解决它

    citySearch 未定义

    这是因为 React 找不到 citySearch 函数。你应该改变

    &lt;SearchBar onSearchTermChange={citySearch} /&gt;

    &lt;SearchBar onSearchTermChange={this.citySearch} /&gt;

    为了以这种方式使用citySearch,您还应该在构造函数中绑定citySearch

    总结:

    import React, { Component } from 'react';
    import './App.css';
    
    //Libraries
    import axios from 'axios';
    
    //Components
    import SearchBar from './Components/search-bar';
    class App extends Component {
      constructor(props){
        super(props);
    
        this.state = {
          city: 'London',
          country: 'uk',
          temperature: 0,
          humidity: 0,
          pressure: 0
        }
        
        this.citySearch = this.citySearch.bind(this)
      }
      
      componentDidMount() {
        //Axios call
        let city = this.state.city;
        let country = this.state.country;
        axios
          .get(`http://api.openweathermap.org/data/2.5/weather?APPID=${API_KEY}&q=${city},${country}`)
          .then(function(response) {
            this.setState({
              city: response.data.name,
              country: response.data.name,
              temperature: response.data.main.temp,
              humidity: response.data.main.humidity,
              pressure: response.data.main.pressure
            });
          }.bind(this))
          .catch(function(error) {
            console.log(error);
          }); 
      }
    
      citySearch(city){
        this.setState({city})
      }
    
      render() {
        return (
          <div className="container">
            <h1 className="display-1 text-center">Weather App</h1>
            <SearchBar onSearchTermChange={this.citySearch} />
          </div>
        );
      }
    }
    
    export default App;

    不要在你的构造函数中调用setState,你可以像你一样初始化你的状态。所以应该删除你构造函数中原来的setState


    更新

    每次拨打citySearch时重新搜索。

    import React, { Component } from 'react';
    import './App.css';
    
    //Libraries
    import axios from 'axios';
    
    //Components
    import SearchBar from './Components/search-bar';
    class App extends Component {
      constructor(props){
        super(props);
    
        this.state = {
          city: 'London',
          country: 'uk',
          temperature: 0,
          humidity: 0,
          pressure: 0
        }
        
        this.citySearch = this.citySearch.bind(this)
      }
      
      componentDidMount() {
        axioSearch();    
      }
      
      axioSearch(city) {
        let city = city || this.state.city;
        let country = this.state.country;
        axios
          .get(`http://api.openweathermap.org/data/2.5/weather?APPID=${API_KEY}&q=${city},${country}`)
          .then(function(response) {
            this.setState({
              city: response.data.name,
              country: response.data.name,
              temperature: response.data.main.temp,
              humidity: response.data.main.humidity,
              pressure: response.data.main.pressure
            });
          }.bind(this))
          .catch(function(error) {
            console.log(error);
          });   
      }
    
      citySearch(city){
        this.axioSearch(city);
      }
    
      render() {
        return (
          <div className="container">
            <h1 className="display-1 text-center">Weather App</h1>
            <SearchBar onSearchTermChange={this.citySearch} />
          </div>
        );
      }
    }
    
    export default App;

    【讨论】:

    • 现在我遇到了另一个问题。每当我尝试输入我的输入并 console.log 它时,[object Object] 就会在输入中弹出,并且我会在控制台中返回某种代理对象(我读到这是一个“合成事件”)。但是,我的应用状态仍然没有改变。
    • 在您的SearchBar 组件中,参数应该是来自input 的事件。要从事件中获取值,您可以使用e.target.value。所以把你的onHandleChange改成onHandleChange(env) { const city = env.currentTarget.value; this.setState(...); ...; }
    • 看来我快到了!我唯一剩下的就是每次我用数据填充输入字段时重复 axios 请求。因为现在,当我输入内容时,它只会更改该州的城市名称,但不会再次触发请求以从 API 中提取正确的数据。
    • @TommyVee:每次调用 citySearch 时再次获取 API 的脏更新。请务必修改它以适合您的应用程序。希望你能明白。
    • 再次感谢您的快速回复!非常欣赏它。我收到一个错误'第 30 行:'axioSearch' 未定义 no-undef' 这通常发生在我忘记在某处绑定 'this' 时......知道这可能来自哪里吗?
    【解决方案4】:

    你只是在构造函数中设置状态。如果您想拨打电话,可以拨打componentWillMount()componentDidMount()

    import React, { Component } from 'react';
    import './App.css';
    
    //Libraries
    import axios from 'axios';
    
    //Components
    import SearchBar from './Components/search-bar';
    class App extends Component {
      constructor(props){
        super(props);
    
        this.state = {
          city: 'London',
          country: 'uk',
          temperature: 0,
          humidity: 0,
          pressure: 0
        }
      }
    
      citySearch(city){
        this.setState({city})
      }
    
      componentWillMount(){
        //Axios call
        let city = this.state.city;
        let country = this.state.country;
        axios
          .get(`http://api.openweathermap.org/data/2.5/weather?APPID=${API_KEY}&q=${city},${country}`)
          .then(function(response) {
            this.setState({
              city: response.data.name,
              country: response.data.name,
              temperature: response.data.main.temp,
              humidity: response.data.main.humidity,
              pressure: response.data.main.pressure
            });
          }.bind(this))
          .catch(function(error) {
            console.log(error);
          });
    
          this.citySearch('London');
      }
    
      render() {
        return (
          <div className="container">
            <h1 className="display-1 text-center">Weather App</h1>
            <SearchBar onSearchTermChange={citySearch} />
          </div>
        );
      }
    }
    
    export default App;
    

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 2019-01-04
      • 2017-03-11
      • 1970-01-01
      • 1970-01-01
      • 2021-03-13
      • 2021-10-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多