Display fetched data into table in React - reactjs

I am unable to tel why my table has no data. Is it the way I'm calling for the display, {this.newItems} or what could it be?
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
taskList: []
};
}
componentDidMount() {
this.refreshList();
}
//refreshList Function start
refreshList = () => {
axios
.get("http://127.0.0.1:8000/list/api/rooms/")
.then(res => this.setState({ taskList: res.data }))
.catch(err => alert(err))
}
//refreshList Function end
//renderItems Function start
renderItems = () => {
const newItems = this.state.taskList;
return newItems.map(item => (
<tr key={item.id}>
<td>{item.thing1}</td>
<td>{item.thing2}</td>
<td>{item.thing3}</td>
</tr>
));
};
//renderItems Function end
render (){
return (
<div>
<Navbar/>
<table className="layout container">
<thead>
<tr>
<th>thing1</th>
<th>thing2</th>
<th>thing3</th>
</tr>
</thead>
<tbody>
{this.newItems}
</tbody>
</table>
<Footer/>
</div>
)
}
}

The reason is that inside <tbody> tag you are using this.newItems, which is a local variable and doesn't exist outside the scope of renderItems function.
The piece of code responsible to render the table data is renderItems function, which you created but never called.
So you just need to do that:
<tbody>
{this.renderItems()}
</tbody>
Also, inside the renderItems function, there is no need to create additional variable if you are not going to modify it. So it can be written simply as:
renderItems = () => {
return this.state.taskList.map(item => (
<tr key={item.id}>
<td>{item.thing1}</td>
<td>{item.thing2}</td>
<td>{item.thing3}</td>
</tr>
));
};

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.

Not able to render the new component on onClick()

