2017-09-07 4 views
0

Ceci est mon premier essai dans une application React simple. Travailler avec l'API Openweather et AXIOS. J'ai suivi le cours de Stephen Grider sur Udemy et j'essaie de créer quelque chose par moi-même maintenant, mais j'ai toujours des problèmes lors de la transmission de données entre les composants. J'ai un composant SearchBar et j'aimerais pouvoir passer la valeur d'entrée à l'état du composant parent, donc je peux le mettre à jour avec chaque recherche et le rendre dans le DOM. Cependant, je continue à courir dans les erreurs. J'ai essayé de passer une fonction comme accessoire à mon composant SearchBar mais j'obtiens des erreurs:Réagir - transmettre des données entre les composants

setState (...): Ne peut mettre à jour qu'un composant monté ou monté. Cela signifie généralement que vous avez appelé setState() sur un composant non monté. C'est un no-op. Veuillez vérifier le code du composant App.

Citysearch n'est pas défini

Ceci est source de confusion pour moi, comme je l'ai essayé de copier les étapes exactes du cours, où il semble fonctionner très bien. Mais encore une fois, je suis très nouveau à ce sujet, donc c'est probablement juste moi faire une sorte d'erreur de débutant. Tous les conseils seraient très appréciés.

Vérifiez mon code ci-dessous:

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; 

Monocomposant de SearchBar:

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; 
+1

les axios appellent 'componentDidMount', pas le constructeur. vous pouvez juste 'this.state = {city: 'London'}' - n'utilisez pas setState ici. –

+0

pourquoi faites-vous tout dans le constructeur –

Répondre

0

setState (...): Ne peut mettre à jour un composant monté ou montage. Ce signifie généralement que vous appelez setState() sur un composant démonté. C'est un no-op. Veuillez vérifier le code du composant App.

Ceci est dû à votre appel axios dans le constructeur. Mettez votre appel en Axios componentDidMount devrait résoudre

Citysearch n'est pas défini

Il est parce que React ne peut pas trouver citySearch fonction.Vous devez changer

<SearchBar onSearchTermChange={citySearch} />

à

<SearchBar onSearchTermChange={this.citySearch} />

Pour utiliser citySearch cette façon, vous devez également lier citySearch dans votre constructeur

En résumé:

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;

Ne pas appeler setState dans votre constructeur, vous pouvez simplement initialiser votre état comme votre fait. Donc le setState original dans votre constructeur devrait être supprimé.


MISE À JOUR

Pour rechercher à nouveau chaque fois que vous appelez 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;

+0

Cela a fonctionné parfaitement! Merci de votre aide ! – TommyVee

+0

Maintenant, je suis confronté à un autre problème. Chaque fois que j'essaie de taper dans mon entrée et console.log, [objet objet] apparaît dans l'entrée, et je récupère un objet proxy dans la console (j'ai lu qu'il s'agit d'un 'événement synthétique'). Cependant, l'état de mon application ne change toujours pas. – TommyVee

+0

Dans votre composant 'SearchBar', le paramètre doit être un événement de' input'. Pour obtenir la valeur de l'événement, vous pouvez utiliser 'e.target.value'. Donc changez votre 'onHandleChange' en' onHandleChange (env) {const ville = env.currentTarget.value; this.setState (...); ...; } ' –

0

Vous venez setState dans le constructeur. Si vous voulez faire un appel, vous pouvez le mettre dans componentWillMount() ou 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; 
0

D'abord, vous ne devriez pas faire vos appels Axios dans le constructeur. Le composant n'est pas encore monté à ce stade. Faites cela dans un componentDidMount pour vous assurer que le composant est déjà monté. Secodly, vous n'avez pas lié citySearch à la classe App. Donc, dans le composant SearchBar, il ne sait pas que la méthode citySearch doit être appelée depuis la classe App. Il est conseillé de faire cette liaison dans le constructeur de la classe App pour des raisons d'optimisation.

Enfin, je vous conseille d'écrire React en tirant parti de manière plus fonctionnelle des cadres de gestion de l'État comme Redux ou Flux

Le code ci-dessous devrait fonctionner

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; 

Pour le composant SearchBar, vous n » t lie onHandleChange dans le composant SearchBar. Cela va jeter des erreurs. Vous devriez le faire dans le constructeur searchBar

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

Merci pour votre réponse. J'ai réussi à le faire fonctionner déjà. Et je suis d'accord sur le fait que l'utilisation de Flux/Redux est vraiment une façon plus élégante de faire des choses, je commence juste avec React donc je veux vraiment me concentrer sur la bibliothèque principale avant de passer à Redux/Flux :) – TommyVee