Goal:
Use axios instead of fetch in order to display the data in the table
Problem:
Somehow it doesn't work when I use axios in relation to 'isLoaded'
What part of the code am I missing?
Stackblitz:
https://stackblitz.com/edit/react-cntoqk?
Info:
Newbie in Reactjs
import React from 'react';
import './style.css';
import React, { Component } from 'react';
import axios from 'axios';
export default class App extends Component {
constructor() {
super();
this.state = {
isLoaded: false,
listData: {}
};
}
componentDidMount() {
/**
fetch('https://jsonplaceholder.typicode.com/comments?postId=1')
.then(results => results.json())
.then(data =>
this.setState({
isLoaded: true,
listData: data
})
)
.catch(err => console.log(err));
*/
axios
.get('https://jsonplaceholder.typicode.com/comments?postId=1')
.then(response =>
this.setState({
isLoaded: true,
listData: data
})
);
}
render() {
const { isLoaded } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<>
<table className="table">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{this.state.listData &&
this.state.listData.map(item => {
return (
<tr key={item.id.toString()}>
<td>{item.id}</td>
<td>{item.name}</td>
<td>{item.email}</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
}
}
As Floyd already pointed out, your code should look like this
axios
.get('https://jsonplaceholder.typicode.com/comments?postId=1')
.then(response =>
this.setState({
isLoaded: true,
listData: response.data
})
);
Related
I have this on the front end (react) right now.
import '../styles/TourPage.css';
import React, { Component } from 'react';
import axios from 'axios'
class TourPage extends Component {
constructor(props) {
super(props);
this.state = {
myData: []
}
}
componentDidMount() {
axios.get('/getResults')
.then( res => {
console.log("Res is: ", res.data)
this.setState({
myData: res.data
});
})
console.log("res.data", this.state.myData)
}
render() {
console.log("res.data", this.state.myData)
return (
<table id="customers">
<tr>
<th>siteLocation</th>
<th>Services</th>
<th>cnum</th>
</tr>
{this.state.myData.length > 0? this.state.myData.map((data, index) => (
<tr>
{/* <tr key={index}> */}
<td>{data.location}</td>
<td>{data.Services}</td>
<td>{data.cnum}</td>
<button onClick={this.click} disabled={this.state.isLoading}> Delete </button>
{/* {this.state.data} */}
{/* </tr> */}
</tr>
))
: "No Data Found"}
</table>
);
}
}
export default TourPage;
What I want to do, is on a button click, set data._id in the state, and then call Axios to post it to the Node.JS backend server, so I can update the database. Basically to delete the document. as you can see below, I tried with <a href> but that seems to be an HTML-specific thing. I also tried with the button, but I cannot figure it out. How can I do this?
I have refactored most of your code. You can pass id using an anonymous arrow function.
Do modify this to suit your needs.
import { render } from "react-dom";
import React, { Component } from "react";
import axios from "axios";
import "../styles/TourPage.css";
class TourPage extends Component {
constructor(props) {
super(props);
this.state = {
myData: [],
isLoading: true
};
}
componentDidMount() {
axios
.get("/getResults")
.then((res) => {
this.setState({
myData: res.data
});
})
.catch((error) => {
// Handle the errors here
console.log(error);
})
.finally(() => {
this.setState({
isLoading: false
});
});
}
deleteById = (id) => {
// You'll get the id here
// Delete by id code goes here
};
render() {
// You can handle the loader part here with isLoading flag. In this case No data found will be shown initially and then the actual data
let { myData, isLoading } = this.state;
return (
<table id="customers">
<tr>
<th>siteLocation</th>
<th>Services</th>
<th>cnum</th>
</tr>
{myData.length > 0
? myData.map(({ location, Services, cnum, _id }, index) => (
<tr key={index}>
<td>{location}</td>
<td>{Services}</td>
<td>{cnum}</td>
<button
onClick={() => this.deleteById(_id)}
disabled={isLoading}
>
Delete
</button>
</tr>
))
: "No Data Found"}
</table>
);
}
}
export default TourPage;
Can you try this ?
render() {
deleteDoc = (id) => {
await fetch('service_url', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: id} )
.then(async response => {
await response.json().then(data => {
console.log(data);
});
})
.catch(err => {
console.log(err)
})
}
return (
<table id="customers">
<tr>
<th>siteLocation</th>
<th>Services</th>
<th>cnum</th>
</tr>
{this.state.myData.length > 0 ? this.state.myData.map((data, index) => (
<tr>
<td>{data.location}</td>
<td>{data.Services}</td>
<td>{data.cnum}</td>
<button onClick={this.deleteDoc(data._id)} disabled={this.state.isLoading}> Delete </button>
</tr>
))
: "No Data Found"}
</table>
);
}
how can i sort my data by title? This is my code:
And how can i call this 3 calls at the same time? I tried with "Promise All" but didn't work for me..
Thanks for help! ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import './Style.css';
class PostList extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: [],
items: []
};
}
componentDidMount() {
fetch(this.props.url)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
data: result.data,
items: result.items
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Please wait...</div>;
} else {
return (
<div> <table style={{ width: '100%'}}>
{data.items.map(item => (
<div>
<tr>
<th>Title:</th> <td>{item.title}</td>
</tr>
<tr>
<th>Artist:</th> <td>{item.artist}</td>
</tr>
<tr>
<th>Label:</th> <td>{item.label}</td>
</tr>
<tr>
<th>Year:</th> <td>{item.year}</td>
</tr>
</div>
))}
</table>
</div>
);
}
}
}
export default PostList
AND
import React, {Component} from 'react';
import PostList from './PostList';
class index extends Component {
render () {
return (
<div style={{
display: 'inline-flex'
}}>
<PostList url={"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list1"} />
<PostList url={"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list2"} />
<PostList url={"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list3"} />
</div>
)
}
}
export default index;
To sort the items just use Array.prototype.sort and String.prototype.localeCompare to compare the titles:
const sortedItems = data.items.sort((item1, item2) => item1.title.localeCompare(item2.title));
// and then render sorted items
{sortedItems.map(item => (...)}
If you want to do three calls at the same time you really need to use Promise.all. It can be done in parent component, or inside of PostList. So you can do the following:
const LIST_URLS = [
'https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list1',
'https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list2',
'https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list3'
];
...
async componentDidMount() {
this.setState({ isLoading: true });
try {
const lists = await Promise.all(LIST_URLS.map((url) => {
return fetch(this.props.url).then(res => res.json());
});
const list = lists.flat();
const sortedList = data.items.sort((item1, item2) => item1.title.localeCompare(item2.title));
this.setState({ list: sortedList });
} catch (error) {
this.setState({ error });
} finally {
this.setState({ isLoading: false });
}
}
render() {
// here you can just render single list with all the items, passing them as a prop
const { isLoading, error, items } = this.state;
return (
<div>
{isLoading && 'Loading...'}
{items && <PostList list={this.state.list} />}
{error && 'Failed to fetch'}
</div>
);
}
If all 3 API data should be sorted, then you have to use like below. If you want individual API responses to be sorted use sort before updating the state.
class PostList extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: [],
items: [],
};
this.callAPi = this.callAPi.bind(this);
}
callAPi(url) {
return fetch(url)
.then((res) => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
data: [...result.data].sort((item1, item2) =>
item1.title.localeCompare(item2.title)
),
items: [...result.items].sort((item1, item2) =>
item1.title.localeCompare(item2.title)
),
});
},
(error) => {
this.setState({
isLoaded: true,
error,
});
}
);
}
componentDidMount() {
Promise.all(props.urls.map(this.callAPi));
}
render() {
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Please wait...</div>;
} else {
return (
<div>
<table style={{ width: "100%" }}>
{data.items.map((item) => (
<div>
<tr>
<th>Title:</th> <td>{item.title}</td>
</tr>
<tr>
<th>Artist:</th> <td>{item.artist}</td>
</tr>
<tr>
<th>Label:</th> <td>{item.label}</td>
</tr>
<tr>
<th>Year:</th> <td>{item.year}</td>
</tr>
</div>
))}
</table>
</div>
);
}
}
}
USE
<PostList
urls={[
"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list1",
"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list2",
"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list3",
]}
/>;
I am fetching data using axios and then map state to props with redux but I have a problem. If I dispatch the action in componentDidUpdate() the action execute indefinitely and if I used the constructor(props) I get undefined value for props so where I should fetch the data ?
import React, { Component } from 'react'
import {connect} from 'react-redux'
import { getUserPosts } from '../../actions'
class UserPosts extends Component {
//UNSAFE_componentWillMount() {
//}
constructor(props) {
super(props);
console.log(props);
}
componentDidUpdate() {
//this.props.dispatch(getUserPosts(this.props.user_reducer.login?.user._id));
}
showUserPosts = (user) => (
Array.isArray(user.userPosts) ?
user.userPosts.map((item, i) => (
<tr key={i}>
<td>{i}</td>
<td>author</td>
<td>date</td>
</tr>
))
: null
)
render() {
let user = this.props.user_reducer;
//console.log(user.userPosts);
return (
<div>
<div className="user_posts">
<h4>Your reviews:</h4>
<table>
<thead>
<tr>
<th>Name</th>
<th>Author</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{this.showUserPosts(user)}
</tbody>
</table>
</div>
</div>
)
}
}
function mapStateToProps(state) {
//console.log(state);
return {
user_reducer: state.user_reducer
}
}
export default connect(mapStateToProps)(UserPosts)
action:
export function getUserPosts(userId) {
const req = axios.get(`/api/user_posts?user=${userId}`)
.then(res => res.data);
return {
type: 'GET_USER_POSTS',
payload: req
}
}
componentDidMount() is the best placement for the call to fetch.
Here is an example implementation of the axios fetch from componentDidMount():
import React from 'react'
import ReactDOM from 'react-dom'
import axios from 'axios'
class UserPosts extends React.Component {
constructor(props) {
super(props)
// Initiate state with an empty array of user posts
this.state = { userPosts: [] }
}
componentDidMount() {
axios.get('http://api-url-here')
.then((response) => {
// Set the userPosts when data is received.
// render method will show user posts when state changes
this.setState({userPosts: response.data})
})
}
showUserPosts = (user) => (
Array.isArray(user.userPosts) ?
user.userPosts.map((item, i) => (
<tr key={i}>
<td>{i}</td>
<td>author</td>
<td>date</td>
</tr>
))
: null
)
render() {
let user = this.state;
//console.log(user.userPosts);
return (
<div>
<div className="user_posts">
<h4>Your reviews:</h4>
<table>
<thead>
<tr>
<th>Name</th>
<th>Author</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{this.showUserPosts(user)}
</tbody>
</table>
</div>
</div>
)
}
}
ReactDOM.render(<UserPosts />, document.getElementById('root'))
I am failing to delete the clients from the API, i expected to click on Onclick button and the data should be deleted from the database:
Using the onclick button, the data should be deleted:
import React, { useRef } from 'react'
import ReactToPrint from 'react-to-print'
import { Table, Button } from 'react-bootstrap'
const Hello = () => {
alert('Name, Description, Start Date, End Date, Validity, Status')
}
class clientview extends React.Component {
constructor (props) {
super(props)
this.state = {
error: null,
clients: []
}
this.deleteTask = this.deleteTask.bind(this)
}
componentDidMount () {
const url = 'http://localhost:3001/clients/sel_all'
fetch(url)
.then(res => res.json())
.then(
result => {
console.log(result)
this.setState({
clients: result.data
})
},
error => {
this.setState({ error })
}
)
}
deleteTask (id, url = 'http://localhost:3001/clients/delete') {
return fetch(url + '/' + id, { method: 'DELETE' }).then(response =>
response.json()
)
}
render () {
const { error, clients, props } = this.state
if (error) {
return <div> Error:{error.message}</div>
} else {
return (
<div>
<h2>All Clients</h2>
<Table>
<thead>
<tr>
<th>No</th>
<th>Client Name</th>
<th>Client Address</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
{clients.map(client => (
<tr key={client.id}>
<td>{client.id}</td>
<td>{client.name}</td>
<td>{client.address}</td>
<td>{client.comment}</td>
<td>
<button onClick={Hello}>View Contract</button>
<button>
<ReactToPrint
trigger={() => <button>print</button>}
content={() => this.componentRef}
/>
</button>
<button
onClick={() => {
props.editRow(client)
}}
className='button'
>
Edit
</button>
</td>
<button
onClick={() => {
this.deleteTask.bind(this)
}}
>
Dele
</button>
</tr>
))}
</tbody>
</Table>
</div>
)
}
}
}
export default clientview
I am getting an error in my code 'this.state.UserData.map' is not a function . i want get list from the database using fetch. i think i am forgetting something.
please help me remove this error. thanks in advance.
Here is my complete code to show list...
import React from 'react';
import ReactDOM from 'react-dom';
export default class FetchedData extends React.Component{
constructor(props){
super(props);
this.state={ UserData:[] };
this.headers=[
{key:1,label:'Name'},
{key:2,label:'Department'},
{key:3,label:'Marks'},
];
}
componentDidMount(){
fetch("https://www.veomit.com/test/zend/api/fetch.php")
.then(response => {
return response.json();
})
.then(result => {
this.setState({
UserData:result
})
.catch(error => {
console.log(
"An error occurred while trying to fetch data from Foursquare: " +error
);
});
});
}
render(){
return(
<div>
<table className="table table-bordered">
<thead>
<tr>
{
this.headers.map(function(h) {
return (
<th key = {h.key}>{h.label}</th>
);
})
}
</tr>
</thead>
<tbody>
{
this.state.UserData.map(function(item){
return (
<tr>
<td>{item.name}</td>
<td>{item.department}</td>
<td>{item.marks}</td>
</tr>
);
})
}
</tbody>
</table>
</div>
);
}
}
````````
Please replace your code I hope it's working for you.
Thanks
import React from 'react';
import ReactDOM from 'react-dom';
export default class FetchedData extends React.Component{
constructor(props){
super(props);
this.state={ UserData:[] };
this.headers=[
{key:1,label:'Name'},
{key:2,label:'Department'},
{key:3,label:'Marks'},
];
}
componentWillMount() {
fetch("https://www.veomit.com/test/zend/api/fetch.php")
.then(response => {
return response.json();
})
.then(result => {
this.setState({
UserData: result
});
})
.catch(function(error) {
console.log(
"An error occurred while trying to fetch data from Foursquare: " +
error
);
});
}
render(){
return(
<div>
<table className="table table-bordered">
<thead>
<tr>
{
this.headers.map(function(h) {
return (
<th key = {h.key}>{h.label}</th>
);
})
}
</tr>
</thead>
<tbody>
{ this.state.UserData.length > 0 ?
this.state.UserData.map((item,index) => (
<tr key={index}>
<td>{item.name}</td>
<td>{item.department}</td>
<td>{item.marks}</td>
</tr>
))
) : (
<tr>
<td colspan="3">No record found.</td>
</tr>
)}
</tbody>
</table>
</div>
);
}
}
````````
The data is an object - you need to convert it to an array with Object.values:
UserData: Object.values(result)
response is not array. You need convert response server to array of object to use map
response must like this. You can tell backend services to change like this or you convert like this to your state
[{name: 'John Doe', department: 'CEO', marks: 'title' } , {....} ]