Axios post method in react isn't working: suggestions? - reactjs

I'm trying to update a database with a user's text input, and it isn't working, even after trying a bunch of different approaches.
The text input is controlled by the following component:
import React from 'react'
class Dogue extends React.Component {
constructor(props){
super(props)
this.state = {
id: '',
nameInput:''
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(e) {
this.setState({
id: Date.now(),
nameInput: e.target.value
})
}
handleSubmit(e){
e.preventDefault()
this.props.inputFunction(this.state.nameInput, this.state.id)
}
render(){
console.log(this.props.id)
return (
<div className = 'dogue-container'>
<img className = 'img' src = {this.props.dogList}/>
<br/>
<form onSubmit = {this.handleSubmit} className = 'form'>
<input
onChange ={this.handleChange}
className ='input'
type = 'text'
placeholder = 'Enter dog name'
/>
<br/>
<button className = 'button'>Submit</button>
</form>
<h2 className = 'text'>Name: {this.props.name} </h2>
</div>
)
}
}
export default Dogue
and the state update and post is controlled by the App component:
import React, { Component } from "react";
import './styles.css'
import DogList from "./DogList";
import axios from "axios";
class App extends React.Component {
constructor() {
super();
this.state = {
loading: false,
dog: [],
dogName: [],
newName:''
};
this.updateStateWithInput = this.updateStateWithInput.bind(this)
}
setData = async () => {
const x = await fetch("https://dog.ceo/api/breed/hound/images");
const y = await x.json();
const z = await y.message;
let newArr = [];
for (let i = 0; i < z.length; i++) {
if (i <= 9) {
newArr.push(z[i]);
}
}
return newArr;
};
async componentDidMount() {
this.setState({
loading: true
});
let dogPromise = await this.setData();
let dogNamePromise = await axios.get('http://localhost:3000/dogs');
this.setState({
loading: false,
dog: dogPromise,
dogName: dogNamePromise.data
});
}
//Here is the function to update state and make axios post
async updateStateWithInput (nameInput,id) {
let newDog={id:id, dogName:nameInput}
this.setState({
dogName: this.state.dogName.push(newDog)
})
await axios.post('http://localhost:3000/dogs', this.state.dogName)
.then(res => {
console.log(res)
})
}
render() {
return this.state.loading ? (
<h1 className = 'text'> Dogues Loading.....</h1>
) : (
<div>
<h1 className = 'text'>Rate My Dogue</h1>
<DogList
dogs={this.state.dog}
name={this.state.dogName}
inputFunction = {this.updateStateWithInput}
/>
</div>
);
}
}
export default App
Basically, all I'm trying to do is update an array of objects, with a new object - example as follows:
//existing array:
[
{
id: 1,
dogName: 'bruce',
},
{
id: 2,
dogName: 'borker',
},
{
id: 3,
dogName: 'henry',
},
];
//new object to be pushed into array:
{id: id of some sort, dogName: the text input from the user}

Either you use await or use then, cannot use both:
const res = await axios.post('http://localhost:3000/dogs', this.state.dogName);
console.log(res)

Related

Sending 'sent' data from a page to a component in Gatsby

I have state data in my index.js page that is being sent to my details.js page via the Link component built into gatsby. From my details.js page, I am trying to send data to my component ChartData.js.
In details.js I can access my information by using {props.location.state.x}. Now I need the same data to be sent to my component and what I did was put Stock (Stock is the class name in ChartData.js) the comonent and set 'symbol' equal to the way I would reference data just like this: {<Stock symbol={props.location.state.symbol}/>}
Now under ChartData/.js when I try to reference symbol I get the error 'symbol is not defined'. Not sure if I am messing up the syntax of passing it or if you cannot do it this way.
index.js:
import React from "react"
import { Link } from "gatsby"
import axios from "axios"
import "../css/style.css"
import Layout from "../components/layout"
import { symbol } from "prop-types"
//import Stock from "../components/ChartData"
//import Characters from "../components/ChartData"
export default class index extends React.Component {
state = {
companyName: "",
previousClose: "",
marketCap: "",
change: "",
symbol: "",
topStocks: [],
Yearweekhigh: "",
Yearweeklow: "",
avgTotalVolume: "",
peRatio: "",
}
clickHandler = (event) => {
if (event.keyCode === 13) {
const query = event.target.value;
const API_KEY = '******************';
axios.get(`https://cloud.iexapis.com/stable/stock/${query}/quote?token=${API_KEY}`)
.then(res => {
const companyName = res.data['companyName'];
this.setState({ companyName })
const previousClose = res.data['previousClose'];
this.setState({ previousClose })
const marketCap = res.data['marketCap'];
this.setState({ marketCap })
const change = res.data['change'];
this.setState({ change })
const symbol = res.data['symbol'];
this.setState({ symbol })
const Yearweekhigh = res.data['week52High'];
this.setState({ Yearweekhigh })
const Yearweeklow = res.data['week52Low'];
this.setState({ Yearweeklow })
const avgTotalVolume = res.data['avgTotalVolume'];
this.setState({ avgTotalVolume })
const peRatio = res.data['peRatio'];
this.setState({ peRatio })
const open = res.data['open'];
this.setState({ open })
const high = res.data['high'];
this.setState({ high })
const low = res.data['low'];
this.setState({ low })
const volume = res.data['volume'];
this.setState({ volume })
})
}
}
render() {
return (
<Layout>
<div class = "main-div">
<input type="search" class="main-search" onKeyDown={event => this.clickHandler(event)}/>
<table>
<tr>
<th>Ticker-Symbol</th>
<th>Market Cap</th>
<th>Previous Close</th>
</tr>
<tr>
<td>
<Link to='/details/' state={{
setState: this.state.symbol,
companyName: this.state.companyName,
previousClose: this.state.previousClose,
marketCap: this.state.marketCap,
change: this.state.change,
Yearweekhigh: this.state.Yearweekhigh,
Yearweeklow: this.state.Yearweeklow,
avgTotalVolume: this.state.avgTotalVolume,
peRatio: this.state.peRatio,
open: this.state.open,
high: this.state.high,
low: this.state.low,
volume: this.state.volume,
symbol: this.state.symbol
}}>
{this.state.symbol}</Link>
</td>
<td>{this.state.marketCap}</td>
<td>{this.state.previousClose}</td>
</tr>
</table>
</div>
<div>
{
this.state.topStocks.length && this.state.topStocks.map(stock => (
<h1>{stock.symbol}</h1>
))
}
</div>
</Layout>
)
}
}
details.js
//import { Link } from "gatsby"
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import Layout from '../components/layout';
import "../css/style.css"
import Stock from "../components/ChartData"
const Details = props => {
const [yourState, setYourState] = useState('');
useEffect(() => {
}, []);
return <Layout>
<div>
<h1 class="details-company-name">{props.location.state.companyName}</h1>
<div class = "details-div">
<div class="details-div-1">
<p>Open <h2>{props.location.state.open}</h2> </p>
<p>High <h2>{props.location.state.high}</h2> </p>
<p>Low <h2>{props.location.state.low}</h2> </p>
<p>52 WK HIGH <h2>{props.location.state.Yearweekhigh}</h2> </p>
<p>52 WK LOW <h2>{props.location.state.Yearweeklow}</h2> </p>
<p>{props.location.state.symbol}</p>
</div>
<div class="details-div-2">
<p>VOLUME <h2>{props.location.state.volume}</h2></p>
<p>AVG VOL <h2>{props.location.state.avgTotalVolume}</h2> </p>
<p>MKT CAP <h2>{props.location.state.marketCap}</h2></p>
<p>P/E RATIO <h2>{props.location.state.peRatio}</h2></p>
<p>DIV/YIELD</p>
</div>
</div>
</div>
<Stock symbol={props.location.state.symbol}/>
</Layout>;
};
export default Details;
ChartData.js
import React from 'react'
import Plot from 'react-plotly.js'
class Stock extends React.Component {
constructor(props) {
super(props);
this.state = {
stockChartXValues: [],
stockChartYValues: [],
};
}
componentDidMount() {
this.fetchStock();
}
fetchStock() {
const pointerToThis = this;
const API_KEY = '*****************';
let API_CALL = `https://cloud.iexapis.com/stable/${symbol}/aapl/chart/5y?token=${API_KEY}`;
let stockChartXValuesFunction = [];
let stockChartYValuesFunction = [];
fetch(API_CALL)
.then(function (response) {
return response.json();
})
.then(function (data) {
for (var x in data) {
stockChartXValuesFunction.push(x);
stockChartYValuesFunction.push(
data[x]['uOpen']
);
pointerToThis.setState({
stockChartXValues: stockChartXValuesFunction,
stockChartYValues: stockChartYValuesFunction,
});
}
})
}
render() {
return (
<div>
<Plot
data={[
{
x: this.state.stockChartXValues,
y: this.state.stockChartYValues,
type: "scatter",
mode: "lines+markers",
marker: {color: "red"}
},
]}
layout={{ width: 720, height: 440, title: "A Fancy Plot"}}
/>
</div>
)
}
}
export default Stock
You have a few issues there:
Everything you pass through props must be received by the child component accessing to those props. So instead of symbol, you must this.props.symbol. Since you are not destructuring your props:
let API_CALL =
`https://cloud.iexapis.com/stable/${this.props.symbol}/aapl/chart/5ytoken=${API_KEY}`;
To avoid wrong or empty calls, I would ensure that you have your props properly set and I would add a condition like:
componentDidMount() {
if(props.symbol) this.fetchStock();
}
You may need to add a constructor in your file to gather props:
constructor(props) {
super(props);
this.state = {}; // remove if not needed
}

How to make an axios POST request in React?

So, some context: Users submit a dog name via a text input, and this is controlled by the 'Dogue.jsx' component:
import React from 'react';
class Dogue extends React.Component {
constructor(props) {
super(props);
this.state = {
id: props.id,
nameInput: '',
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({
nameInput: e.target.value,
});
}
handleSubmit(e) {
e.preventDefault();
this.props.inputFunction(this.state.nameInput);
}
render() {
console.log(this.props.id);
return (
<div className="dogue-container">
<img className="img" src={this.props.dogList} />
<br />
<form onSubmit={this.handleSubmit} className="form">
<input
onChange={this.handleChange}
className="input"
type="text"
placeholder="Enter dog name"
/>
<br />
<button className="button">Submit</button>
</form>
<h2 className="text">Name: {this.props.name} </h2>
</div>
);
}
}
export default Dogue;
The submitted information is then passed to 'App.jsx', where it is used to update state:
import React, {Component} from 'react';
import './styles.css';
import DogList from './DogList';
import axios from 'axios';
class App extends React.Component {
constructor() {
super();
this.state = {
loading: false,
dog: [],
dogName: [],
};
this.updateStateWithInput = this.updateStateWithInput.bind(this);
}
setData = async () => {
const x = await fetch('https://dog.ceo/api/breed/hound/images');
const y = await x.json();
const z = await y.message;
let newArr = [];
for (let i = 0; i < z.length; i++) {
if (i <= 9) {
newArr.push(z[i]);
}
}
return newArr;
};
async componentDidMount() {
this.setState({
loading: true,
});
let dogPromise = await this.setData();
let dogNamePromise = await axios.get('http://localhost:3000/dogs');
this.setState({
loading: false,
dog: dogPromise,
dogName: dogNamePromise.data,
});
}
updateStateWithInput(nameInput) {
//Here is where state is updated.
//change state, then use axios.post to submit data
}
render() {
return this.state.loading ? (
<h1 className="text"> Dogues Loading.....</h1>
) : (
<div>
<h1 className="text">Rate My Dogue</h1>
<DogList
dogs={this.state.dog}
name={this.state.dogName}
inputFunction={this.updateStateWithInput}
/>
</div>
);
}
}
export default App;
The updated state, I imagine, will be used in the axios post request to submit data to the database. So, I've got input data being sent from Dogue to App, I'm just not sure what to do now? The information currently in state looks as follows:
[
{
id: 1,
dogName: 'bruce',
},
{
id: 2,
dogName: 'borker',
},
{
id: 3,
dogName: 'henry',
},
];
I should also show my map function, in DogList.jsx:
import React from 'react';
import Dogue from './Dogue';
const DogList = (props) => {
return (
<div className="img-container">
{props.dogs.map((doggie, index) => {
return (
<Dogue
id={props.name[index] && props.name[index].id}
key={index}
dogList={doggie}
name={props.name[index] && props.name[index].dogName}
inputFunction={props.inputFunction}
/>
);
})}
</div>
);
};
export default DogList;
You can send a POST request with axios by calling:
axios.post(url, data, options);
It’s similar to the way you called the get method to make a GET request.
I’m leaving this axios cheat sheet here since it’s really useful until you get the hang of it:
https://kapeli.com/cheat_sheets/Axios.docset/Contents/Resources/Documents/index

I think render works twice

I'm only learning React, trying to write a simple TODO list app. When I'm trying to add a new task, two identical tasks are added. I tried to debug by the console.log element and saw a problem. render works twice, so my button sends info to the function twice. Can someone please guide me to the solution? Here is the code.
import React from 'react';
class TaskInput extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ''
};
}
addTask = () => {
const { input } = this.state;
if (input) {
this.props.addTask(input);
this.setState({ input: '' });
}
};
handleEnter = event => {
if (event.key === 'Enter') this.addTask();
};
inputChange = event => {
this.setState({ input: event.target.value });
};
render() {
const { input } = this.state;
console.log(this.state);
return (
<div className="task-input">
<input
type="text"
onKeyPress={this.handleEnter}
onChange={this.inputChange}
value={input}
></input>
<button onClick={this.addTask } >ADD</button>
</div>
);
}
}
export default TaskInput;
Here is the App.js code:
import React from 'react';
import Task from './components/Task';
import TaskInput from './components/TaskInput';
class App extends React.Component {
constructor () {
super();
this.state = {
tasks: [
{id: 0, title: 'Create Todo-app', done: false},
{id: 1, title: 'Do smth else', done: true},
{id: 2, title: 'Do more things', done: false}
]
};
}
addTask = task => {
this.setState(state => {
let {tasks} = state;
console.log("state");
tasks.push({
id: tasks.length !==0 ? tasks.length : 0,
title: task,
done: false
});
return tasks;
});
}
doneTask = id => {
const index = this.state.tasks.map(task => task.id).indexOf(id);
this.setState(state => {
let {tasks} = state;
tasks[index].done = true;
return tasks;
});
};
deleteTask = id => {
const index = this.state.tasks.map(task => task.id).indexOf(id);
this.setState(state => {
let {tasks} = state;
delete tasks[index];
return tasks;
})
};
render() {
const { tasks } = this.state;
const activeTasks = tasks.filter(task => !task.done);
const doneTasks = tasks.filter(task => task.done)
return (
<div className = "App">
<h1 className="top">Active tasks: {activeTasks.length}</h1>
{[...activeTasks, ...doneTasks].map(task => (
<Task
doneTask={() => this.doneTask(task.id)}
deleteTask={() => this.deleteTask(task.id)}
task={task}
key={task.id}
></Task>))}
<TaskInput addTask={this.addTask}></TaskInput>
</div>
);
}
}
export default App;
I think you are accidentally directly modifying the state inside addTask.
The line let {tasks} = state; is creating a reference to the original state, rather than a new copy, and then your push modifies the state directly.
Using expansion/spread syntax to get a copy of your array like this should work:
addTask = task => {
this.setState(state => {
const tasks = [ ...state.tasks ];
tasks.push({
id: tasks.length !==0 ? tasks.length : 0,
title: task,
done: false
});
return { tasks };
});
}
Using let tasks = [ ...state.tasks ]; will create a new array rather than a reference, and prevent the state from being modified directly.
The reason you were seeing double results was that you effectively set the state with the push, and then set it again with the returned value.
I've changed your code a little bit. It's working here. Would you please check?
class TaskInput extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "",
tasks: []
};
}
addTask = newTask => {
this.setState(state => ({
...state,
input: "",
tasks: [...state.tasks, newTask]
}));
};
handleEnter = event => {
if (event.key === "Enter") this.addTask(event.target.value);
};
inputChange = event => {
this.setState({ input: event.target.value });
};
render() {
const { input } = this.state;
console.log(this.state);
return (
<div className="task-input">
<input
onKeyPress={this.handleEnter}
onChange={this.inputChange}
value={input}
></input>
<button onClick={this.addTask}>ADD</button>
</div>
);
}
}
ReactDOM.render(<TaskInput/>, document.querySelector("#root"));
.as-console-wrapper {
max-height: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

React App Rendering Before Firestore Data Has Loaded

I am trying to load data from Firestore and show it in the gantt-chart, but it renders before it has loaded the data from firebase. So I call setState inside of componentDidMount because I thought this would then call the render again at which point the data would be there. But it is still sitting empty. Any ideas as to why?
import React, { Component } from 'react';
import Gantt from './Gantt';
import Toolbar from './Toolbar';
import MessageArea from './MessageArea';
import Firebase from './Firebase';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
currentZoom: 'Days',
messages: [],
projects: [],
links: []
};
this.handleZoomChange = this.handleZoomChange.bind(this);
this.logTaskUpdate = this.logTaskUpdate.bind(this);
this.logLinkUpdate = this.logLinkUpdate.bind(this);
}
componentDidMount() {
const db = Firebase.firestore();
var projectsArr = [];
db.collection('projects').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
let project = doc.data();
projectsArr.push({id: 1, text: project.name, start_date: '15-04-2017', duration: 3, progress: 0.6});
});
});
this.setState({
projects: projectsArr
});
}
addMessage(message) {
var messages = this.state.messages.slice();
var prevKey = messages.length ? messages[0].key: 0;
messages.unshift({key: prevKey + 1, message});
if(messages.length > 40){
messages.pop();
}
this.setState({messages});
}
logTaskUpdate(id, mode, task) {
let text = task && task.text ? ` (${task.text})`: '';
let message = `Task ${mode}: ${id} ${text}`;
this.addMessage(message);
}
logLinkUpdate(id, mode, link) {
let message = `Link ${mode}: ${id}`;
if (link) {
message += ` ( source: ${link.source}, target: ${link.target} )`;
}
this.addMessage(message)
}
handleZoomChange(zoom) {
this.setState({
currentZoom: zoom
});
}
render() {
var projectData = {data: this.state.projects, links: this.state.links};
return (
<div>
<Toolbar
zoom={this.state.currentZoom}
onZoomChange={this.handleZoomChange}
/>
<div className="gantt-container">
<Gantt
tasks={projectData}
zoom={this.state.currentZoom}
onTaskUpdated={this.logTaskUpdate}
onLinkUpdated={this.logLinkUpdate}
/>
</div>
<MessageArea
messages={this.state.messages}
/>
</div>
);
}
}
export default App;
You are calling setState outside of the then callback.
So Change
db.collection('projects').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
let project = doc.data();
projectsArr.push({id: 1, text: project.name, start_date: '15-04-2017', duration: 3, progress: 0.6});
});
});
this.setState({
projects: projectsArr
});
To
db.collection('projects').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
let project = doc.data();
projectsArr.push({id: 1, text: project.name, start_date: '15-04-2017', duration: 3, progress: 0.6});
});
this.setState({
projects: projectsArr
});
});
Also, as a general pattern you can do something like this:
class AsyncLoad extends React.Component {
state = { data: null }
componentDidMount () {
setTimeout(() => {
this.setState({ data: [1, 2, 3]})
}, 3000)
}
render () {
const { data } = this.state
if (!data) { return <div>Loading...</div> }
return (
<pre>{JSON.stringify(data, null, 4)}</pre>
)
}
}
It's a common enough operation to create an HOC for it.

