setState | componentDidMount not updating correctly - react-views - javascript

I am having a lot of trouble with componentDidMount() and setState. from what I can tell setState is updating since I am able to print the results within my getData function, but I am not able to print it in the render, or componentDidMount(). I think the issue might be that it is rendering before the state is updated or componentDidMount is not triggering correctly. I have been stuck on this problem forever now and I can't seem to figure it out.
I am using express-react-views to render on the server side.
const React = require ('react');
const Head = require ('../components/Head.jsx');
const Nav = require ('../components/Nav.jsx');
const Footer = require ('../components/Footer.jsx');
const getPipeLine = require('../../service/Contructor.js');
class ActiveLoans extends React.Component {
constructor(props) {
super(props)
this.state = {
FinalData: {}
};
this.getData = this.getData.bind(this)
};
async getData (){
try{
let display = new getPipeLine;
const data = display.then((FinalData) => {
this.setState({FinalData},
(async ()=> {console.log('state set', FinalData)})()) //returns correct results
}, 1000);
return data
} catch (err) {
console.log(err.message)
}}
async componentDidMount() {
try{
await this.getData(FinalData);
(async ()=> {console.log('mount', await this.getData())})() //returns nothing
} catch(err) {
console.log(err.message)
}
}
render(){
(async ()=> {console.log('Render', await this.getData())})() //returns undefined
return(
<React.Fragment>
<Head />
<Nav />
{Array.isArray(this.getData) && this.getData?.map((results) => (
<div key = {results.a.LoanNumber} >
<table>
<thead>
<tr>
<th>Loan Number</th>
<th>Loan Status</th>
<th>Loan Type</th>
<th>Submit Date</th>
<th>Last Review</th>
</tr>
</thead>
<tbody>
<tr>
<td>{results.a.LoanNumber}</td> //displays nothing
<td>{results.a.LoanStatus}</td>
<td>{results.a.LoanType}</td>
<td>{results.a.SubmitDate}</td>
<td>{results.a.LastReview}</td>
</tr>
</tbody>
</table>
</div>
))
}
<Footer />
</React.Fragment>
)}}
module.exports = ActiveLoans;
this is the first few results that I am trying to display
a: {
'0': {
LoanNumber: 12345252,
LoanStatus: 'Initial',
LoanType: 'FHA',
SubmitDate: '1/14/2022',
LastReview: null
},
'1': {
LoanNumber: 12345626,
LoanStatus: 'Initial',
LoanType: 'VA',
SubmitDate: '1/14/2022',
LastReview: null
},
'2': {
LoanNumber: 12345670,
LoanStatus: 'Initial',
LoanType: 'Conventional',
SubmitDate: '1/14/2022',
LastReview: null

Related

Unable to render data from API in React, no errors displayed

I am using Django Rest Framework to send data to React app. But the data is being shown on screen.
The code isnt returning any errors thus making it difficult to see whats going wrong. This is my second React project thus i am not too familiar with React & JS as of now.
This is my code:
import { render } from "#testing-library/react";
import axios from "axios";
import React, { Component, useState, useEffect } from "react";
const api_url = "http://localhost:8000/api/CBView/"
class StocksHomePage extends Component {
constructor(props) {
super(props);
this.state = {
isFetching:false,
data_s :[]
};
}
componendDidMount() {
this.fetchData();
this.timer = setInterval(() => this.fetchData(), 50);
}
fetchData = () => {
this.setState({...this.state, isFetching:true});
axios.get(api_url)
.then (response => {
this.setState({data_s:response.data[0]})
})
.catch(e => {
console.log(e);
this.setState({...this.state, isFetching:false});
});
};
render() {
return (
<div>
{this.state.data_s.map(m => <p>{m.co_S}</p>)}
{/* <p data={this.state.data_s.co_S} ></p> */}
<ul>
<li isKey dataField='co_N'></li>
<li dataField='co_S'></li>
<li dataField='price'></li>
</ul>
<p>{this.state.isFetching ? 'Fetching users...' : ''}</p>
</div>
)
}
}
I fixed the issue, all i had to do was include maps function with variable to represent those values. Here is my code:
class StocksHomePage extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
loaded: false,
placeholder: "loading"
};
}
componentDidMount() {
axios
.get("http://localhost:8000/CBView")
.then(response => {return response.data; })
.then(data => {this.setState(() => {
return {data, loaded:true};
});
});
}
handleClick = (props) => {
<HashRouter>
<Route path='/StocksDetail' component={StocksDetail} />
</HashRouter>
};
render() {
return (
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Price/ Chng</th>
<th>Mkt Cap</th>
<th>Volume</th>
<th>Turnover</th>
</tr>
</thead>
<tbody>
{this.state.data.map(item => {
return (
<tr key={item.co_S}>
<button onCLick={this.handleClick(item.co_S)}><td >{item.co_N}</td></button>
<td>{item.price}</td>
<td>{item.p_chng_pc}</td>
<td>{item.Mkt_cap}</td>
<td>{item.volume}</td>
<td>{item.volume * item.price}</td>
</tr>
);
})};
</tbody>
</table>
);
}
}
export default StocksHomePage;

