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;
})
Related
I've created a MERN with redux application where users can order a meal from a menu. In the admin side, I am providing delete and add functions so the meals on the menu can be changed all in the same page. I have managed to get the delete meal item to work, but I am getting the following error when I try and add a new meal item:
My redux action is as follows:
export const createMeal = (meal) => (dispatch) => {
fetch("api/meals", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(meal),
})
.then((res) => res.json())
.then((data) => {
dispatch({ type: CREATE_MEAL, payload: data });
});
};
In my server file, I have the following endpoint created in Express:
app.post("/api/meals", async (req, res) => {
if (!req.body.title) {
return res.send({ message: "Data is required." });
}
const newMeal = new Meal(req.body);
const savedMeal = await newMeal.save();
res.send(savedMeal);
});
My UpdateMenuScreen is as follows:
import React, { Component } from "react";
import { connect } from "react-redux";
import { fetchMeals, deleteMeal, createMeal } from "../actions/mealActions";
class UpdateMenuScreen extends Component {
constructor(props) {
super(props);
this.state = {
meal: null,
showAddMenu: false,
title: "",
};
}
componentDidMount() {
this.props.fetchMeals();
}
componentDidUpdate() {
this.props.fetchMeals();
}
handleInput = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
createMeal = (e) => {
e.preventDefault();
const meal = {
title: this.state.title,
};
this.props.createMeal(meal);
};
deleteMeal(id) {
this.props.deleteMeal(id);
}
render() {
return (
<div>
<h3>Current Menu</h3>
{!this.props.meals ? (
<div>Loading...</div>
) : (
<ul className="meals">
{this.props.meals.map((meal) => (
<li key={meal._id}>
<div className="meal">
<p>{meal.title}</p>
<button
className="button"
onClick={() => this.props.deleteMeal(meal._id)}
>
Delete
</button>
</div>
</li>
))}
</ul>
)}
<button
onClick={() => {
this.setState({ showAddMenu: true });
}}
>
Add New Menu Item
</button>
{this.state.showAddMenu && (
<div className="cart">
<form onSubmit={this.createMeal}>
<ul className="form-container">
<li>
<label>Menu Item Title:</label>
<input
name="title"
type="text"
required
onChange={this.handleInput}
></input>
</li>
<li>
<button className="button primary" type="submit">
Save New Menu Item
</button>
</li>
</ul>
</form>
</div>
)}
</div>
);
}
}
export default connect((state) => ({ meals: state.meals.items }), {
fetchMeals,
deleteMeal,
createMeal,
})(UpdateMenuScreen);
Can anyone see what I'm missing? Or is it not possible to do this all on the same page?
EDIT:
I've console logged this.props.meals in ComponentDidMount and got the following results:
My mealsReducer is as follows:
const { FETCH_MEALS, DELETE_MEAL, CREATE_MEAL } = require("../types");
export const mealsReducer = (state = {}, action) => {
switch (action.type) {
case FETCH_MEALS:
return { items: action.payload };
case DELETE_MEAL:
return { items: action.payload };
case CREATE_MEAL:
return { items: action.payload };
default:
return state;
}
};
I also get this underneath my original error, could it be something in my mealActions that I don't have correct?
Please go to your reducer of meals and define the initial state of meals to []
This should fix your error.
render() {
const { meals = [] } = this.props // default to empty array when it's undefined
return (
<div>
<h3>Current Menu</h3>
{!meals.length ? (
<div>Loading...</div>
) : (
<ul className="meals">
{meals.map((meal) => (
<li key={meal._id}>
<div className="meal">
<p>{meal.title}</p>
<button
className="button"
onClick={() => this.props.deleteMeal(meal._id)}
>
Delete
</button>
</div>
</li>
))}
</ul>
)}
<button
onClick={() => {
this.setState({ showAddMenu: true });
}}
>
Add New Menu Item
</button>
{this.state.showAddMenu && (
<div className="cart">
<form onSubmit={this.createMeal}>
<ul className="form-container">
<li>
<label>Menu Item Title:</label>
<input
name="title"
type="text"
required
onChange={this.handleInput}
></input>
</li>
<li>
<button className="button primary" type="submit">
Save New Menu Item
</button>
</li>
</ul>
</form>
</div>
)}
</div>
);
}
}
I`m changing class after clicking and it works.
The problem is that, classes change simultaneously in both elements and not in each one separately. Maybe someone could look what I'm doing wrong. Any help will be useful.
import React, { Component } from "react";
class PageContentSupportFaq extends Component {
constructor(props) {
super(props);
this.state = {
isExpanded: false
};
}
handleToggle(e) {
this.setState({
isExpanded: !this.state.isExpanded
});
}
render() {
const { isExpanded } = this.state;
return (
<div className="section__support--faq section__full--gray position-relative">
<div className="container section__faq">
<p className="p--thin text-left">FAQ</p>
<h2 className="section__faq--title overflow-hidden pb-4">Title</h2>
<p className="mb-5">Subtitle</p>
<div className="faq__columns">
<div
onClick={e => this.handleToggle(e)}
className={isExpanded ? "active" : "dummy-class"}
>
<p className="mb-0">
<strong>First</strong>
</p>
</div>
<div
onClick={e => this.handleToggle(e)}
className={isExpanded ? "active" : "dummy-class"}
>
<p className="mb-0">
<strong>Second</strong>
</p>
</div>
</div>
</div>
</div>
);
}
}
export default PageContentSupportFaq;
Every element must have its seperate expanded value. So we need an array in state.
And here is the code:
import React, { Component } from "react";
class PageContentSupportFaq extends Component {
state = {
items: [
{ id: 1, name: "First", expanded: false },
{ id: 2, name: "Second", expanded: true },
{ id: 3, name: "Third", expanded: false }
]
};
handleToggle = id => {
const updatedItems = this.state.items.map(item => {
if (item.id === id) {
return {
...item,
expanded: !item.expanded
};
} else {
return item;
}
});
this.setState({
items: updatedItems
});
};
render() {
return this.state.items.map(el => (
<div
key={el.id}
onClick={() => this.handleToggle(el.id)}
className={el.expanded ? "active" : "dummy-class"}
>
<p className="mb-0">
<strong>{el.name}</strong>
<span> {el.expanded.toString()}</span>
</p>
</div>
));
}
}
export default PageContentSupportFaq;
You can get two state one state for first and another for a second and handle using two function like this
import React, { Component } from 'react';
class PageContentSupportFaq extends Component {
constructor(props) {
super(props)
this.state = {
isExpanded: false,
isExpanded2:false,
}
}
handleToggle(e){
this.setState({
isExpanded: !this.state.isExpanded
})
}
handleToggle2(e){
this.setState({
isExpanded2: !this.state.isExpanded2
})
}
render() {
const {isExpanded,isExpanded2} = this.state;
return (
<div className="section__support--faq section__full--gray position-relative">
<div className="container section__faq">
<p className="p--thin text-left">FAQ</p>
<h2 className="section__faq--title overflow-hidden pb-4">Title</h2>
<p className="mb-5">Subtitle</p>
<div className="faq__columns">
<div onClick={(e) => this.handleToggle(e)} className={isExpanded ? "active" : "dummy-class"}>
<p className="mb-0"><strong>First</strong></p>
</div>
<div onClick={(e) => this.handleToggle2(e)} className={isExpanded2 ? "active" : "dummy-class"}>
<p className="mb-0"><strong>Second</strong></p>
</div>
</div>
</div>
</div>
);
}
}
export default PageContentSupportFaq;
You'll need to track toggled classes in array, that way it will support arbitrary number of components:
// Save elements data into array for easier rendering
const elements = [{ id: 1, name: "First" }, { id: 2, name: "Second" }];
class PageContentSupportFaq extends Component {
constructor(props) {
super(props);
this.state = {
expanded: []
};
}
handleToggle(id) {
this.setState(state => {
if (state.isExpanded.includes(id)) {
return state.isExpanded.filter(elId => elId !== id);
}
return [...state.expanded, id];
});
}
render() {
return elements.map(el => (
<div
key={el.id}
onClick={() => this.handleToggle(el.id)}
className={this.isExpanded(el.id) ? "active" : "dummy-class"}
>
<p className="mb-0">
<strong>{el.name}</strong>
</p>
</div>
));
}
}
I am new to react development and I have a react app where on the componentDidMount am setting the state of value as "add" and it renders the div content for "add" and once button click on the add div am calling an addstate method
where am setting the state of the value as "edit" and it renders the div content with respect to "edit" and where i call again the addstate method through done method call.
In this case the fetch call from addstate method is happening to the backend but the state is not setting back to edit..it fails only in IE11. It works on chrome, firefox and mobile devices.
If i remove the piece of code "Value:edit" in addstate method its working good. But my requirement needs to render based upon different scenarios. so basically am able to set the state of the result only once in IE11. it does not work repeatedly.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "test",
items: []
}
};
addState() {
fetch("/local/addThings").then(res => res.json())
.then(
(result) => {
this.setState({
value: "edit",
items: result
});
}
)
.catch(error => console.error('Error:', error));
}
done() {
this.setState({
value: "add"
});
}
componentDidMount() {
fetch("/local/getThings")
.then(
(result) => {
this.setState({
value: "add"
});
}
)
.catch(error => console.error('Error:', error));
}
render() {
const { value, items } = this.state;
if (value === "add") {
return <div >
<div >
<ul >
<li onClick={() => this.addState()}>
<div>
<img src="Add.png" />
<center><p>AddButton</p></center>
</div>
</li>
</ul>
</div>
</div>
;
}
if (value === "edit") {
return (<div>
<div >
<ul >
<li onClick={() => this.done()}>
<div >
<img src="Save.png" />
<center><p>SaveButton</p></center>
</div>
</li>
{items.map(item => (
<center><p>{item.name}</p></center>
</li>
))}
</ul>
</div>
</div>
);
}
}
}
ReactDOM.render(React.createElement(App, null), document.getElementById("details")); ```
Try binding your method and refer to it directly in your onClick event:
lass App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "test",
items: []
}
this.addState = this.addState.bind(this);
};
addState() {
fetch("/local/addThings").then(res => res.json())
.then(
(result) => {
this.setState({
value: "edit",
items: result
});
}
)
.catch(error => console.error('Error:', error));
}
done() {
this.setState({
value: "add"
});
}
componentDidMount() {
fetch("/local/getThings")
.then(
(result) => {
this.setState({
value: "add"
});
}
)
.catch(error => console.error('Error:', error));
}
render() {
const { value, items } = this.state;
if (value === "add") {
return <div >
<div >
<ul >
<li onClick={this.addState}>
<div>
<img src="Add.png" />
<center><p>AddButton</p></center>
</div>
</li>
</ul>
</div>
</div>
;
}
if (value === "edit") {
return (<div>
<div >
<ul >
<li onClick={() => this.done()}>
<div >
<img src="Save.png" />
<center><p>SaveButton</p></center>
</div>
</li>
{items.map(item => (
<center><p>{item.name}</p></center>
</li>
))}
</ul>
</div>
</div>
);
}
}
}
I added settimeout in my methods and it worked in IE. It seems like the response was slower in IE for the API calls. Not sure if there is a workaround or this is the right approach.
fetch("/local/addThings").then(res => res.json())
.then(
(result) => {
setTimeout(() => {
this.setState({
value: "edit",
items: result
});
}, 200);
}
)
.catch(error => console.error('Error:', error));
}```
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!
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.