I am trying to use fetch to get json data from my back end and then put it on a array, and show it on the screen, for now on the console log.
I am trying to store the information I get back in a array called data which I initialized in getinistate, and then put json data in it while the fetch call is done. For now The error I am reciving is that console.log is basically empty.
Here is the code.
<body>
<div id="reactBinding"></div>
<script type="text/babel">
var Heading = React.createClass({
getInitialState: function() {
return {
data: [],
amount : 1000
};
},
handleChange: function(event){
this.setState({amount : event.target.value});
},
loadCommentsFromServer: function() {
var value = {
method : 'GET' ,
headers : {
'Accept': 'application/json',
'contentType' : 'application/x-www-form-urlencoded',
},
body : ({
amount : this.state.amount
})
};
fetch('http://localhost:3000/getIOT', value)
.then((response) => response.json())
.then((responseData) =>{
responseData : this.state.data
})
.catch(function(err){
console.log(err);
});
},
showTable : function(){
console.log(data);
},
render : function(){
var amount = this.state.amount;
return(
<div className="container">
<div className="row">
<div classname="col-xs-4 col-xs-offset-4">
<div className="text-center">
<h1>{this.props.name}</h1>
<h2> {amount} </h2>
<input type="text" value={amount} onChange={this.handleChange} />
<button onClick={this.showTable}>Show Table</button>
<button onClick={this.loadCommentsFromServer}> Submit </button>
</div>
</div>
</div>
</div>
);
}
});
ReactDOM.render(
<div>
<Heading
name="React JS"
>
</Heading>
</div>
, document.getElementById('reactBinding'));
</script>
</body>
So again, what I want to do is get the information from fetch, put it in the variable called data array and then when someone clicks showTable, it should console.log the array out. Totally new to react so need a bit of handholding since this is the first time I am writing it. If this code is a bit too messy it would be great someone could help show me how to write a simple fetch.
Also if you have time it would be great if someone could explain how can I display the array in a table. in the showTable part.
You need to use the setState to store the data in state variable once you get the response, like this:
fetch('http://localhost:3000/getIOT', value)
.then((response) => response.json())
.then((responseData) =>{
//responseData : this.state.data
this.setState({data: responseData}); // use this line
})
put the console.log in render function, it will print the data once you get the response, like this:
render : function(){
var amount = this.state.amount;
console.log('data', this.state.data);
....
Update:
Check the working Code:
var Heading = React.createClass({
getInitialState: function() {
return {
data: [],
amount : 1000
};
},
handleChange: function(event){
this.setState({amount : event.target.value});
},
loadCommentsFromServer: function() {
var value = {
method : 'GET' ,
headers : {
'Accept': 'application/json',
'contentType' : 'application/x-www-form-urlencoded',
},
body : ({
amount : this.state.amount
})
};
fetch('http://localhost:3000/getIOT', value)
.then((response) => response.json())
.then((responseData) =>{
this.setState({data: responseData});
})
.catch(function(err){
console.log(err);
});
},
showTable : function(){
console.log(this.state.data);
},
render : function(){
var amount = this.state.amount;
console.log('data', this.state.data);
return(
<div className="container">
<div className="row">
<div classname="col-xs-4 col-xs-offset-4">
<div className="text-center">
<h1>{this.props.name}</h1>
<h2> {amount} </h2>
<input type="text" value={amount} onChange={this.handleChange} />
<button onClick={this.showTable}>Show Table</button>
<button onClick={this.loadCommentsFromServer}> Submit </button>
</div>
</div>
</div>
</div>
);
}
});
ReactDOM.render(
<div>
<Heading
name="React JS"
>
</Heading>
</div>
, document.getElementById('reactBinding'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='reactBinding'></div>
Related
I've created a notes app. On the front page it has categories and notes. You can click on the categories and get all of the notes under that category. I just added a button that lets you delete the category and all of its notes and then navigate back to the front page. It looks like this:
Button:
<IonRow>
<IonButton onClick={deletecat} >
Delete Category
</IonButton>
</IonRow>
Here is the deletecat function:
const deletecat = () => {
const trashcategory = ({category}) => {
try {
fetch(`https://fakeurl.com/delcat/${category}/`, {
method: "DELETE",
mode: "cors",
headers: {
"Content-Type": "application/json",
},
})
} catch (error) {
console.log("error time!", error);
return false;
}
};
trashcategory({category})
router.push('/notes')
}
When I click on my button I get this error:
NotFoundError: Node.removeChild: The node to be removed is not a child of this node
This issue was actually addressed on SO before (React Error: NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node), but their specific solution was for jquery. But I think the concept is the same:
This issue occurs when you:
1. Render something using React
2. Then, you manipulate DOM rendered by React with external script
3. Now on the next render cycle(re-render), React doesn't find the DOM node it rendered previously as its already modified/removed by external script
How do I resolve this? Is there any way I can re-render the DOM in a way where it doesn't try and look for what was rendered previously? How else might I get around this?
edit: This is the front page:
useEffect(() => {
getcategories({username})
getnotes({username})
console.log("USEEFFECTTIME")
},[]);
const getcategories = ({ username }) => {
try {
fetch(`https://fakeurl.com/getcategories`, {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({username}),
})
.then(res => res.json())
.then(data => {
setCategorydata(data);
setLoading(false);
})
} catch (error) {
console.log("error time!", error);
return false;
}
};
console.log('before get categories')
const getnotes = async ({ username }) => {
try {
//await fetch(`/getnotes`, {
await fetch(`https://fakeurl.com/getnotes`, {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({username}),
})
.then(res => res.json())
.then(data2 => {
setNotedata(data2);
setLoading2(false)
})
} catch (error) {
console.log("error time!", error);
return false;
}
};
const categories = categorydata.categories
const notes = notedata.notes
<IonSlides id="slider" options={{ slidesPerView: "auto", zoom: true, grabCursor: true }} className={ `${ styles.categorySlider } ion-padding-bottom` }>
{ categories.map((category, index) => {
const noteCount = notes.filter(n => n.note_category === category.id).length;
return (
<IonSlide key={ `categorySlide_${ index }`}>
<IonCol className="ion-text-left">
<IonCard routerLink={`/categorypage/${category.id}`}>
<IonCardHeader className="ion-no-padding" >
<div className={ styles.slideCount }>
<h6>{ noteCount } { noteCount === 1 ? "note" : "notes" } </h6>
</div>
<div className={ styles.slideHeader }>
<h4 style={{color:"black"}}>{ category.category }</h4>
</div>
</IonCardHeader>
<IonCardContent>
<div className={ styles.categoryColor } style={{ borderBottom: `2px solid ${ category.color }` }}></div>
</IonCardContent>
</IonCard>
</IonCol>
</IonSlide>
);
})}
</IonSlides>
<IonGrid className={ styles.bottomContainer }>
<IonRow>
<IonCol size="12" className="ion-padding-start">
<IonCardSubtitle className={ styles.heading }>
Recent Notes
</IonCardSubtitle>
</IonCol>
</IonRow>
<div className={ styles.recentNotes }>
{ notes.slice(0).reverse().map((note, index) => {
return (
<IonRow key={ `note_${ index }` } className="animate__animated animate__faster" id={ `noteRow_${ note.id }` }>
<IonCol size="12">
<Link to={`/Update/${note.id}`}>
<h2>{note.note_name}</h2>
</Link>
</IonCol>
</IonRow>
);
})}
</div>
</IonGrid>
Per your comments above, to make the changes reflect on both the front page and the component page, you call the data from the API at the parent component level and then pass the data and setData down as props to the component page.
If the front page and the component page are siblings under a router, then you can pull the data in the router component and share as props or implement the useContext hook to share the data.
Updates like changing note contents and deleting categories should happen on the front-end and then be updated to the back-end via fetch requests asynchronously.
The problem is coming from the asynchronous delay between updates from the API competing with synchronous unmounts with calls to the router.push method. By relying on local state data, you should get rid of your problem.
i just enter to "REACT " world to do my front-end off my own project and i have problem for 2 day with the function map , i get data from my back-end and i just save the id in the Cuartos array , i dont know what its my error , i try it with for loop with console.log in a function out of render and it work , but work out of the render function how i can resolve it ? i need to get all the cuarto id in the render
this is my code
class FormInterruptor extends React.Component {
constructor (){
super();
const axx={au:[]};
const Cuartos = [];
axios.get("http://localhost:5000/API/Cuartos")
.then(response => {
const a=JSON.stringify(response.data);
console.log(response.data);
axx.au=response.data;
const b=JSON.stringify(axx.au.idcuarto);
console.log("aqui estas" )
for (let i = 1; i < b.length; i=i+2)
{
Cuartos.push({idcuarto:parseInt((JSON.stringify(axx.au.idcuarto))[i])});
}
});
this.state = {
IdInterruptor: '',
IdCuarto: '',
Pin: '',
Dimmer: '',
Cuartos
};
}
onChange(e){
this.setState({
[e.target.name]:e.target.value
});
}
handleSubmit = event => {
event.preventDefault();
const Luz = {
IdInterruptor: this.state.IdInterruptor,
IdCuarto: this.state.IdCuarto,
Pin: this.state.Pin,
Dimmer: this.state.Dimmer
};
//AYUDA CON EL LUGAR DODNE SE PONDRA EL INTERRUPTOR
let config = {headers: {'Access-Control-Allow-Origin': "*"}};
axios.post('http://localhost:5000/API/Cuarto/1/Luz/add', Luz , config)
.then(res => {
//console.log(res);
console.log(res.data);
})
}
render(){
return (
<div className="App">
<header className="App-header">
<img src={process.env.PUBLIC_URL + '/Images/Escudo.png'} alt='Escudo' width='400'/>
<div className="Formulario">
<h2>
Formulario Luz
</h2>
<form onSubmit={this.handleSubmit} >
<div id='form'>
<input id="form" type="text"placeholder="ID del interruptor" value={this.state.IdInterruptor} name="IdInterruptor" onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<select id="form" name="IdCuarto" value={this.state.IdCuarto} onChange={this.onChange.bind(this)} >
</select>
</div>
<div id="separador">
<input id="form" type="text" name="Pin" placeholder="Pin" value={this.state.Pin} onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<input id="form" type="text" name="Dimmer" placeholder ="Dimmer" value={this.state.Dimmer} onChange={this.onChange.bind(this)}/>
</div>
<div >
<input type="submit" value="Submit" className="button" onChange={this.onChange}/>
</div>
</form>
</div>
<div>
{this.state.Cuartos.map(p => {
return <p > {p.idcuarto} !</p>}
)}
</div>
</header>
</div>
);
}
}
export default FormInterruptor
Update:
i change the code and i change my state in the componentDidMount and
this is my data array of Cuartos how i need to use the map function
enter image description here
First and foremost, what you should be doing is to make the HTTP request in the ComponentDidMount lifecycle hook instead of the constructor, as the purpose of the constructor is only for
Initializing local state by assigning an object to this.state. Binding
event handler methods to an instance.
constructor(props) {
super(props);
this.state = {
IdInterruptor: '',
IdCuarto: '',
Pin: '',
Dimmer: '',
Cuartos: undefined,
}
}
componentDidMount() {
let Cuartos;
axios.get("http://localhost:5000/API/Cuartos")
.then(response => {
const a=JSON.stringify(response.data);
console.log(response.data);
axx.au=response.data;
const b=JSON.stringify(axx.au.idcuarto);
console.log("aqui estas" )
for (let i = 1; i < b.length; i=i+2) {
Cuartos.push({idcuarto:parseInt((JSON.stringify(axx.au.idcuarto))[i])});
}
this.setState({ Cuartos });
});
}
Then, on your render, you should carry out a check such that you will only carry out Array.map() when the request is returned, and that Cuartos is defined, and the idcuartos array is not empty.
render() {
const { Cuartos } = this.state;
return <>
<div>
{
Cuartos && Cuartos.idcuartos.length && Cuartos.idcuartos.map(p => {
return . <p>{q}</p>
})
}
</div>
</>
}
Make your api call in componentDidMount and save your data to state and then manipulate your data before rendering.
class FormInterruptor extends React.Component {
constructor (){
super();
this.state = {
IdInterruptor: '',
IdCuarto: '',
Pin: '',
Dimmer: '',
Cuartos:[]
};
}
componentDidMount(){
axios.get("http://localhost:5000/API/Cuartos")
.then(response => this.setState({Cuartos:res.data}));
}
onChange(e){
this.setState({
[e.target.name]:e.target.value
});
}
handleSubmit = event => {
event.preventDefault();
const Luz = {
IdInterruptor: this.state.IdInterruptor,
IdCuarto: this.state.IdCuarto,
Pin: this.state.Pin,
Dimmer: this.state.Dimmer
};
//AYUDA CON EL LUGAR DODNE SE PONDRA EL INTERRUPTOR
let config = {headers: {'Access-Control-Allow-Origin': "*"}};
axios.post('http://localhost:5000/API/Cuarto/1/Luz/add', Luz , config)
.then(res => {
//console.log(res);
console.log(res.data);
})
}
render(){
return (
<div className="App">
<header className="App-header">
<img src={process.env.PUBLIC_URL + '/Images/Escudo.png'} alt='Escudo' width='400'/>
<div className="Formulario">
<h2>
Formulario Luz
</h2>
<form onSubmit={this.handleSubmit} >
<div id='form'>
<input id="form" type="text"placeholder="ID del interruptor" value={this.state.IdInterruptor} name="IdInterruptor" onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<select id="form" name="IdCuarto" value={this.state.IdCuarto} onChange={this.onChange.bind(this)} >
</select>
</div>
<div id="separador">
<input id="form" type="text" name="Pin" placeholder="Pin" value={this.state.Pin} onChange={this.onChange.bind(this)} />
</div>
<div id="separador">
<input id="form" type="text" name="Dimmer" placeholder ="Dimmer" value={this.state.Dimmer} onChange={this.onChange.bind(this)}/>
</div>
<div >
<input type="submit" value="Submit" className="button" onChange={this.onChange}/>
</div>
</form>
</div>
<div>
{this.state.Cuartos.map(p => {
return <p > {p.idcuarto} !</p>}
)}
</div>
</header>
</div>
);
}
}
export default FormInterruptor
You are making a call in the constructor which is not recommended, try doing it in componentDidMount
Javascript is asynchronous so when are making a call using axios it will not wait until the response got back it will continue to render the component, you need to update your component after you got the response
If you still want to render with your existing code, add below line after the for loop inside the axios call back
this.setState({"Cuartos": Cuartos})
I have written my code where I must Fetch data from API on button, but for more easier and cleaner page I want to have toggle button, but i dont know how to implement it in my function and into my render method.
I tried with state, and function, but dont know how to write it in render.
import React from "react";
import "./FetchBeerStyle.css";
export default class FetchBeer extends React.Component {
constructor(props) {
super(props);
this.state = {
beers: [],
on:false,
}
}
handleClick = () => {
fetch('https://api.punkapi.com/v2/beers')
.then(res => {
if (!res.ok) {
throw new Error('There has been an error');
}
return res.json();
})
.then(data => {this.setState({ beers: data})
console.log(this.state.beers);
})
.catch(e => console.log(e))
}
render(){
return (
<div>
<button onClick={this.handleClick}>Get All Beers/Return</button>
{this.state.beers.map((beer) => {
return <div key={beer.id}>
<h1 className="h1" >NAME : {beer.name}</h1>
<img src= {beer.image_url}/>
<h2>TAGLINE : {beer.tagline}</h2>
<p>FIRST BREWED : {beer.first_brewed}</p>
<p> DESCRIPTION : <br></br>{beer.description}</p>
<p> FOOD PAIRING : <br></br>{beer.food_pairing}</p>
<p> ALCOHOL BY VOLUME(%) : {beer.abv}</p>
<p> pH : {beer.ph}</p>
</div>
})}
</div>
);
}
}
You can check if button is true or false then you render your data. Also you need to call a different function that changes you button's state on click and call you function "handleClick" to fetch the data.
`{
this.state.on ?
this.state.beers.map((beer) => {
return <div key={beer.id}>
<h1 className="h1" >NAME : {beer.name}</h1>
<img src= {beer.image_url}/>
<h2>TAGLINE : {beer.tagline}</h2>
<p>FIRST BREWED : {beer.first_brewed}</p>
<p> DESCRIPTION : <br></br>{beer.description}</p>
<p> FOOD PAIRING : <br></br>{beer.food_pairing}</p>
<p> ALCOHOL BY VOLUME(%) : {beer.abv}</p>
<p> pH : {beer.ph}</p>
</div>
})
: null
}`
I have a simple app where a user selects a Person and vue makes an api call for that users posts.Each of these posts in turn have their own comments.This is all from https://jsonplaceholder.typicode.com/
The comment section is always empty.
The codepen is here
My html
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id='app'>
<div v-if='isError'>
There was an error
</div>
<div v-else-if='isLoading'>
Loading
</div>
<div v-else>
<select v-model="selectedUser">
<option v-for="person in info" v-bind:value="person"> {{person.name}}</option>
</select>
</div>
<div class="posts">
<div v-if="isLoadingPosts">
Loading...
</div>
<div v-else>
<ul>
<li v-for="post in postData">
<p>
{{ post.body }}
</p>
<button v-bind:id='post.id' v-on:click='getComments'>
View Comments
</button>
</li>
</ul>
</div>
</div>
<div class="comments">
<p>
{{ commentData }}
</p>
</div>
</div>
JS logic
var app = new Vue({
el: '#app',
data: {
info : null,
isLoading : true,
isError : false,
selectedUser : '',
postData : null,
isLoadingPosts : true,
commentData : null,
},
watch : {
selectedUser : function () {
axios
.get('https://jsonplaceholder.typicode.com/posts?userId=' + this.selectedUser.id)
.then(response => (this.postData =response.data))
.catch(error=> {console.log(error)})
.finally(() => this.isLoadingPosts = false)
}
},
methods : {
getComments : function (){
axios
.get('https://jsonplaceholder.typicode.com/posts/' + this.id + '/comments')
.then(response => (this.commentData =response.data))
}
},
mounted () {
axios
.get('https://jsonplaceholder.typicode.com/users')
.then(response => (this.info = response.data))
.catch(error => {console.log(error);this.isError = true})
.finally(() => this.isLoading = false)
}
})
Everything works except the comments part where it always returns an empty object.I also feel that my code is repetitive,any corrections would be appreciated.
So you have a couple issues with this method:
getComments : function (){
axios
.get('https://jsonplaceholder.typicode.com/posts/' + this.id + '/comments')
.then(response => (this.commentData =response.data))
}
}
First, this.id in there will be looking for an id prop on the component itself, not the id you're trying to bind in your button.
Try changing the button code to this:
<button v-on:click='getComments(post.id)'>View Comments</button>
And then the method to:
getComments : function (id){
axios
.get('https://jsonplaceholder.typicode.com/posts/' + id + '/comments')
.then(response => (this.commentData =response.data))
}
}
Also, you might want to add a .catch() handler like you id for your other axios calls.
I am new to react js.I have a problem in rendering the pretty json data inside textarea.I don't know Which part is wrong
I want my prettyjson to render inside textarea Like this
"email":"xxxx#x.com",
"email":"yyyy#y.com",
.....
This is my code
But I am getting Nothing inside my textarea
/**
* Created by arfo on 6/26/2016.
*/
var React =require('react');
var api = require('../utils');
var Bulkmail = React.createClass({
getInitialState:function () {
return{
default:10,
data:[],
color:'#58FA58'
}
},
componentDidMount:function () {
api.getemail(this.state.default).then(function (response) {
this.setState({
data:response
})
}.bind(this))
},
onSubmit:function (e) {
e.preventDefault();
console.log(this.refs.text.value.trim());
},
onChange:function (e) {
e.preventDefault();
//console.log(this.refs.text.value.trim())
var data = this.refs.text.value.trim();
if(isNaN(data)){
this.setState({
color:'#FE2E2E'
})
}else{
this.setState({
color:'#58FA58'
})
}
},
render:function () {
console.log(this.state.data);
var results = this.state.data;
return(
<div className="bodybox">
<div className="box">
<div className="upc">
<p>Generate Bulk Email</p>
<form onSubmit={this.onSubmit}>
<input onChange={this.onChange} type="text" style={{border:'1px solid '+this.state.color}} ref="text" defaultValue={this.state.default} placeholder="Enter Number"/>
<button>Get Data</button>
</form>
<div className="result">
<ul>
{this.state.data.map(function (data) {
return <li key={data.id}>{data.email}</li>
})}
</ul>
</div>
</div>
<div className="tdown">
<p>Json Format</p>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<textarea defaultValue={this.state.data.map(function(data) {
return JSON.stringify(data.email)
})} >
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</textarea>
</div>
</div>
</div>
)
}
});
module.exports = Bulkmail ;
No need to use difficult regex, we can use functionality from JSON.stringify(object, undefined, 2) to get beautifully rendered strings from JSON.
var obj={"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}}}
var pretty = JSON.stringify(obj, undefined, 2);
var ugly = document.getElementById('myTextArea').value; document.getElementById('myTextArea').value = pretty;
<textarea value={this.state.data.map(e=>JSON.stringify(e))} defaultValue="val" />
result {"email":"some#mail"},{"email":"some#mail"},{"email":"some#mail"}
let value = this.state.data.map(e=>JSON.stringify(e).replace(/{|}/g,''));
<textarea value={value} defaultValue="val" />
result "email" : "xx#yy.y", "email" : "some#mail", "email" : "some#mail"
let value = this.state.data.map(e=>JSON.stringify(e).replace(/{|}/g,'')).join(',\n');
<textarea value={value} defaultValue="val" />
result "email" : "xx#yy.y",
"email" : "some#mail",
"email" : "some#mail"
In HTML, the value of is set via children. In React, you should use value instead.
/**
* Created by arfo on 6/26/2016.
*/
var React =require('react');
var api = require('../utils');
var Bulkmail = React.createClass({
getInitialState:function () {
return{
default:10,
data:[],
color:'#58FA58'
}
},
componentDidMount:function () {
api.getemail(this.state.default).then(function (response) {
this.setState({
data:response
})
}.bind(this))
},
onSubmit:function (e) {
e.preventDefault();
console.log(this.refs.text.value.trim());
},
onChange:function (e) {
e.preventDefault();
//console.log(this.refs.text.value.trim())
var data = this.refs.text.value.trim();
if(isNaN(data)){
this.setState({
color:'#FE2E2E'
})
}else{
this.setState({
color:'#58FA58'
})
}
},
getEmailValue:function(){
return this.state.data.map(function(data) {
return JSON.stringify(data.email)
}).join('\n');
},
render:function () {
console.log(this.state.data);
var results = this.state.data;
return(
<div className="bodybox">
<div className="box">
<div className="upc">
<p>Generate Bulk Email</p>
<form onSubmit={this.onSubmit}>
<input onChange={this.onChange} type="text" style={{border:'1px solid '+this.state.color}} ref="text" defaultValue={this.state.default} placeholder="Enter Number"/>
<button>Get Data</button>
</form>
<div className="result">
<ul>
{this.state.data.map(function (data) {
return <li key={data.id}>{data.email}</li>
})}
</ul>
</div>
</div>
<div className="tdown">
<p>Json Format</p>
<textarea value={getEmailValue()}
</textarea>
</div>
</div>
</div>
)
}
});