how to make api call using props - reactjs

im trying to make an api call in one component using state from a different component , however when i use props in the API call im getting an error saying cannot read property props of undefined. basicly im trying to make an api call using data from a different component in then display it in the main component , but am not sure how to do it. Can someone pls tell me what im doing wrong ? thanks for the help!
class App extends Component {
constructor() {
super();
this.state = {
places2: [] ,
isLoaded2: true,
isLoaded: true,
latitude: 37.774929,
longitude: -122.419416,
};
// this is the data i want to pass
geocodeByAddress(address)
.then(res => getLatLng(res[0]))
.then(({ lat, lng }) => {
this.setState({
latitude: lat,
longitude: lng,
});
})
.catch(error => {
this.setState({ isGeocoding: false });
console.log('error', error); // eslint-disable-line no-console
});
}
render() {
return (
<div id="h">
{this.state.isLoaded ?
<Health
latitude={this.state.latitude}
longitude={this.state.longitude}
parentMethod={this.parentMethod}
parentMethod2={this.parentMethod2}
/>
: <div>.</div>}
<Map center= {{lat: this.state.latitude, lng: this.state.longitude}}/>
{this.state.isLoaded ?
<div id="location-basic-info" >
<UserForm
address={this.state.address}
Latitude={this.state.latitude}
Longitude={this.state.longitude}
/>
</div> : <div>.</div>}
{this.state.isLoaded2 ?
<Health
latitude={this.state.latitude}
longitude={this.state.longitude}
parentMethod={this.parentMethod}
parentMethod2={this.parentMethod2}
/>
: <div>.</div>}
{this.state.isLoaded2 ?
<div id="location-basic-info" >
<div> {this.state.place} {this.state.places2} </div>
</div> : <div>.</div>}
</div>
<div>
</div>
</div>
);
}
};
export default App;
health.js
class Health extends Component {
constructor() {
super();
this.state = {
zoom: 13,
maptype: 'roadmap',
place_formatted: '',
place_id: '',
place_location: '',
address: '',
latitude: 37.774929,
longitude: -122.419416,
marker:[],
places: [], isLoaded: false,
places2: []
};
}
getplace(){
var param = {
//this is giving me the error
lat: this.props.latitude,
long: this.props.longitude,
temp:1
}
axios.post(`http://localhost:5000/search-champ`, {
param
}).then((data)=>{
this.setState({places: data});
console.log( this.state.places);
console.log(data);
const places = data.data.data[0].results.slice(0,10).map((place) => {
console.log(place.name)
console.log(place.geometry.location.lat)
console.log(place.geometry.location.lng)
let name = place.name;
let vicinity= place.vicinity;
return <div class="col-xs-6 col-sm-6">
<ul id="places-list">
<li><a onClick={() => this.hello(name, vicinity)}> {place.name} </a> </li>
</ul>
</div>
})
console.log('places', places);
const places2 = data.data.data[1].results.slice(0,10).map((place) => {
console.log(place.name)
console.log(place.geometry.location.lat)
console.log(place.geometry.location.lng)
let name = place.name;
let vicinity= place.vicinity;
return <div class="col-xs-6 col-sm-6">
<ul id="places-list">
<li><a onClick={() => this.hello(name, vicinity)}> {place.name} </a> </li>
</ul>
</div>
});
this.setState({ place: places , isLoaded: true});
this.setState({ places2: places2 , isLoaded: true});
})
}
render(){
return(
<div>
<ul class="nav nav-pills" id="f">
<li class="active" onClick={this.props.parentMethod}> Info</li>
<li onClick={this.props.parentMethod2}>Food</li>
<li onClick={this.getplace}>Health</li>
<li>Menu 3</li>
</ul>
{this.state.isLoaded2 ?
<div id="location-basic-info" >
<div> {this.state.places} {this.state.places2} </div>
</div> : <div>.</div>}
</div>
);
}};
export default Health;

Your call to the api must be in the componentDidMount method.
componentDidMount: This method is called once all our children Elements and our Component instances are mounted onto the Native UI
Simple life cycle:
class Example extends React.Component {
constructor()
{
console.log('constructor')
}
componentWillMount()
{
console.log('Pre-mounting ')
}
componentDidMount()
{
console.log('Post-mounting ')
//TODO: call api axios or fetch
}
render()
{
console.log('render ui')
return(....)
}
}
Also i saw something like that in your code:
render() {
// BAD: Do not do this!
this.setState({ place: places , isLoaded: true});
this.setState({ places2: places2 , isLoaded: true});
}
Happy coding!

