Getting Json using Axios and iterating over data in ReactStrap Table - reactjs

I am trying to get data from jsonplaceholder via axios and iterate over that data and put that data into a reactstrap table. I am getting the error: Expected an assignment or function call and instead saw an expression. I'm not entirely sure what I am doing wrong here. Any help is greatly appreciated.
Here is my code:
render() {
const data = axios.get("https://jsonplaceholder.typicode.com/todos")
.then(response =>
this.data = response.data,
this.data.forEach((item) => {
<tr>
<td>{item.userId}</td>
<td>{item.id}</td>
<td>{item.title}</td>
<td>{item.completed}</td>
</tr>
})
)
return (
<div className="App">
<header className="App-header">
<Table>
<thead>
<tr>
<th>
User ID
</th>
<th>
ID
</th>
<th>
Title
</th>
<th>
Completed
</th>
</tr>
</thead>
<tbody>
{
data
}
</tbody>
</Table>
</header>
</div>
);
}
}
The error is where I try to create the table row <tr> tags in my data variable.

You should use lifecycle methods to load your data from API and store them in a state and render them when the state is updated.
Try this
import React, { Component } from 'react';
import axios from 'axios';
class Example extends Component {
constructor(props) {
super(props);
this.state = {
todos: []
}
}
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/todos")
.then(response => {
this.setState({
todos: this.data
});
})
}
render() {
const { todos = [] } = this.state;
return (
<div className="App">
<header className="App-header">
<Table>
<thead>
<tr>
<th>User ID</th>
<th>ID</th>
<th>Title</th>
<th>Completed</th>
</tr>
</thead>
<tbody>
{todos.length ?
todos.map(todo => (
<tr>
<td>{todo.userId}</td>
<td>{todo.id}</td>
<td>{todo.title}</td>
<td>{todo.completed}</td>
</tr>
))
:
(<tr>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>)
}
</tbody>
</Table>
</header>
</div>
);
}
}
export default Example;

The mistake is here:
axios.get('https://jsonplaceholder.typicode.com/todos').then(response => {
console.log(response);
this.setState({
todos: response.data, // you have it as this.data not response
});
});

Related

How to get React to wait for state to be set to render

userAccess is a function from another component which returns an array that I am trying to turn into a state variable and display it in render, however unless I implement an onclick=findSubs, the render does not show the correct state variable values. I thought putting it in componentDidMount would do something but it did not
import {userAccess} from '../../firebase';
class MySubscriptions extends Component{
constructor(props) {
super(props);
this.state = {subs:userAccess()};
this.findSubs = this.findSubs.bind(this);
}
componentDidMount(){
this.setState({subs:userAccess()});
}
findSubs(){
this.setState({subs:userAccess()});
}
render(){
return (
<div>
<Table>
<thead>
<tr>
<th>Subscription ID</th>
</tr>
</thead>
<tbody id="body">
{
this.state.subs.map((aSub) => (
<tr key ={aSub}>
<td key ={aSub}>{aSub.id}</td>
</tr>))
}
</tbody>
</Table>
</div>
)
}
}
export default MySubscriptions;
EDIT
This may not be the best way to do it, but it works
class MySubscriptions extends Component{
constructor(props){
super(props);
this.state ={subs:userAccess(), loaded:false};
}
async componentDidMount(){
await new Promise(resolve => { setTimeout(resolve, 500); });
this.setState({subs: await userAccess()}, () => {
this.setState({loaded:true});
return Promise.resolve();
});
}
render(){
return (
<div>
<Navbars/>
{this.state.loaded &&
<Table>
<thead>
<tr>
<th>Subscription ID</th>
</tr>
</thead>
<tbody id="body">
{
this.state.subs.map((aLine) => (
<tr>
<td>{aLine.id}</td>
</tr>
))
}
</tbody>
</Table>
}
</div>
)
}
}
export default MySubscriptions;
You could add a componentDidUpdate method.
In my opinion, the best practice is using the new Suspense component that was added with React 18, if you are using that version or higher.
You can read more about it and view code samples here.
If you have an earlier version, you can also use conditional rendering.

TableData.js:57 DELETE https://clientdata-dd88a-default-rtdb.firebaseio.com/userData.json/:$%7Bid%7D