React componentDidMount not firing and not updating state in electron app

Im creating a electron-react app and I'm using this boilerplate https://github.com/willjw3/react-electron
Im trying to fetch data from an API, Im able to get the data but im unable to update state using setState. componentDidMount is not firing as well. Am I setting something up wrong? Heres my code.
import React from "react"
import '../css/table.css'
const fs = window.require('fs');
const electron = window.require('electron')
const shell = electron.shell
const stockxAPI = window.require('stockx-api');
const stockX = new stockxAPI();
const scrapeStockx = (link, size) => {
let lowestAsk
return stockX.fetchProductDetails(link)
.then((response) => {
let productData = response.variants
//console.log(productData)
for (let product of productData){
if (product.size == size){
lowestAsk = product.market.lowestAsk
return '$' + lowestAsk
}
}
})
}
const fetchNewData = async (myProducts) => {
for (let product of myProducts){
let goatUrl = 'https://www.goat.com/web-api/v1/product_variants?productTemplateId='
let goatSKU = product.Goat[0].split('sneakers/')[1]
let ogUrl = goatUrl + goatSKU
let price = await scrapeStockx(product.Stockx[0], product.Size)
product.Stockx[1] = price
console.log('Product Size: ' + product.Stockx[1])
}
return myProducts
}
class ProductTable extends React.Component{
constructor(){
super()
this.state = {
Products : ''
}
this.renderTableData = this.renderTableData.bind(this)
this.updateProducts = this.updateProducts.bind(this)
}
async componentDidMount(){
this.setState({Products : 'Loading...'});
let myProducts = await this.updateProducts()
console.log('Component ' + myProducts)
this.setState({Products : myProducts})
console.log('Component' + this.state)
}
async updateProducts () {
let rawData = fs.readFileSync('/Users/yunioraguirre/Desktop/Lucky Cops Item Tracker V1/Lucky Item Tracker/MyProducts.json')
let myProducts = JSON.parse(rawData)
//Updates Goat and Stockx Prices
myProducts = await fetchNewData(myProducts)
try {
await fs.writeFileSync('MyProducts.json', JSON.stringify(myProducts, null, 2))
console.log('Success!')
console.log(myProducts)
} catch (error) {
console.log(error)
}
return myProducts
}
renderTableData = () => {
return this.state.Products.map( product => {
const {Id, Item, sku, Size, Sold, Goat, Stockx} = product
return (
<tr key={Id}>
<td>{Id}</td>
<td>{Item}</td>
<td>{sku}</td>
<td>{Size}</td>
<td>{product["Total Amount Paid"]}</td>
<td>{Sold}</td>
<td>{product['Price Sold For']}</td>
<td> {Goat[1]}</td>
<td> {Stockx[1]}</td>
<td> {product['Flight Club']}</td>
</tr>
)
})
}
renderTableHeader = () => {
console.log('State in Render' + JSON.stringify(this.state.Products))
let header = Object.keys(this.state.Products[0])
return header.map((key, index) => {
return <th key={index}>{key.toUpperCase()}</th>
})
}
render(){
return (
<div id='Table-Wrapper'>
<h1 id='TableTitle'>Total Products</h1>
<table id='Products Table'>
<tbody>
<tr>{this.renderTableHeader()}</tr>
{this.renderTableData()}
</tbody>
</table>
</div>
)
}
}
export default ProductTable
Heres what I get in the console
The issue is you provide an empty string as initial state. The first console log is from the render function and the second is from this.renderTableHeader. The problem happens when you hit this line: let header = Object.keys(this.state.Products[0])
Object.keys(""[0])
You may want to try creating a separate "isLoading" state, and conditionally render JSX on that.
this.state = {
Products : '',
isLoading: false,
}
...
async componentDidMount(){
this.setState({isLoading: true});
let myProducts = await this.updateProducts()
console.log('Component ' + myProducts)
this.setState({Products: myProducts, isLoading: false})
}
....
render(){
if (this.state.isLoading) {
return <div>Loading...</div>;
}
return (
<div id='Table-Wrapper'>
<h1 id='TableTitle'>Total Products</h1>
<table id='Products Table'>
<tbody>
<tr>{this.renderTableHeader()}</tr>
{this.renderTableData()}
</tbody>
</table>
</div>
)
}
I was able to fix my code. As Drew stated, I needed a isLoading variable in state so I could render and fetch my data. Heres my updated State and ComponentDidMount
class ProductTable extends React.Component{
constructor(){
super()
this.state = {
Products : '',
isLoading : true
}
this.renderTableData = this.renderTableData.bind(this)
this.updateProducts = this.updateProducts.bind(this)
}
async componentDidMount(){
let myProducts = await this.updateProducts()
console.log('Component ' + JSON.stringify(myProducts))
console.log('\n')
await this.setState({Products : myProducts, isLoading : false})
//console.log(JSON.stringify(this.state))
}
}