Related

How to pass data from component to another component

I'm trying to pass some data (response of fetch to API) from a component to another component, but I don't find the way to pass them.
In the Class AddresForm, I get the serialized data from form, this data is send to API with fecth method. The response has important information and I need use this information contained on response in another component.
class AddressForm extends React.Component{
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.validatePredio = this.validatePredio.bind(this);
this.state = {
isApartment: false,
required: false
};
this.cities = [];
this.cities.push(["11001" ,"XXX"]);
this.cities.push(["05001", "YYY"]);
this.cities.push(["76001", "ZZZ"]);
}
handleSubmit(event) {
event.preventDefault();
const data = serialize(event.target, { hash: true });
data['direccion'] = data['direccion']+"+"+data['num1']+"+"+data['num2']+"+"+data['num3'];
fetch('https://api.....', {
method: 'POST',
headers: header,
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((responseData) => {
console.log(responseData); // this data is needed in another component (MapSection)
});
}
And in this Class I need use the response of fetch from the previous component, exactly I need use some coordinates to render a Map.
export class MapSection extends React.Component{
constructor(props) {
super(props);
this.setState = this.setState.bind(this);
}
state = {
address: null
};
get googleMapDiv(){
return document.getElementById("mapa");
}
googleMapRef = createRef();
render(){
console.log(this.props,this.googleMapRef);
return(
<section className="hidden2" id="mapaSection">
<div className="container">
<div className="row mt-5">
<div className="col mt-5">
<h3>Confirma la ubicación de tu inmueble</h3>
<div className="row mt-5">
<div className="col">
<p id="direccionGeo"> {this.state.address !== null ? this.state.address : ""} </p>
</div>
</div>
<div id="mapa"
ref={this.googleMapRef}
style={{ width: 'auto', height: '55vh' }}
className="card-panel white map-holder"
/>
<div className="botonesMapa row mt-5">
<div className="col-6" align="center">
<button type="button" className="btn btn-info corregirBtn">Corregir dirección</button>
</div>
<div className="col-6" align="center">
<button type="button" className="btn btn-info confirmarBtn">Ubicación correcta</button>
</div>
</div>
</div>
</div>
</div>
</section>
)
}
componentDidMount() {
const self = this;
const googleMapScript = document.createElement('script');
googleMapScript.src = 'https://maps.googleapis.com/maps/api/js?key=yourKEY';
window.document.body.appendChild(googleMapScript);
googleMapScript.addEventListener('load',() => {
var coord = { lat: 4.6903289512, lng: -74.0522237222};
this.googleMap = this.createGoogleMap(coord);
this.marker = this.createMarker();
window.google.maps.event.addListener(this.marker, 'dragend', function(e) {
var request = {
"entrada": "address",
"mpio_ccdgo": "11001",
"lat": e.latLng.lat(),
"lng": e.latLng.lng()
};
fetch('https://api....', {
method: 'POST',
headers: header,
body: JSON.stringify(request),
}).then((response) => response.json())
.then(responseData => {
self.setState({
address: responseData.direccion_formato
});
});
});
});
}
createGoogleMap = ( data ) => {
return new window.google.maps.Map(this.googleMapRef.current, {
zoom: 16,
center:{
lat: data.lat, //4.6903289512
lng: data.lng//-74.0522237222
},
disableDefaultUI: true
});
};
createMarker = () => {
return new window.google.maps.Marker({
position: {lat: 4.6903289512, lng: -74.0522237222},
map: this.googleMap,
title: 'Avaluamos',
draggable: true
});
};
}
Finally I've a Class that join all components
class InitialForm extends React.Component{
constructor(props) {
super(props);
}
render(){
return(
<div>
<AddressForm />
<MapSection/>
<FeaturesForm/>
</div>
)
}
}
Many Thanks for your time and knowledge.
An idea would be to add a method to InitialForm that takes a string and saves it to InitialForm's state. You can pass this method as a prop to AddressForm and call it with the api response as an argument. Now you got the response in InitialForm and you can pass it down to MapSection.
Is that clear?

Can not get the data response

I am trying to get some data to my state from a fake online rest api, the problem is the data is not getting to the state properly, so it's not showing up.
I have tried to change the state to array or just like this firstName: '',
... and it still won't work
import React, { Component } from 'react';
import axios from 'axios';
class Success extends Component {
state = {
firstName: [],
username: [],
email: [],
id: [],
show: false
};
componentDidMount() {
axios
.get('https://jsonplaceholder.typicode.com/users')
.then(res => this.setState({ firstName: res.data.name }));
}
onClick = () => {
this.setState(prevState => ({ show: !prevState.show }));
};
render() {
return (
<div>
<h1
className="font-weight-light"
style={{
color: 'black',
marginTop: '50px'
}}
>
UserList:
</h1>
<div className="mt-5">
<ul className="list-group">
<li className="list-group-item">
{this.state.firstName}
<div
className="fas fa-angle-down"
style={{ marginLeft: '98%' }}
onClick={this.onClick}
/>
</li>
{this.state.show === true ? (
<li className="list-group-item">
Username: {this.state.username}
</li>
) : null}
{this.state.show === true ? (
<li className="list-group-item">Email: {this.state.email}</li>
) : null}
{this.state.show === true ? (
<li className="list-group-item">ID: {this.state.id}</li>
) : null}
</ul>
</div>
</div>
);
}
}
export default Success;
I want to get that data in the state and show up.
Are you sure that res.data.name exists?
It seems that res.data returns array.
You should declare users state with null, and set users state to res.data.
After that, you can use Array.prototype.map with res.data
For example,
state = {
users: null,
whatever: ''
}
componentDidMount() {
axios
.get('https://jsonplaceholder.typicode.com/users')
.then(res => this.setState({
users: res.data
}));
}
...
// write function that takes id as parameter.
this.state.users.map(item => {
if(item.id === id){
this.setState({
whatever: item.name
})
} return item;
})

React - Map content inside a div

Good Morning! Why does my map content stay outside the "blog--div" div?
It's getting loose on Body and I do not know why. Help-me, please!
I try to put a border around the contents of the "blog--div" but the content becomes loose, making it impossible to apply styles.
imports[...]
class Blog extends Component {
constructor(props) {
super(props)
this.state = {
post: [],
}
}
componentDidMount() {
this.setState({ isLoading: true })
fetch(`${API}`)
.then(res => res.json())
.then(res => {
this.setState({
post: [res],
isLoading: false,
})
})
}
render() {
const { isLoading } = this.state
if (isLoading) {
return <Loading />
}
return (
<div className="blog">
<p className="blog__title">Blog</p>
{this.renderBlog()}
</div>
)
}
renderBlog() {
const page = this.state.post.map((post, key) => {
return (
<div className="blog--div" key={key}>
<div className="blog__post">
<div className="blog__post--title">
<p><a target="_blank" rel="noopener noreferrer" href={post[0].link}>{post[0].title.rendered.replace('Visit.Rio', 'Projeto 1')}</a></p>
</div>
<div className="blog__post--description">
<p>{post[0].excerpt.rendered.replace('Visit.Rio', 'Projeto 1')}</p>
</div>
</div>
</div>
)
})
return page
}
}
export default Blog

React JS - Event Handler in a dynamic list

I'm bringing a API s' content based on a dynamic list and I'm trying to apply a mouserEnter on each li. The event results by toggling content in the each list item. The event is working but it is toggling content in all the list items all at once, but I want it to toggle only the content that matches with the list item that is receiving the mouseEnter.
import _ from 'lodash';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
export default class Dribbble extends React.Component {
constructor(props) {
super(props);
this.state = {
work: [],
hover: false
};
this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
}
handleMouseEnter(){
this.setState({ hover: true })
}
handleMouseLeave(){
this.setState({ hover: false })
}
componentDidMount() {
this.ShotList();
}
ShotList() {
return $.getJSON('https://api.dribbble.com/v1/shots?per_page=3&access_token=41ff524ebca5e8d0bf5d6f9f2c611c1b0d224a1975ce37579326872c1e7900b4&callback=?')
.then((resp) => {
this.setState({ work: resp.data.reverse() });
});
}
render() {
const works = this.state.work.map((val, i) => {
return <li key={i} className="box"
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
>
{!this.state.hover ?
<div>
<img className="cover" src={val.images.normal} />
<div className="bar">
<h2>{val.title}</h2>
<span>{val.views_count}</span>
<i className="fa fa-eye fa-2x" aria-hidden="true"></i>
</div>
</div>
: null}
{this.state.hover ?
<div>
<h3>{val.user.name}</h3>
<img className="avatar img-circle" src={val.user.avatar_url}/>
<p>{val.description}</p>
</div>
:
null
}
</li>
});
return <ul>{works}</ul>
}
}
Here is my code:
There are couple of issues in your example, firstly as #aherriot states you should move the ul outside the map.
Next i would set this.state.hover to be the id of the item being hovered over on onMouseEnter.
The below snippet shows a basic example of this working that should be easy enough to adapt to your code.
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
items: [{id: 1, name: 'Fred'}, {id: 2, name: 'Albert'}, {id: 3, name: 'Jane'}],
hover: false,
}
this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
this.renderItem = this.renderItem.bind(this);
}
handleMouseEnter(id){
console.log(`handleMouseEnter this.setState({ hover: ${id} })`);
this.setState({ hover: id })
}
handleMouseLeave(){
console.log('handleMouseLeave this.setState({ hover: false })');
this.setState({ hover: false })
}
renderItem(item, index) {
let content = [];
content.push(
<span>ID: {item.id}, Name: {item.name}</span>
);
if(this.state.hover === item.id) {
console.log('display " - hovering" for item id: ' + item.id);
content.push(
<span> - hovering</span>
);
}
return (
<li key={item.id}
onMouseEnter={() => this.handleMouseEnter(item.id)}
onMouseLeave={this.handleMouseLeave}
>
{content}
</li>
)
}
render() {
return <ul>
{this.state.items.map(this.renderItem)}
</ul>
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script>
<div id="root"></div>
Maybe you should move the <ul> tag outside of this.state.work.map You only want one <ul> to show up, not one for each element.
You can place it at the bottom inside your div tag instead: return (<div><ul>{works}</ul></div>)

Highlight item onClick - React.js

Add underscore to category-item onClick and remove underscore for any other item. Found some answers on how to do this with only two components, a "item-container-component" and "item-components". But i have three components involved. This is what I hope to achieve:
Archive-component (mother component):
class Archive extends React.Component {
constructor(props){
super(props);
this.state = {
products: [],
category: "",
activeIndex: 0
}
this.filterHandler = this.filterHandler.bind(this);
}
filterHandler(tag, index){
console.log('INDEX: ' + index);
this.setState({
category: tag,
activeIndex: index
})
}
componentDidMount(){
const myInit = {
method: "GET",
headers: {
"Content-Type": "application/json"
}
};
fetch("/getProducts", myInit)
.then((res) => {
return res.json();
})
.then((data) => {
this.setState({products:data});
})
.catch(function(err) {
console.log('ERROR!!! ' + err.message);
});
}
render() {
return (
<div>
<Menu />
<div className="archive-container">
<div className="archive-wrapper">
<CategoryContainer
filterHandler={this.filterHandler}
products={this.state.products}
activeIndex={this.state.activeIndex}
/>
<br/><br/>
<ProductContainer
products={this.state.category.length
? this.state.products.filter((prod) => prod.category === this.state.category)
: this.state.products.filter((prod) => prod.category === 'Paint')
}
/>
</div>
</div>
<Footer />
</div>
);
};
};
Category-container component:
class CategoryContainer extends Component {
render(){
const categories = [...new Set(this.props.products.map(cat => cat.category))];
return (
<div>
<ul className="filterList">{
categories.map((cat, index) =>
<CategoryItem
key={index}
index={index}
category={cat}
active={index === this.props.activeIndex}
handleClick={() => this.props.filterHandler(cat, index)}
/>
)
}</ul>
</div>
);
};
};
Category-item component:
class CategoryItem extends Component {
render(){
return (
<div>
<li
className={this.props.active ? 'active' : 'category'}
onClick={this.props.handleClick}
>
{this.props.category}
</li>
</div>
);
};
};
Yelp!
M
Suppose you have a li tag for which you want to change the color of.
you could probably try something like this.
<li id="colorChangeOnClick" class="redColor" onclick={this.onClickFunction()}></li>
Then in your react class you can have the on click function with parameters e:
onClick(e) {
//This would give you all the field of the target
console.log(e.target.elements);
// you can do all sorts of Css change by this way
e.target.element.class="newGreenColor";
}
Also make sure to make a state or a prop change otherwise the page would not render again.

Resources