I am new to react and facing some problem while rendering a new component on onClick() on a table cell item.
class Component extends React.Component{
constructor(props) {
super(props);
this.routeChange = this.routeChange.bind(this)
this.state = {
values: []
};
}
routeChange(id) {
console.log(id)
const userAccount = (
<Account />
);
return userAccount;
}
render() {
return (
<div className="classname1">
<table>
<thead className="table-header">
<tr className="table-row">
<th>Account Name</th>
</tr>
</thead>
<tbody>
{this.state.values.map(value => {
return (
<tr className="data-table">
<td className="txt-blue" onClick={() => this.routeChange(value.id)}>{value.name}</td>
</tr>)
})}
</tbody>
</table>
</div>
}
So when I execute the above everything works fine and the table has been rendered properly but when I click on the table cell item then my component is not being rendered. But I can see the console.log() which I have passed in routeChange().
Note: My state values[] is not empty because as here I am only showing the snippet of my code.
You need to pass a reference of a function that calls routeChange function to the onClick function. One way to do this is to use an arrow function.
<td className="txt-blue" onClick={() => this.routeChange(values.value.id)}>{values.value.name}</td>
When you click and the event 'onClick' is triggered, it doesn't expect a return value, meaning that component you are returning is going nowhere.
What you can do to show the 'Account' component is keep a variable, say showAccount, in your state, which initialises as false, and with the method 'routeChange' what you do is change this to true.
I don't quite understand your use case, but something like this could be:
class Component extends React.Component{
constructor(props) {
super(props);
this.routeChange = this.routeChange.bind(this)
this.state = {
values: [],
accountId: null,
showAccount: false
};
}
routeChange(id) {
console.log(id)
/* Commenting this,
const userAccount = (
<Account />
);
return userAccount;
*/
this.setState({showAccount: true, accountId: id})
}
render() {
return (
<div className="classname1">
<table>
<thead className="table-header">
<tr className="table-row">
<th>Account Name</th>
</tr>
</thead>
<tbody>
{this.state.values.map(value => {
return (
<tr className="data-table">
<td className="txt-blue" onClick={() => this.routeChange(value.id)}>{value.name}</td>
</tr>)
})}
</tbody>
</table>
{this.state.showAccount && this.state.accountId &&
<Account id={this.state.accountId} />
}
</div>
}
Anyhow, try to play with your component and see what works best for you. What I suggest may not be useful for you, so just take the concept and adapt it for your own app.

Why I get error: "Maximum update depth exceeded" when trying to sort table?

I am trying to sort table but I get an error when trying to use function in render. This is my code snippet:
/*index.jsx*/
import React, {Component, useState } from 'react';
//Functional Component
const Row = ({id, spec, qNumber,i}) => (
<tr>
<th key={i} id={id} scope={"row"}>{i}</th>
<td key={spec} id={id}>{spec}</td>
<td key={qNumber} id={id}>{qNumber}</td>
</tr>
);
class LightBoardPage extends Component{
constructor(props){
super(props);
this.state = {
list: [],
error: null,
loaded: false
}
this.compareBy.bind(this);
this.sortBy.bind(this);
}
buildList =(data)=>{
console.log(data);
this.setState({list: data})
}
componentDidMount(){
console.log('did mount')
let url = './data.json';
fetch(url)
.then(response => response.json())
.then(this.buildList)
.catch(error => {
this.setState({error});
})
}
compareBy(key) {
return function (a, b) {
if (a[key] < b[key]) return -1;
if (a[key] > b[key]) return 1;
return 0;
};
}
sortBy(key) {
let arrayCopy = [...this.state.list];
arrayCopy.sort(this.compareBy(key));
this.setState({list: arrayCopy});
}
render(){
const rows = this.state.list.map( (rowData) => <Row {...rowData}/>);
console.log('render');
let o=0;
return (
<div >
{this.sortBy('spec')}
<table className="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Specialistas</th>
<th>EilÄ—s numeris</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
{this.state.error &&
<h3>{this.state.error}</h3>
}
</div>
)
}
}
export default LightBoardPage;
If I use sortBy() with "onClick" it works but otherwise I get this error:
Error
I am new in react and I don't know what I can do to make sorting work. So what I could do to make this error dissapera?
P.S. This is my code: Code
I wrote () => this.sortBy('spec') and everything fixed

Beginner Question about ReactJS error TypeError: Cannot read property 'map' of undefined

I have tried out several other answers with this same issue and i still cant figure out why i keep getting this error "TypeError: Cannot read property 'map' of undefined".
Any help would be appreciated.
The code is:
import React from 'react';
import * as $ from 'jquery';
class TeamRaceDetails extends React.Component {
constructor(){
super();
this.state = {
teamResults: [],
loading: true
}
this.getTeamResults = this.getTeamResults.bind(this);
}
componentDidMount(){
this.getTeamResults();
}
getTeamResults(){
const id = this.props.teamid;
var url = 'http://ergast.com/api/f1/2013/constructors/' + id + '/results.json';
//console.log(url);
$.get(url, (teamResultData) => {
//console.log(resultData);
this.setState({ teamResults: teamResultData, loading:false });
});
}
render() {
if (this.state.loading === true){
return <h2>Loading...</h2>;
}
var teamResults = this.state.teamResults.MRData.RaceTable.Races.Results;
return (
<div>
<table>
<thead>
<tr>
<th>Round</th>
<th>Grand prix</th>
<th>{this.state.teamResults.position}</th>
<th>{this.state.teamResults.grid}</th>
<th>Points</th>
</tr>
</thead>
<tbody>
{teamResults.map((race, i) => <TeamResults teamRacesData = {race} key={i}/>)}
</tbody>
</table>
</div>
);
}
}
class TeamResults extends React.Component {
render(){
return(
<tr>
<td>{this.props.teamRacesData.round}</td>
<td>{this.props.teamRacesData.Circuit.circuitName}</td>
<td>{this.props.teamRacesData.Results[0].Constructor.name}</td>
<td>{this.props.teamRacesData.Results[0].grid}</td>
<td>{this.props.teamRacesData.Results[0].position}</td>
</tr>
);
}
}
export default TeamRaceDetails;
Because you call this.getTeamResults() in componentDidMount and this API is async
. So, in the first time of render this.state.teamResults.MRData.RaceTable.Races.Results is undefined. In the second of render, you can got this data.
Try this code:
<tbody>
{teamResults && teamResults.map((race, i) => // make sure teamResults defined
<TeamResults teamRacesData = {race} key={i}/>
)}
</tbody>
When you use map operator to render a list in react, should be check same as above
Or you can defined default parameter like this:
var teamResults = this.state.teamResults.MRData.RaceTable.Races.Results || [];
// teamResults always is an array, will not have an error
Most likely teamResults is not an array. You can mitigate by assigning a default value:
var teamResults = this.state.teamResults.MRData.RaceTable.Races.Results || [];
return (
<div>
<table>
<thead>
<tr>
<th>Round</th>
<th>Grand prix</th>
<th>{this.state.teamResults.position}</th>
<th>{this.state.teamResults.grid}</th>
<th>Points</th>
</tr>
</thead>
<tbody>
{teamResults.map((race, i) => <TeamResults teamRacesData = {race} key={i}/>)}
</tbody>
</table>
</div>
);

Running function without events in render

I'm new with ReactJS and want to ask how functions works here. I have a class, function and render like this :
class MainTable extends React.Component {
constructor(props) {
super(props);
this.state = {
results: []
};
this.getREST = this.getREST.bind(this);
}
getREST() {
console.log(this.props.str)
axios.get(this.props.str)
.then(res => {
const results = res.data.results.map(obj => obj);
this.setState({results});
});
console.log(this.state.results);
}
render() {
return (
<Table hover striped bordered hover responsive size="sm">
<thead>
<tr>
<th>Name</th>
<th>Name</th>
<th>Name</th>
<th>Name</th>
</tr>
</thead>
<tbody>
{this.state.results.map(result =>
<tr key={result.Name}>
<td>{result.Name}</td>
<td>{result.Name}</td>
<td>{result.Name}</td>
<td>{result.Name}</td>
</tr>
)}
</tbody>
</Table>
);
}
}
I can run getRest() function with button event using something like this
<button onClick={this.handleClick.bind(this)} value="Click me" />
But how can i run getRest() function without any events, just in render()?
You should fetch your data in componentDidMount lifecycle method, not in render.
componentDidMount(){
axios.get(this.props.str)
.then(res => {
const results = res.data.results.map(obj => obj);
this.setState({results});
});
}

Resources