Setting default table order in Reactjs

I am working with a table and I am trying to figure out is there a way to set the default order to ASC when the page loads?
class Orders extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [
{orders: 'Vanilla', date: '03/15/1990'},
{orders: 'Chocolate', date: '03/15/1989'},
],
sortingOrder: 'ASC'
};
this.sortBy.bind(this);
}
renderTableData() {
return this.state.data.map((data, index) => {
const{orders, date} = data
return (
<tr key={index}>
<td>{orders}</td>
<td>{date}</td>
</tr>
)
})
}
sortBy(sortedKey) {
const data = this.state.data;
let sortingOrder = this.state.sortingOrder;
if(sortingOrder === 'ASC') {
sortingOrder = 'DESC';
data.sort((a,b) => b[sortedKey].localeCompare(a[sortedKey]))
}
else {
sortingOrder = 'ASC';
data.sort((a,b) => a[sortedKey].localeCompare(b[sortedKey]))
}
this.setState({data, sortingOrder })
}
render() {
return (
<table id="orders">
<thead>
<tr className="header">
<th>Order</th>
<th onClick={() => this.sortBy('date')}>Date</th>
</tr>
</thead>
<tbody>
{this.renderTableData()}
</tbody>
</table>
);
}
}
I tried calling this.sortBy() in my render method first, but that gave me an error about too many calls. Any ideas?
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
you can do on componentDidMount for default
componentDidMount(){
this.sortBy('ASC');
}
you should use the comopnentDidMount method
https://reactjs.org/docs/react-component.html#componentdidmount
componentDidMount(){
this.sortBy('date');
}

Datatable functions are not working with Reactjs

I'm using Datatable Library to draw table easily.
And I got a data with Fetch API and render to table and It works well. But I don't know why DataTable Funcions like sorting, searching, showing options.
As you see, get data from API and render to HTML are works well, but when I click sort or search function it changes to this.
Also Another functions like interval the data from API every 10 seconds and render to table are works well.
It seems that there are some problem in initial state.
import React, { Component } from 'react';
import './PostContainer.css';
class PostContainer extends Component {
constructor(props) {
super(props);
this.state = {
tableData: {
status: '0000',
data: {
loading: { sell_price: 'loading', volume_7day: 'loading' },
},
},
};
}
async componentDidMount() {
this.getData();
this.interval = setInterval(() => {
this.getData();
}, 10000);
}
getData() {
fetch('https://api.bithumb.com/public/ticker/all')
.then(res => {
const data = res.json();
return data;
})
.then(res => {
this.setState({
tableData: res,
});
})
.catch(error => {
console.error(error);
});
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
let data = this.state.tableData;
let chart = [];
console.log(data);
if (data.status === '0000') {
delete data.data['date'];
for (let [key, value] of Object.entries(data.data)) {
chart.push(
<tr key={key}>
<td>{key}</td>
<td>{value.sell_price}</td>
<td>{value.volume_7day}</td>
</tr>
);
}
} else if (
data.status === '5500' ||
data.status === '5600' ||
data.status === '5900'
) {
this.setState({
tableData: {
data: {
ERROR: {
sell_price: 'ERROR with API',
volume_7day: 'ERROR with API',
},
},
},
});
}
return (
<div className="Post">
<table id="table" className="table table-striped table-bordered">
<thead>
<tr>
<th>Coin Name</th>
<th>Current Price</th>
<th>Volume</th>
</tr>
</thead>
<tbody>{chart}</tbody>
</table>
</div>
);
}
}
export default PostContainer;
Can access to DEMO directly. I uploaded to Github Pages.
I can think of 2 issue to look for
a.
If you see in screenshot there is no Pagination.
When I try load DEMO with Developer Console open.
It works fine and you will see Pagination which will show 10 record at a time.
Check your code for Datatable initialization code in index.js
$('#table').DataTable({
order: [[1, 'desc']],
});
Make sure above code is called after Data is loaded in HTML
b.
Your state value is not updated to actual values while sorting
tableData: {
status: "0000",
data: {
loading: {
sell_price: "loading",
volume_7day: "loading"
}
}
}

Select table cell in react bootstrap table