How to rerender one sibling component due to change of second sibling component

I have this structure:
<Filter>
<Departure setDeparture={this.setDeparture} />
<Destination setDestination={this.setDestination} iataDeparture={this.state.departure} />
<DatePicker setDates={this.setDates} />
<SearchButton />
</Filter>
Now, I try to rerender Destination component when I update Departure component. Unfortunatelly my code doesn't work.
I don't use redux because I don't know it yet, so I try solutions without redux.
Please, help me with this problem.
Here goes code for each component:
Filter:
import React, { Component } from 'react';
import axios from 'axios';
import Departure from './Departure';
import Destination from './Destination';
import DatePicker from './DatePicker';
import SearchButton from './SearchButton';
class Filter extends Component {
constructor(props) {
super(props);
this.state = {
departure: '',
destination: '',
startDate: '',
endDate: '',
flights: []
}
}
handleSubmit = event => {
const getFlights = `https://murmuring-ocean-10826.herokuapp.com/en/api/2/flights/from/${this.state.departure}/to/${this.state.destination}/${this.state.startDate}/${this.state.endDate}/250/unique/?limit=15&offset-0`;
event.preventDefault();
console.log(this.state.departure);
console.log(this.state.destination);
console.log(this.state.startDate);
console.log(this.state.endDate);
axios.get(getFlights)
.then(response => {
this.setState({ flights: response.data.flights });
console.log(getFlights);
console.log(this.state.flights);
this.props.passFlights(this.state.flights);
});
}
setDeparture = departure => {
this.setState({ departure: departure });
}
setDestination = destination => {
this.setState({ destination: destination });
}
setDates = (range) => {
this.setState({
startDate: range[0],
endDate: range[1]
});
}
render() {
return (
<section className='filter'>
<form className='filter__form' onSubmit={this.handleSubmit}>
<Departure setDeparture={this.setDeparture} />
<Destination setDestination={this.setDestination} iataDeparture={this.state.departure} />
<DatePicker setDates={this.setDates} />
<SearchButton />
</form>
</section>
);
}
}
export default Filter;
Departure:
import React, { Component } from 'react';
import axios from 'axios';
const url = 'https://murmuring-ocean-10826.herokuapp.com/en/api/2/forms/flight-booking-selector/';
class Departure extends Component {
constructor(props) {
super(props);
this.state = {
airports: [],
value: '',
iataCode: ''
}
}
componentDidMount() {
axios.get(url)
.then(data => {
const airports = data.data.airports;
const updatedAirports = [];
airports.map(airport => {
const singleAirport = [];
singleAirport.push(airport.name);
singleAirport.push(airport.iataCode);
updatedAirports.push(singleAirport);
return singleAirport;
});
this.setState({
airports: updatedAirports,
value: airports[0].name,
iataCode: airports[0].iataCode
});
this.props.setDeparture(this.state.iataCode);
});
}
handleChange = event => {
const nameValue = event.target.value;
const iataCode = this.state.airports.find(airport => {
return airport[0] === nameValue;
});
this.setState({
value: event.target.value,
iataCode: iataCode[1]
});
this.props.setDeparture(iataCode[1]);
}
render() {
const departureNames = this.state.airports;
let departureOptions = departureNames.map((item, index) => {
return (
<option value={item[0]} key={index}>{item[0]}</option>
);
});
return (
<div className='filter__form__select'>
<select value={this.state.value} onChange={this.handleChange}>
{departureOptions}
</select>
</div>
);
}
}
export default Departure;
Destination:
import React, { Component } from 'react';
import axios from 'axios';
const url = 'https://murmuring-ocean-10826.herokuapp.com/en/api/2/forms/flight-booking-selector/';
class Destination extends Component {
constructor(props) {
super(props);
this.state = {
routes: {},
airports: [],
value: '',
iataCode: '',
iataDestinationAirports: '',
options: []
}
}
componentDidMount() {
axios.get(url)
.then(data => {
const routes = data.data.routes;
const airports = data.data.airports;
const updatedAirports = [];
airports.map(airport => {
const singleAirport = [];
singleAirport.push(airport.name);
singleAirport.push(airport.iataCode);
updatedAirports.push(singleAirport);
return singleAirport;
});
this.setState({
routes: routes,
airports: updatedAirports,
});
})
.then(() => {
this.getNamesFromIataCode();
this.props.setDestination(this.state.iataDestinationAirports);
});
}
componentDidUpdate(prevProps) {
if (this.props.iataDeparture !== prevProps.iataDeparture) {
this.setState({ iataCode: this.props.iataDeparture });
() => this.getNamesFromIataCode();
};
}
handleChange = (event) => {
const nameValue = event.target.value;
const iataCode = this.state.airports.find(airport => {
return airport[0] === nameValue;
});
this.setState({
value: event.target.value,
iataDestinationAirports: iataCode[1]
});
this.props.setDestination(iataCode[1]);
}
getNamesFromIataCode = () => {
const iataCode = this.state.iataCode;
console.log(iataCode);
const destinationNames = this.state.routes[iataCode];
let destionationAirports = destinationNames.map(item => {
return this.state.airports.filter(el => {
return el[1] === item;
});
});
let arrayOfOptions = [];
let firstOptionIataCode = '';
let firstOptionName = '';
let destinationOptions = destionationAirports.map((item, index) => {
console.log(item);
arrayOfOptions.push(item[0]);
return (
<option value={item[0][0]} key={index}>{item[0][0]}</option>
);
});
firstOptionIataCode = arrayOfOptions[0][1];
firstOptionName = arrayOfOptions[0][0];
console.log(firstOptionIataCode);
this.setState({
options: destinationOptions,
iataDestinationAirports: firstOptionIataCode,
value: firstOptionName
});
console.log(this.state.iataDestinationAirports);
console.log(this.state.options);
return destinationOptions;
}
render() {
const selectionOptions = this.state.options;
return (
<div className='filter__form__select'>
<select value={this.state.value} onChange={this.handleChange}>
{selectionOptions}
</select>
</div>
);
}
}
export default Destination;
As Tholle mentioned, you need to lift the state up. Here's an example:
import React from "react";
import ReactDOM from "react-dom";
const A = ({ users, selectUser }) => {
return (
<React.Fragment>
<h1>I am A.</h1>
{users.map((u, i) => {
return <button onClick={() => selectUser(i)}>{u}</button>;
})}
</React.Fragment>
);
};
const B = ({ user }) => {
return <h1>I am B. Current user: {user}</h1>;
};
const C = ({ user }) => {
return <h1>I am C. Current user: {user}</h1>;
};
class App extends React.Component {
state = {
users: ["bob", "anne", "mary"],
currentUserIndex: 0
};
selectUser = n => {
this.setState({
currentUserIndex: n
});
};
render() {
const { users, currentUserIndex } = this.state;
const currentUser = users[currentUserIndex];
return (
<React.Fragment>
<A selectUser={this.selectUser} users={users} />
<B user={currentUser} />
<C user={currentUser} />
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Working example here.

Resources