"TableData.js:57 DELETE https://clientdata-dd35a-default-rtdb.firebaseio.com/userDataRecord.json/:$%7Bid%7D net::ERR_FAILED
TableData.DeleteData # TableData.js:57
onClick # TableData.js:152
TableData.js:57 Uncaught (in promise) TypeError: Failed to fetch"
I get this error on my delete button code.Delete button code cant identify the id of tabledatas. I am trying it but didn't get output. Please help me to solve this issue. I share my code.
tabledata.js file
const db = StartFirebase();
export class TableData extends Component {
constructor() {
super();
this.state = {
tableDatas: []
}
}
componentDidMount() {
const dbRef = ref(db, 'userDatas')
onValue(dbRef, (snapshot) => {
let records = []
snapshot.forEach(childSnapshot => {
let keyName = childSnapshot.key;
let data = childSnapshot.val()
records.push({ "key": keyName, "data": data })
})
this.setState({ tableDatas: records })
})
}
DeleteData=async(id)=>{
await fetch('https://clientdata-dc88a-default-rtdb.firebaseio.com/userDatas.json/:${id}',{
method:'DELETE'
}).then((res)=>{
res.json().then((resp)=>{
alert('delete', id)
})
})
}
render() {
return (
<div>
<table className="table table-bordered table table-hover" id="table-to-xls">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Sr</th>
<th scope="col">House No</th>
<th scope="col">Name</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{
this.state.tableData.map((row, id) => {
return (
<tr key={id}>
<th scope="row">{id}</th>
<td>{row.data.userDatas.srno}</td>
<td>{row.data.userDatas.house}</td>
<td>{row.data.userDatas.nameMarathi}</td>
<td>{row.data.userData.name}</td>
<td>{<button onClick={()=>this.DeleteData(id)}>Delete</button>}</td>
</tr>
)
})
}
</tbody>
</table>
</div>
)
}
}
This URL is wrong:
https://clientdata-dc88a-default-rtdb.firebaseio.com/userDatas.json/:${id}
When accessing the Firebase Realtime Database's REST API, the .json extension always needs to be at the end of the URL.
So:
https://clientdata-dc88a-default-rtdb.firebaseio.com/userDatas/:${id}.json

React Datatable Values Duplicating

I'm fetching data from a firebase real-time database and its working, expect the head of the table which is the name, email and stuff. Its supposed to only show up once at the very top like every datatable, instead, its showing on every new entry.
(I apologise everything is in french)
Thanks in advance.
here's a picture:
here's my code:
import React from 'react'
import { bd, auth } from '../firebase'
import "../reserve.css"
import 'bootstrap/dist/css/bootstrap.min.css';
class Pro extends React.Component {
state = {
contacts: null
}
componentDidMount(){
bd.collection('contacts')
.get()
.then( snapshot => {
const contacts = []
snapshot.forEach( doc => {
const data = doc.data()
contacts.push(data)
})
this.setState({ contacts: contacts })
console.log(snapshot)
})
.catch ( error => console.log(error))
}
render(){
return (
<div className="ProClass">
{
this.state.contacts &&
this.state.contacts.map( contact => {
return(
<div className="ProClassReservations">
<table>
<thead>
<tr>
<td>Nom Complet</td>
<td>Email</td>
<td>Date d'arrivée</td>
<td>Date de Départ</td>
<td>Nombre de Personnes</td>
<td>Type de Chambre</td>
<td>Tel</td>
</tr>
</thead>
<tbody>
<tr>
<td>{contact.nom}</td>
<td>{contact.email}</td>
<td>{contact.arrive}</td>
<td>{contact.depart}</td>
<td>{contact.npersonnes}</td>
<td>{contact.type}</td>
<td>{contact.tel}</td>
</tr>
</tbody>
</table>
</div>
)
})
}
</div>
)
}
}
export default Pro
This is because you have the Table headers inside the map, you must ONLY map the values into the respective table rows. All you need to do is append the rows after your headers.
return (
<div className="ProClass">
<div className="ProClassReservations">
<table>
<thead>
<tr>
<td>Nom Complet</td>
<td>Email</td>
<td>Date d'arrivée</td>
<td>Date de Départ</td>
<td>Nombre de Personnes</td>
<td>Type de Chambre</td>
<td>Tel</td>
</tr>
</thead>
<tbody>
{
this.state.contacts &&
this.state.contacts.map( contact => {
return(
<tr>
<td>{contact.nom}</td>
<td>{contact.email}</td>
<td>{contact.arrive}</td>
<td>{contact.depart}</td>
<td>{contact.npersonnes}</td>
<td>{contact.type}</td>
<td>{contact.tel}</td>
</tr>
)
})
}
</tbody>
</table>
</div>
)

Map data to table in ReactJS

I have successfully retrieved data from my API and set that data to setOfAllBooks state. I want to map the data in setOfAllBooks to a within the component. The page loads with the header alright but my data isn't there. I think there should be something wrong with mmy map() function.
import React, { Component } from 'react';
import './ViewAll.css';
import axios from 'axios'
const rootURL = 'http://localhost:5000';
const TableRow = ({ row }) => (
<tr class="table-light">
<th scope="row" key={row.title}>{row.title}</th>
<td key={row.author}>{row.author}</td>
<td key={row.isbn}>{row.isbn}</td>
<td key={row.isbn}>24</td>
</tr>
)
const Table = ({data}) => (
<table class="table table-hover">
<thead>
<tr class="table-primary">
<th scope="col">Title</th>
<th scope="col">Author</th>
<th scope="col">ISBN</th>
<th scope="col">No. Of Copies</th>
</tr>
</thead>
<tbody>
{data.map(row => {
<TableRow row={row} />
})}
</tbody>
</table>
)
class ViewAll extends Component {
constructor(props){
super(props);
this.state = {
setOfAllBooks: []
}
}
componentDidMount(){
axios.get(`${rootURL}/api/book/viewAll`)
.then(res => {
this.setState({ setOfAllBooks: res.data });
console.log(this.state.setOfAllBooks)
})
}
render(){
return(
<div>
<Table data={this.state.setOfAllBooks} />
</div>
)
}
}
export default ViewAll;
You missed return inside the .map call.
{data.map(row => {
// Missing return here. Add return, otherwise
// callback function of the map returns undefined
// which is the default return value of each functions
// in JS
<TableRow row={row} />
// return <TableRow row={row} /> will fix it.
})}
Or write the implicit return version of the arrow function.
{data.map(row => <TableRow row={row} />)}