export class UsersTable extends React.Component {
constructor() {
super();
this.state = {
info: null
};
}
componentWillMount() {
fetch("http://localhost:8081/milltime/getUsers")
.then(res => res.json())
.then(info => {
this.setInfo(info);
});
}
setInfo(info) {
const state = this.state;
state['info'] = info;
this.setState(state);
}
render() {
const info = this.state.info;
if (!this.state.info) {
return null;
}
let listItems = [];
for (var i = 0; i < info['mta:getUsersResponse']['mta:users'].length; i++) {
listItems.push(
<tr>
<td>{info['mta:getUsersResponse']['mta:users'][i]['mta:UserId']}</td>
<td>{info['mta:getUsersResponse']['mta:users'][i]['mta:FullName']}</td>
<td>{info['mta:getUsersResponse']['mta:users'][i]['mta:CostHour']}</td>
</tr>);
}
return(
<div className="usersTable">
<Table striped bordered condensed responsive hover>
<thead>
<tr>
<th>Id</th>
<th>Full Name</th>
<th>Hour cost</th>
</tr>
</thead>
<tbody>
{listItems}
</tbody>
</Table>
</div>
);
}
}
This is the code I have for a table that get users and displays 3 columns of data. What I am having problems doing is being able to select a table and by selecting that table get the data in that cell and use it to search with the help of the id of the user in the selected cell. Has anyone got a neat solution? I'm using React bootstrap.
Bind your onClick handler when your creating the row.
See comments in code.
https://reactjs.org/docs/handling-events.html
export class UsersTable extends React.Component {
constructor() {
super();
this.state = {
info: null
};
}
componentWillMount() {
fetch("http://localhost:8081/milltime/getUsers")
.then(res => res.json())
.then(info => {
this.setInfo(info);
});
}
setInfo(info) {
const state = this.state;
state['info'] = info;
this.setState(state);
}
onSelectedRow(user, clickEvent){
//your user object and the click event
//clickEvent.currentTarget = the cell clicked
}
render() {
const info = this.state.info;
if (!this.state.info) {
return null;
}
let listItems = [];
for (var i = 0; i < info['mta:getUsersResponse']['mta:users'].length; i++) {
const user = info['mta:getUsersResponse']['mta:users'][i]; //dryer
//Bind you onclick handler to the context and you user object (or id if thats what you want)
listItems.push(
<tr onClick={this.onSelectedRow.bind(this, user)}>
<td>{user['mta:UserId']}</td>
<td>{user['mta:FullName']}</td>
<td>{user['mta:CostHour']}</td>
</tr>);
}
return(
<div className="usersTable">
<Table striped bordered condensed responsive hover>
<thead>
<tr>
<th>Id</th>
<th>Full Name</th>
<th>Hour cost</th>
</tr>
</thead>
<tbody>
{listItems}
</tbody>
</Table>
</div>
);
}
}
Api requests should be handled in componentDidMount lifecycle event as described in React docs.
Also, your are mutating your state on setInfo and this is not a good practice either. You can directly update your state like:
setInfo(info) {
this.setState({
info: info,
})
}
or simply using object shorthand
setInfo(info) {
this.setState({
info,
})
}
Should your api change in the future, you are gonna have problems replacing all the mta:** in your code. Why don't you map them upon state?
this.setState({
info: {
users: info['mta:getUsersResponse']['mta:users'].map(user => ({
id: user['mta:UserId'],
fullName: user['mta:FullName'],
costHour: user['mta:CostHour'],
}))
}
})
Click handling becomes easier from now, just create a UserRow component, send user as prop and propagate changes on onClick.
const UserRow = ({ user, onClick }) =>
<tr onClick={onClick}>
<td>{user.id}</td>
<td>{user.fullName}</td>
<td>{user.costHour}</td>
</tr>
Now you can map though your state and propagate props to it:
const UserRow = ({ user, onClick }) =>
<tr onClick={onClick}>
<td>{user.id}</td>
<td>{user.fullName}</td>
<td>{user.costHour}</td>
</tr>
class App extends React.Component {
constructor() {
super()
this.state = {
info: {
users: [
{ id: 0, fullName: 'User 1', costHour: 100 },
{ id: 1, fullName: 'User 2', costHour: 50 },
{ id: 2, fullName: 'User 3', costHour: 150 }
]
}
}
this.handleUserClick = this.handleUserClick.bind(this)
}
handleUserClick(user) {
console.log(`user ${user.id} has been clicked`)
}
render() {
return (
<div className="usersTable">
<table striped bordered condensed responsive hover>
<thead>
<tr>
<th>Id</th>
<th>Full Name</th>
<th>Hour cost</th>
</tr>
</thead>
<tbody>
{this.state.info.users.map(user =>
<UserRow
key={user.id}
user={user}
onClick={this.handleUserClick.bind(this, user)}
/>
)}
</tbody>
</table>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<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="root"></div>

Categories

Resources