I am working on a React component since a long time but for some reason my view doesn't update after doing an ajax call and setting a state.
So, basically, I have a state of clients which is at the beginning an empty array. In the lifecycle method componentDidMount I do an ajax call and in the .then promise I set the state to the response. But for some reason, the view doesn't get updated since the p tag saying "there are no clients" still is there, and a map function I wrote doesn't output any results.
I am sure the clients state is updated since I console.log the result after setting the state and Also in my React dev tools I can see that the clients state has 1 item.
For context, I am using this component in a Laravel project but that doesn't make any difference I guess.
My code
import React, { Component } from 'react';
class Clients extends Component {
constructor(props) {
super(props);
this.state = {
clients: [],
};
}
componentDidMount() {
this.getClients();
}
getClients() {
axios.get('/oauth/clients')
.then(({data}) => {
this.setState({
clients: data,
}, () => {
console.log(this.state.clients);
});
});
}
render() {
const clients = this.state.clients;
return (
<div>
{/* Begin card */}
<div className="card card-default">
<div className="card-header">
<div style={flex}>
<span>
OAuth Clients
</span>
{/* <a class="action-link" tabindex="-1" #click="showCreateClientForm"> */}
<a className="action-link" tabIndex="-1">
Create New Client
</a>
</div>
</div>
<div className="card-body">
{ clients.length === 0 &&
<p className="mb-0">
You have not created any OAuth clients.
</p>
}
<table className="table table-borderless mb-0">
<thead>
<tr>
<th>Client ID</th>
<th>Name</th>
<th>Secret</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{ clients.map(client => {
return (
<tr key={client.id}>
<td style={alignMiddle}>
{client.id}
</td>
<td style={alignMiddle}>
{client.name}
</td>
<td style={alignMiddle}>
{client.secret}
</td>
<td style={alignMiddle}>
<a className="action-link" tabIndex="-1">
Edit
</a>
</td>
<td style={alignMiddle}>
<a className="action-link text-danger">
Delete
</a>
</td>
</tr>
);
}) }
</tbody>
</table>
</div>
</div>
{/* End card */}
</div>
);
}
}
// Styles
const flex = {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
};
const alignMiddle = {
verticalAlign: 'middle',
};
export default Clients;
Am I missing something?
Related
I want to render large lists of data inside a table. I am using the React-List library found online, but when the user scrolls about 200 items, the rest of them take too much time to load.
I achieved something like this:
After about 200 items, I get these warnings in the console, and the list starts to render slower and slower like in the image below:
I use React-List for rendering this table and a get request to get all the data once, code will be shown below.
import React from 'react';
import axios from 'axios';
import { toastr } from '../../../components/toastr/toastr.component';
import { Table } from 'react-bootstrap';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faTrashAlt } from '#fortawesome/free-solid-svg-icons';
import DaysJS from 'react-dayjs';
import Loading from '../../../components/loading/loading.component';
import Tooltip from '../../../components/tooltip/tooltip.component';
import ReactList from 'react-list';
import './error.styles.scss';
class ErrorPage extends React.Component {
constructor() {
super();
this.state = {
pending: true,
errors: []
}
};
componentDidMount() {
axios.get('/api/logError').then(resp => {
this.setState({ pending: false, errors: resp.data });
}).catch(() => toastr('error', 'Eroare la preluarea datelor!'));
};
renderItem = (index, key) => {
return (
<tr key={key}>
<td>
{this.state.errors[index].id}
</td>
</tr>
)
};
renderTable (items, ref) {
return (
<div style={{maxHeight: '400px', overflowY: 'scroll'}}>
<Table bordered striped hover size="sm">
<tbody ref={ref}>
{items}
</tbody>
</Table>
</div>
);
}
renderRow = (index, key) => {
const entry = this.state.errors[index]
return (
<tr key={key}>
<td width='40px' className='text-center'>{index}</td>
<td width='40px' className='text-center'>{entry.id_user}</td>
<td width='200px'>{entry.email}</td>
<td width='200px'>{entry.name}</td>
<td width='200px'>{entry.action}</td>
<td>{entry.error}</td>
<td width='120px' className='text-center'><DaysJS format='DD.MM.YYYY - HH:MM'>{entry.createdAt}</DaysJS></td>
<td width='30px' className='cursor-pointer text-center' data-tip data-for='tooltip'>
<Tooltip id='tooltip' message='Șterge eroare'/>
<FontAwesomeIcon className='text-danger' icon={faTrashAlt} />
</td>
</tr>
);
}
render() {
const { pending, errors } = this.state;
return (
<div className='error-page mt-3 row'>
<Loading pending={pending} />
<div className='col-sm-4 fw-bold'>Total erori: {errors.length}</div>
<div className='col-sm-4'>
<h4 className='text-center'>Erori</h4>
</div>
<div className='col-sm-4 text-end'>
<button className='btn btn-danger btn-sm'>
<FontAwesomeIcon icon={faTrashAlt} className='me-1' />
Șterge toate
</button>
</div>
<div className='col-sm-12'>
<Table bordered size="sm">
<thead>
<tr>
<th width='40px'>Id user</th>
<th width='200px'>Email</th>
<th width='200px'>Unitate</th>
<th width='200px'>Acțiune</th>
<th>Eroare</th>
<th width='120px'>Data</th>
<th width='38px'></th>
</tr>
</thead>
</Table>
<ReactList
itemsRenderer={(items, ref) => this.renderTable(items, ref)}
itemRenderer={this.renderRow}
length={errors.length}
/>
</div>
</div>
);
};
};
export default ErrorPage;
I used in AngularJS a library called ng-infinite-scroll that rendered the items with no problem with infinite scroll and I tried to find something similar for ReactJS.
Here is the Radar chart that I want to update.
Currently, I'm working on an application where once we search for a doctor, the radar chart that's being shown in the picture above should get updated based on the new data received through props. However, what's happening currently is that the chart isn't getting updated immediately even though the text data on the side is getting updated. The chart gets updated only when I refresh the page.
Here is the code for the entire Name component that you see in the picture. As you can see in the code, I'm directly passing the data from the props to the UniversalChart component.
class Name extends Component {
state = {
page_id_name: 1,
hcp_id: 101,
nameData: []
};
render() {
console.log('data inside hcp_overview is: ', this.props)
return (
<div>
<hr style={{ backgroundColor: "light-grey" }} />
<div class="row m-b-lg m-t-lg" >
<div class="col-md-3">
<div >
<div>
<h2 class="no-margins">
{this.props.data[101].overview.name}
</h2>
<h4>{this.props.data[101].overview.designation}</h4>
<h5>{this.props.data[101].overview.specialty}</h5>
<h5>{this.props.data[101].top_three_affiliations[0]}</h5>
</div>
</div>
</div>
<div class="col-md-3" >
<h5 style={{ marginLeft: 10 }}>
<u>Key Details</u>
</h5>
<table class="table small m-b-xs" style={{ fontSize: 12 }}>
<tbody>
<tr>
<td>
<strong>NPI: </strong>{this.props.data[101].overview.npi}
</td>
</tr>
<tr>
<td>
<strong>Gender: </strong>{this.props.data[101].overview.gender}
</td>
</tr>
<tr>
<td>
<strong>Age: </strong>{this.props.data[101].overview.age}
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-3" >
<h5 style={{ marginLeft: 10 }}><u>Top Affiliations</u></h5>
<table class="table small m-b-xs" style={{ fontSize: 12 }} >
<tbody>
<tr>
<td>
{this.props.data[101].top_three_affiliations[0]}
</td>
</tr>
<tr>
<td>
{this.props.data[101].top_three_affiliations[1]}
</td>
</tr>
<tr>
<td>
{this.props.data[101].top_three_affiliations[2]}
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-3" >
<UniversalChart
type={this.props.data[101].chart_data_config.chartType}
data={this.props.data[101].datasets}
options={this.props.data[101].chart_data_config}
labels={this.props.data[101].labels}
key={this.props.data[101].datasets}
/>
</div>
</div>
</div>
)
}
And here is my UniversalChart component which uses ChartJS to display the chart.
class UniversalChart extends Component {
state = {
}
chartRef = React.createRef();
componentDidMount() {
const myChartRef = this.chartRef.current.getContext("2d");
new Chart(myChartRef, {
type: this.props.type,
data: { labels: this.props.labels, datasets: this.props.data },
options: JSON.parse(this.props.options.chartOptions)
})
}
render() {
return <canvas ref={this.chartRef} height={this.props.height} />
}
}
Am I missing something with regards to the React Component Lifecycle method? Just to reiterate, all the data on the right side gets updated but the chart itself doesn't get updated. Please let me know if any additional information needs to be added.
Here is the edited Universal Chart component where I tried the suggestion of #Giovanni Esposito.
class UniversalChart extends Component {
state = {
}
chartRef = React.createRef();
componentDidUpdate(prevProps, prevState) {
if(prevProps.data !== this.props.data){
const myChartRef = this.chartRef.current.getContext("2d");
new Chart(myChartRef, {
type: this.props.type,
data: { labels: this.props.labels, datasets: this.props.data },
options: JSON.parse(this.props.options.chartOptions)
})
}
}
componentDidMount() {
const myChartRef = this.chartRef.current.getContext("2d");
new Chart(myChartRef, {
type: this.props.type,
data: { labels: this.props.labels, datasets: this.props.data },
options: JSON.parse(this.props.options.chartOptions)
})
}
render() {
console.log('props inside render of universal chart is: ', this.props);
console.log('state inside render of univ chart is: ', this.state);
return <canvas ref={this.chartRef} height={this.props.height} />
}
}
I am new with programing and I want to use if ternario, but it doesn't work. I have two functions and I create a third function to show one of them or the other. It is an application in ReactJS. Below is the code:
import { Table } from "react-bootstrap";
import { Link } from "react-router-dom";
import { useCartContext } from "../../Context/CartContext";
const emptyCart = () => {
return(
<>
<div>
<h3>The Cart is empty</h3>
<p>
Return to home to see our products
</p>
<Link to='/' ><button className="btn btn-info"> Home </button></Link>
</div>
</>
);
};
const CartFunction = () => {
const { list, totalPrice } = useCartContext();
return (
<Table striped hover>
<thead>
<tr>
<th>Product</th>
<th>Title</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{list.map((varietal) => (
<tr key={varietal.id}>
<td>
<img
src={varietal.pictureUrl}
alt='img'
style={{ width: "82px" }}
/>
</td>
<td>{varietal.title}</td>
<td>{varietal.count}</td>
<td>${varietal.price}</td>
</tr>
))}
</tbody>
<thead>
<tr>
<td colSpan="3">Total</td>
<td>${totalPrice()}</td>
</tr>
</thead>
</Table>
);
};
const CartComponent = () => {
const { list } = useCartContext();
return (
<>
{list.length !== 0 ? <CartFunction /> : <emptyCart />}
</>
);
};
export default CartComponent;
Visual Code it says that emptyCard has a value but it is never used. If there is someone that could help me I would appreciate it. Cheers
I am trying to hit an api available at covid19 api [ you can see directly , click it ] but I am not able to map through the state.
I tried browsing the questions and still didn't find it .
my code in app.js is
import React, { Component } from 'react'
import api from '../api/covidapi'
import SearchBar from './SearchBar'
class App extends Component {
constructor(props) {
super(props);
this.state = {
country : 'Please Enter the country',
active_cases : 'No country found',
countries : [],
errorMessage : '',
isLoading : false,
};
}
async componentDidMount() {
const response = await api.get('/summary');
console.log('data loaded = > ', response);
console.log(response.data.Countries.length) // giving 247
console.log('countries ', response.data.Countries) //lists all countries {....},{...}...
this.setState({countries:response.data.Countries})
// console.log('global end')
this.setState({
totalConfirmed : response.data.Global.TotalConfirmed,
})
} //component did mount ended.
onSearchSubmit = async (country) =>{
console.log(country)
try {
const response =
await api.get(`/live/country/${country}/status/confirmed`)
this.setState({country:country, active_cases:response.data[6].Active})
}
catch(e) {
this.setState({errorMessage : "Country Doesn't exist or misspelled"})
}
}; //onsearch submit ended.
render() {
return (
<div>
<div className="container">
<p style={{textAlign:'center',
backgroundColor:'green',
color:'white',
width:'97%',margin:'auto',
padding:'24px',
marginTop:'12px',}}>
Total confirmed as of now is <span> : </span>
<span style={{color : 'red'}} >
{this.state.totalConfirmed}
</span>
</p>
<SearchBar onSubmit = {this.onSearchSubmit}/>
</div>
<div className="container">
<h2 className="bg bg-primary" style={{marginBottom:'0px',
textAlign:'center',marginTop:'15px',
padding:'10px'}}>Covid19 Cases In single Country
</h2>
<table className="table table-striped">
<thead>
<tr>
<th>Country</th>
<th>Acitve Cases</th>
</tr>
</thead>
<tbody>
<tr>
<td>{this.state.country}</td>
<td>{ this.state.active_cases}</td>
</tr>
</tbody>
</table>
</div>
<br />
<hr />
<div className="container">
<div style={{textAlign:'center',color:'red',fontWeight:'bold'}}>
</div>
<h2 className="bg bg-primary" style={{marginBottom:'0px',
textAlign:'center', padding:'10px'}}>
Covid19 Cases Worldwide
</h2>
<table className="table table-striped table-hover table-dark">
<thead>
<tr>
<th>S.N</th>
<th>Country Name</th>
<th>Confirmed Cases</th>
<th> Total Deaths</th>
<th>Total Recovered</th>
</tr>
</thead>
<tbody>
{
Object.keys(this.state.countries).map((country) => (
<tr>
<td>{country}</td>
<td>........</td>
<td>........</td>
<td> ........</td>
<td>............</td>
</tr>
))
}
</tbody>
</table>
</div>
</div>
);
}
}
export default App;
and covidapi.js code is
import axios from 'axios'
export default axios.create({
baseURL :'https://api.covid19api.com'
})
The problem is in this section of the code in app.js
{
Object.keys(this.state.countries).map((country) => (
<tr>
<td>{country}</td>
<td>........</td>
<td>........</td>
<td> ........</td>
<td>............</td>
</tr>
))
}
I am not able to map through countries in my state , I think there is
problem with the Objects and array.
when Render the country that is passed in map it return the integer value like 1,2,3 .... and not able to get other values.
Response in the console looks like this
What I am trying is to display the all the countries list to the table whenever the application loads.
You can use this.state.countries directly without Object.keys() (It is an array already), and use the properties inside each item as follows:
{
this.state.contries.map(item => {
return(
<tr>
<td> { item.Country } </td>
<td> { item.totalConfirmed } </td>
... // Other tds
</tr>
)
}
}
I have a child component PatientRow which is receiving mapped patients array in props from it’s parent ObsTabel. The odd thing is the PatientRow is never rendered and I can’t find the PatientRow component on React Dev tools either. On the other hand if I just pass the patients array then map it in PatienRow the components gets rendered, however this is not what I want. I want to map the array in ObsTabel & pass it to PatientRow so that the rows are individual component with their own state. Please let me know if you can find my mistakes.
Note: ObsTable has a parent component from where it is receiving patient array passed as props. file structure - ParentComponent(with patient array).js>ObsTable.js>PatientRow.js
This doesn’t exist in DOM
export default class PatientRow extends React.Component {
constructor(props) {
super(props);
this.state = {
disabled: false
};
}
render() {
const { id, label, name, room, timestamp, observationLevel, roomStatus, patient, index } = this.props;
console.log(this.props);
return (
<tbody>
<tr key={id} >
<td>{label}</td>
<td>{name}</td>
<td>{observationLevel}</td>
<td>{roomStatus}</td>
<td>{timestamp} </td>
<td>
<div>
<Button> Awake </Button>
<Button>Asleep/Breathing</Button>
</div>
<Button> View Room </Button>
<div>
<Button>Awake </Button>
</div>
</td>
<td>
<Button>Asleep</Button>
</td>
</tr>
</tbody>
);
}
}
export default class ObsTabel extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div >
<Table bordered striped hover >
<thead>
<tr>
<th>Room</th>
<th>Patient Name</th>
<th> Obs Level </th>
<th>Room Status</th>
<th>Obs Due In</th>
<th>Patient Location</th>
<th>Patient Obs Detail</th>
<th>Comment</th>
</tr>
</thead>
{this.props.patients.map((patient, index) => {
// console.log(patient); logs each patient
<div key={index}>
<PatientRow
name={patient.name}
id={patient.id}
label={patient.label}
room={patient.room} observationLevel={patient.observationLevel}
roomStatus={patient.roomStatus}
timestamp={patient.timestamp}
index={index}
/>
</div>;
})}
</Table>
</div>
</div>
);
}
}
it's because you are not returning anything inside map
return (
<div key={index}>
<PatientRow
name={patient.name}
id={patient.id}
label={patient.label}
room={patient.room}
observationLevel={patient.observationLevel}
roomStatus={patient.roomStatus}
timestamp={patient.timestamp}
index={index}
/>
</div>
);