Refreshing sorted table in React and state issue

I tried to sort an array in React, but I don't know how to refresh it. If I set data in a state like this: (data: this.props.data) pagination isn't working. Why is that?
render() {
let data = this.props.data;
return (
<div className='container'>
<table>
<thead>
<tr>
<th>iD</th>
<th>First name</th>
<th>Last name</th>
<th>Birth date</th>
<th onClick={() => {data.sort()}}>Company</th>
<th>Note</th>
</tr>
</thead>
<tbody>
{data.map((user) => {
return (
<tr key={user.id}>
<td className="number">{user.id}</td>
<td className="firstname">{user.firstName}</td>
<td className="lastname">{user.lastName}</td>
<td className="date">{user.dateOfBirth}</td>
<td className="company">{user.company}</td>
<td className="note">{user.note}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
Check the code below
state = {
//use constructor or es7
data:this.props.data
}
_handleSort=()=>{
/**
* Define you short logic here.
*/
let sortedDate = this.state.data.dateOfBirth.sort()
this.setstate({
data:sortedDate
})
}
render() {
let {data} = this.state;
return (
<div className='container'>
<table>
<thead>
<tr>
<th>iD</th>
<th>First name</th>
<th>Last name</th>
<th>Birth date</th>
<th onClick={() => {this._handleSort}>Company</th>
<th>Note</th>
</tr>
</thead>
<tbody>
{data.map((user) => {
return (
<tr key={user.id}>
<td className="number">{user.id}</td>
<td className="firstname">{user.firstName}</td>
<td className="lastname">{user.lastName}</td>
<td className="date">{user.dateOfBirth}</td>
<td className="company">{user.company}</td>
<td className="note">{user.note}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
The best way of fix this problem is sort array in parent component.
Instesd of data.sort() you will call this.props.sort() property and your table component will be updated with sorted data.
render() {
let data = this.props.data;
return (
<div className='container'>
<table>
<thead>
<tr>
<th>iD</th>
<th>First name</th>
<th>Last name</th>
<th>Birth date</th>
<th onClick={this.props.sort}>Company</th>
<th>Note</th>
</tr>
</thead>
<tbody>
{data.map((user) => {
return (
<tr key={user.id}>
<td className="number">{user.id}</td>
<td className="firstname">{user.firstName}</td>
<td className="lastname">{user.lastName}</td>
<td className="date">{user.dateOfBirth}</td>
<td className="company">{user.company}</td>
<td className="note">{user.note}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
Parent :
class Parent extends Component {
constructor() {
super(props)
this.state = {
data: ....
}
}
sort = () => {
this.setState({
data: sortDataHere !!!!
})
}
render() {
return (
<Table
data={this.state.data}
sort={this.sort}
/>
)
}
}
Your component isn't properly controlled, since you're just using a reference obtained from props, which doesn't trigger render(). Components should instead be controlled on either state or props to trigger render() changes.
Here's an example to demonstrate that this pattern doesn't work:
class Example extends React.Component {
render () {
let text = this.props.data
return (
<div>
{text}
<button onClick={()=> (text='bye')}>
Click Me
</button>
</div>
)
}
}
ReactDOM.render(<Example data='hello' />, document.getElementById('container'))
<div id='container'></div>
<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>
What you are trying to do is control the component. You have two main options:
1) A stateful approach:
constructor (props) {
super(props)
this.state = { data: props.data }
}
render () {
return (
<th onClick={() => {sortTable.bind(this)}}>Company</th>
)
}
sortTable () {
let { data } = this.state
// sort algorithm,
this.setState({ data })
}
2) A Stateless Pattern using props and something like Redux
This is usually the preferred methodology as it keeps components purely as presentation without logic, which tend to be more reusable.
class Example extends React.Component {
render () {
const { data } = this.props
return (
<th onClick={() => this.props.sortData(data)}>Company</th>
)
}
}
const mapStateToProps = (state) => {
return {
data: state.data
}
}
const mapDispatchToProps = (dispatch) => {
return {
sortData: data => {
dispatch({ type: SORT, payload: data })
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Example)
Then in a state reducer:
export default function (state, action) {
switch (action.type) {
case SORT:
// transform the data
}
}
I tried to keep this above example minimal, and as such it will not work as is. It purely demonstrates how the connected component might look. To fully use redux you need to setup your application with a <Provider> and a store.

Resources