I am attempting to load data into a table using react, and I got to the point where the data does exist when attempting to render the fragment, however, it doesn't seem to actually update the dom and render (I tested and know the data DOES in fact exist when it runs the fragment in the {} block under tbody. Any help would be awesome, thank you.
import React from 'react';
class InvoicePickTable extends React.Component {
constructor(props) {
super(props);
this.state = {invoices:[]};
}
getInvoiceData(){
return new Promise(function(resolve, reject) {
console.log("hi");
resolve([{number: "1"},{number: "2"},{number: "3"}]);
})
}
componentDidMount() {
const self = this;
self.getInvoiceData()
.then((response) => {
self.setState({invoices: response});
})
.catch((err) => {
console.error(err);
});
}
render() {
return (
<table>
<thead>
<tr>
<th>Invoice #</th>
<th>Task Price</th>
<th>Balance</th>
<th>Task Name</th>
</tr>
</thead>
<tbody>
{
this.state.invoices.forEach(function (invoice) {
console.log("in");
console.log(invoice);
return (
<tr>
<td>{invoice.number}</td>
</tr>
);
})
}
</tbody>
</table>
);
}
}
export default InvoicePickTable;
Use
this.state.invoices.map(invoice => <tr><td>{invoice.number}</td></tr>)
in your render function. Array.forEach does not actually return an array
I fixed it, you need to use MAP not FOR EACH, hope this helps someone!
import React from 'react';
class InvoicePickTable extends React.Component {
constructor(props) {
super(props);
this.state = {invoices:[]};
}
getInvoiceData(){
return new Promise(function(resolve, reject) {
console.log("hi");
resolve([{number: "1"},{number: "2"},{number: "3"}]);
})
}
componentDidMount() {
const self = this;
self.getInvoiceData()
.then((response) => {
self.setState({invoices: response});
})
.catch((err) => {
console.error(err);
});
}
render() {
return (
<table>
<thead>
<tr>
<th>Invoice #</th>
<th>Task Price</th>
<th>Balance</th>
<th>Task Name</th>
</tr>
</thead>
<tbody>
{
this.state.invoices**.map**(function (invoice) {
console.log("in");
console.log(invoice);
return (
<tr **key = {invoice.number}**>
<td>{invoice.number}</td>
<td>1231</td>
<td>4</td>
<td>A Task</td>
</tr>
);
})
}
</tbody>
</table>
);
}
}
export default InvoicePickTable;
here is a good example of rendering the data with ajax and map function.
Related
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
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');
}
Here is my App.js
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
employees: []
};
}
loadEmployees() {
fetch('http://localhost:8080/Employee')
.then((response) => response.json())
.then((responseData) => {
this.setState({
employees: responseData
});
});
}
componentDidMount() {
this.loadEmployees();
}
render() {
return (
<EmployeeList employees={this.state.employees}/>
)
}
}
export default App;
Here is the Employee.js
class Employee extends React.Component {
render() {
return (
<tr>
<td>{this.props.employee.firstName}</td>
<td>{this.props.employee.lastName}</td>
<td>{this.props.employee.description}</td>
</tr>
)
}
}
export default Employee;
And EmployeeList.js
class EmployeeList extends Component {
render(){
var employees = this.props.employees.map(employee =>
<Employee key={employee._links.self.href} employee={employee}/>
);
return (
<table>
<tbody>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Description</th>
</tr>
{employees}
</tbody>
</table>
)
}
}
export default EmployeeList;
I have spring-boot rest point at the http://localhost:8080/Employee
Here is my Controller class.
#RestController
public class EmployeeController {
#Autowired
EmployeService employeeService;
#RequestMapping(value="/Employee")
public List<Employee> defaultEmployee() {
return employeeService.getAllData();
}
}
I am returning List<Employee>, it turns to JSON, when I try to catch this result, here is the error.
The Rest returns employees from the DB, but i can not map it into the list.
Can anyone tell me what is the problem?
Make sur that the this.state.employees is an array , the things in react the component will render no mather if the value of the props are empty or not
and the map function will trow an error if you try to pass an empty array
so on your EmployeeList.js added this code
class EmployeeList extends Component {
render(){
var employees = <div>Loading</div>
if(this.props.employees.length > 0){
employees = this.props.employees.map(employee =>
<Employee key={employee._links.self.href} employee={employee}/>
);
}
return (
<table>
<tbody>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Description</th>
</tr>
{employees}
</tbody>
</table>
)
}
}
Please test it and let me know if it work
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>
I am trying to edit a row of table containing person objects. My idea is to show the table and after clicking on the row to edit, the row changes to 2 textBoxes (Nameand surnameto edit) and a button to confirm edit operation. When I run the program the table shows 4 times its size(I have 4 rows) and when I click on a random row disappears 4 rows and the table becomes 3 times its size(12 rows).
What is causing the fail? Thanks for your time
The code:
class EditPersons extends React.Component {
constructor(props) {
super(props);
this.state = {
editing: null
};
this.editPerson = this.editPerson.bind(this);
}
componentDidMount() {
this.props.fetchData('http://localhost:9536/persons/');
}
editPerson(person) {
this.setState(
{ editing: person.PersonId }
);
}
renderPersonOrEdit(person) {
if (this.state.editing === person.PersonId) {
console.log('editing: ' + person.PersonId); //test ok
//Here comes the 2 textBoxes and the edit-button
}
else {
return (
<tbody>
{this.props.persons.map((person, i) => {
return(
<tr key={i}>
<td onClick={()=>this.editPerson.(person)}><Link>{person.Name}<Link></td>
<td>{person.Surname}</td>
</tr>
);
})}
</tbody>
);
}
}
render() {
if (this.props.hasErrored) {
return <p>Downloading has failed!</p>;
}
if (this.props.isLoading) {
return <p>Downloading…</p>;
}
return (
<div>
<table id="myTable">
<thead>
<tr>
<th>Person name</th>
<th>Person Surname</th>
</tr>
</thead>
{this.props.persons.map((person) => {
return this.renderPersonOrEdit(person);
})}
</table>
<Link to="/project" className="btn btn-primary btn-xs" style={{marginTop: 20}}>Back</Link>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
personss: state.persons,
hasErrored: state.personsHasErrored,
isLoading: state.personsIsLoading
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(personsFetchData(url))
};
};
EditPersons.propTypes = {
fetchData: PropTypes.func.isRequired,
persons: PropTypes.array.isRequired,
hasErrored: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired
};
export default connect(mapStateToProps, mapDispatchToProps)(EditPersons);
In your render() function you are already mapping over the elements and then in the renderPersonOrEdit you are doing the same, change your code to map at only the render function
class EditPersons extends React.Component {
constructor(props) {
super(props);
this.state = {
editing: null
};
this.editPerson = this.editPerson.bind(this);
}
componentDidMount() {
this.props.fetchData('http://localhost:9536/persons/');
}
editPerson(person) {
this.setState(
{ editing: person.PersonId }
);
}
renderPersonOrEdit() {
if (this.state.editing !== null) {
console.log('editing: ' + person.PersonId); //test ok
//Here comes the 2 textBoxes and the edit-button
//set editing to null after editing the contents
}
else {
return <tbody>
{this.props.persons.map((person) => {
return (
<tr key={person.PersonId}>
<td onClick={()=>this.editPerson.(person)}><Link>{person.Name}<Link></td>
<td>{person.Surname}</td>
</tr>
);
})}
</tbody>
}
}
render() {
if (this.props.hasErrored) {
return <p>Downloading has failed!</p>;
}
if (this.props.isLoading) {
return <p>Downloading…</p>;
}
return (
<div>
<table id="myTable">
<thead>
<tr>
<th>Person name</th>
<th>Person Surname</th>
</tr>
</thead>
{this.renderPersonOrEdit()}
</table>
<Link to="/project" className="btn btn-primary btn-xs" style={{marginTop: 20}}>Back</Link>
</div>
);
}
}