Unable to render state, but can console.log it - reactjs

I have a state defined like this:
state = {
items: [
{id: 0, value: 0},
{id: 1, value: 0},
],
};
when I console.log(this.state.items[0].id) in the the constructor, I get the correct value.
But when I try to render it like this:
render() {
return (
<div>
<table>
<tr>
<th id="d0" onClick={(e)=>this.onClick(e)}>{this.state.items[0].id}</th>
....
It says "Cannot read property '0' of undefined"
Is the render happening before the state gets initialized, and therefore is undefined when it tries to render?
class App extends React.Component {
/**
* #param {object} props
*/
state = {
items: [
{ id: 0, value: 0 },
{ id: 1, value: 0 },
],
};
constructor(props) {
super(props);
console.log(this.state.items[0].id);
}
render() {
return (
<div>
<table>
<tbody>
<tr>
<th id="d0" onClick={(e) => this.onClick(e)}>th</th>
<th id="d1">h</th>
</tr>
</tbody>
</table>
</div>
);
}
onClick(e) {
this.setState({ day0: 6 });
}
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>

Your state should be set within your constructor
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [
{ id: 0, value: 0 },
{ id: 1, value: 0 },
]
}
}
render() {
return (
<div>
<table>
<tr>
<th id="d0" onClick={(e)=>this.onClick(e)}>{this.state.items[0].id}</th>
</tr>
</table>
</div>
);
}
}

You are initializing the state incorrectly. States should be initialized inside the constructor in class based components. Please update the state initialization as :
class App extends React.Component {
/**
* #param {object} props
*/
constructor(props) {
super(props);
this.state = {
items: [
{ id: 0, value: 0 },
{ id: 1, value: 0 },
],
};
}
render() {
return (
<div>
<table>
<tbody>
<tr>
<th id="d0" onClick={(e) => this.onClick(e)}>{this.state.items[0].id}</th>
<th id="d1">h</th>
</tr>
</tbody>
</table>
</div>
);
}
onClick(e) {
this.setState({ day0: 6 });
}
}
ReactDOM.render(<App />, document.querySelector('.react'));

Related

Rendering array inside object to a table using react

I'm new in React and I stuck with this.
Suppose I have a state like this
state = {
dataSource: {
model: ["Slip on", "Running", "Sneaker"],
colors: ["Dark", "Light", "Colorful"],
activity: ["School", "Hang out", "Rest"],
}
};
I want to render a table with the header as the name of the object inside dataSource and value correspond to that object.
I already tried using map() and cause I knew that map() can not be used on object I tried to change the state like this
state = {
dataSource: [
["Slip on", "Running", "Sneaker"],
["Dark", "Light", "Colorful"],
["School", "Hang out", "Rest"],
]
};
then try to solve it like this
render() {
<table>
<tbody>
{this.state.dataSource.map((c) => (
<tr>
{c.map((x) => (
<td>{x}</td>
))}
</tr>
))}
</tbody>
</table>
}
it did render the value but not the right way, so I wonder if there is a way to do it? Thanks for your help :)
Object.keys might help
const { Component } = React;
class App extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: {
model: ["Slip on", "Running", "Sneaker"],
colors: ["Dark", "Light", "Colorful"],
activity: ["School", "Hang out", "Rest"],
}
};
}
render() {
const { dataSource } = this.state;
const arr = Array(dataSource.model.length).fill(0);
return <table>
<thead>
<tr>
{Object.keys(dataSource).map(pr => <th key={pr}>{pr}</th>)}
</tr>
</thead>
<tbody>
{arr.map((pr, index) => <tr key={index}>
{Object.keys(dataSource).map(key => <td key={key}>{dataSource[key][index]}</td>)}
</tr>)}
</tbody>
</table>
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>
Map can not work. In case of objects you should use objects methods, for example something like
return
Object.entries(state.dataSource).map(([key: tableName, value]) =>
<div>
<h1>{tableName}</h1>
{value.map(v => <div>{v}</div>}
</div>
)

Child component should render similar child component as sibling in parent component

I am new to react so bear any nontechnical words.
I have parent component that displays the table headers, now next is child component which has tables' td along with one td is add button when the user clicks on add button. The similar child component should be added as a sibling to previous child component and this process should go on.
Child Component:
class ChildComp extends React.Component{
state = {
Avalue: {value: ''},
Bvalue: {value: ''},
Cvalue: {value: ''},
Dvalue: {value: ''},
Evalue: {value: ''},
Fvalue: {value: ''},
Gvalue: {value: ''},
}
AddanotherSimilarChildcomp=(e)=>{
e.preventDefault();
const historyData = {
A: this.state.A.value,
B:this.state.B.value,
C: this.state.C.value,
D: this.state.D.value,
E: this.state.E.value,
F: this.state.F.value,
G: this.state.G.value,
}
console.log(historyData);
//and should render another similar ChildComp component below the one in which the current ChildComp is present
}
handleChange=(e)=>{
e.preventDefault();
const target = e.target;
const inputName = target.name;
const inputValue = target.value;
this.setState({
[inputName] : {
value: inputValue,
}
});
}
render(){
return(
<tbody id="first-table-row">
<tr>
<td data-th="A"><input type="text" minmax="40" name="A" value={this.state.a.value} onChange={this.handleChange} /></td>
<td data-th="B"><input type="date" minmax="40" name="B" value={this.state.B.value} onChange={this.handleChange} /></td>
<td data-th="C"><input type="text" minmax="225" name="C" value={this.state.C.value} onChange={this.handleChange} /></td>
<td data-th="D"><input type="text" minmax="40" name="D"value={this.state.D.value} onChange={this.handleChange} /></td>
<td data-th="E"><input type="text" minmax="40" name="E" value={this.state.E.value} onChange={this.handleChange} /></td>
<td data-th="F"><input type="text" minmax="40" name="F" value={this.state.F.value} onChange={this.handleChange} /></td>
<td data-th="G">
<div id="samerow">
<span>{this.props.somedata}</span>
<input type="text" minmax="40" name="G"value={this.state.G.value} onChange={this.handleChange} />
</div>
</td>
<td className="save" ><button id="save-btn" onClick={this.AddanotherSimilarChildcomp} type='button'>Add</button></td>
</tr>
</tbody>
)
}
}
Parent Component:
class ParentComponent extends React.PureComponent{
render(){
return(
<div className='table-center' id='table1'>
<table className="rwd-table" id="tblBlah" >
<tbody>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
<th>F</th>
<th>G</th>
<th> </th>
</tr>
</tbody>
<ChildComp/>
</table>
</div>
)
}
}
It sounds like you want to clone rows after the button is clicked.. Let me know if this is what you are looking for..
Hope this helps!
class ParentComponent extends React.Component {
render() {
return (
<div>
<table>
<tbody>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
<th>F</th>
<th>G</th>
<th> </th>
</tr>
</tbody>
<ChildComp
rows={[
[1, 2, 3, 4, 5, 6, 7],
[8, 9, 10, 11, 12, 13, 14],
[14, 15, 16, 17, 18, 19, 20]
]}
/>
</table>
</div>
);
}
}
class ChildComp extends React.Component {
state = {
tableRows: []
};
componentDidMount() {
this.setState({ tableRows: this.props.rows });
}
addNewRow = (rowToClone, index) => event => {
let newRows = [...this.state.tableRows];
newRows.splice(index, 0, rowToClone.map(i => `${i}` + `${i[0] || i}`));
this.setState({ tableRows: newRows });
};
render() {
return (
<tbody>
{this.state.tableRows.map((row, index) => {
return (
<tr>
{row.map(i => <td>{i}</td>)}
<td>
<button onClick={this.addNewRow(row, index + 1)}>
Clone Row
</button>
</td>
</tr>
);
})}
</tbody>
);
}
}
ReactDOM.render(<ParentComponent />, document.body);
table, th, tr, td {
border: 1px solid black;
}
table {
border-collapse: collapse;
}
td {
width: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
I think you are over-complicating the logic for your component-tree. This is how I interpreted your question.
You have a Parent component that renders a table with headers.
Each Child component is a table row.
You have a button that should add more rows (Child components).
The table cells belonging to each row should be editable (hence
inputs).
See working sandbox: https://codesandbox.io/s/inspiring-wave-bpv7f
It makes the most sense to have the Parent component manage the data-set. So all logic that involves updating or adding something from the data-set should belong to the Parent, not the Child components.
Consider an example like this;
Parent.js
class App extends React.Component {
state = {
headers: ["name", "age", "job", "salary"],
data: [
[
{ name: "Bobby Hill", editting: false },
{ age: 13, editting: false },
{ job: "student", editting: false },
{ salary: 0, editting: false }
]
]
};
createHeaders = () => {
const { headers } = this.state;
return headers.map(item => <th className="table-header">{item}</th>);
};
createBody = () => {
const { data } = this.state;
return data.map((row, index) => (
<Child data={row} rowIndex={index} toggleEdit={this.toggleEdit} />
));
};
addRow = () => {
const { data } = this.state;
const rowTemplate = [
{ name: "", editting: true },
{ age: "", editting: true },
{ job: "", editting: true },
{ salary: "", editting: true }
];
this.setState({
data: [...data, rowTemplate]
});
};
toggleEdit = (rowIndex, cellIndex) => {
const dataCopy = [...this.state.data];
const itemToUpdate = dataCopy[rowIndex][cellIndex];
itemToUpdate.editting = !itemToUpdate.editting;
this.setState({
data: dataCopy
});
};
render() {
return (
<div className="table-center" id="table1">
<table className="rwd-table" id="tblBlah">
<tbody>
<tr>{this.createHeaders()}</tr>
{this.createBody()}
</tbody>
</table>
<button onClick={this.addRow}>Add Row</button>
</div>
);
}
}
In the Parent component we have:
A data-set in our state which is an array of arrays. Each array
pertains to table-row.
When we iterate over the data-set, we pass in an array to each Child
component, which will render the row.
The addRow function will add a new array to our data-set,
containing objects corresponding to each table-header/property.
The toggleEdit function helps us swap between edit modes for each
cell.
Child.js
import React from "react";
const Child = ({ data, rowIndex, toggleEdit }) => {
return (
<tr>
{data.map((cell, cellIndex) => (
<td
className="table-cell"
onDoubleClick={() => toggleEdit(rowIndex, cellIndex)}
>
{cell.editting ? (
<input value={Object.values(cell)[0]} />
) : (
<span>{Object.values(cell)[0]}</span>
)}
</td>
))}
</tr>
);
};
export default Child;
Now in the Child component:
It consumes the data (array) that was passed to it was a prop and
uses it to render the row.
For each item (object) in the array, it creates a table-cell to
display the value.
Double-clicking the cell will toggle the edit property of the item belonging to the parent-state.
If editting is true, than an input is displayed, if not just a
normal table-cell.

React won`t render array map function

Hello I am new with new with React js. We have to create a project for counting points for teams, there are 4 teams in total. Every team has 5 children in it. Now I created an array to have 5 counts with id. The 5 counters are meant for the children. You should be able to add points for every child. So it is possible to update it by id with buttons. I`m using React in laravel. Here is the code:
export default class Gryffindor extends Component {
constructor(props) {
super(props);
this.state = {
counters: []
};
this.fetchCounter = this.fetchCounter.bind(this);
}
fetchCounter(e) {
const counters = [
{ id: 1, amount: 0 },
{ id: 2, amount: 0 },
{ id: 3, amount: 0 },
{ id: 4, amount: 0 },
{ id: 5, amount: 0 }
];
this.setState({ counters });
}
render() {
return <CounterBody counters={this.state.counters} />;
}
}
const CounterBody = ({ counters }) => (
<table>
<thead>
<tr>
<th>Test</th>
<th>Test</th>
<th>Test</th>
</tr>
</thead>
<tbody>
{counters.map(counter => (
<tr key={counter.id}>
<td></td>
<td>{counter.amount}</td>
<td></td>
</tr>
))}
</tbody>
</table>
);
if (document.getElementById("Gryffindor")) {
ReactDOM.render(<Gryffindor />, document.getElementById("Gryffindor"));
}
I have no idea why it is not showing up. Can someone help me?
You are never calling fetchCounter. You could call it inside componentDidMount.
class Gryffindor extends React.Component {
constructor(props) {
super(props);
this.state = {
counters: []
};
this.fetchCounter = this.fetchCounter.bind(this);
}
componentDidMount() {
this.fetchCounter();
}
fetchCounter() {
const counters = [
{ id: 1, amount: 0 },
{ id: 2, amount: 0 },
{ id: 3, amount: 0 },
{ id: 4, amount: 0 },
{ id: 5, amount: 0 }
];
this.setState({ counters });
}
render() {
return <CounterBody counters={this.state.counters} />;
}
}
const CounterBody = ({ counters }) => (
<table>
<thead>
<tr>
<th>Test</th>
<th>Test</th>
<th>Test</th>
</tr>
</thead>
<tbody>
{counters.map(counter => (
<tr key={counter.id}>
<td />
<td>{counter.amount}</td>
<td />
</tr>
))}
</tbody>
</table>
);
ReactDOM.render(<Gryffindor />, 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>

Raised Button onClick triggers different function

I have two components, RaisedButton and TableList. Tablelist return select rows and the same is updated in the state (currentSelectedRows). RaisedButton simply consoles the currentSelectedRows. Now the problem statement:
onClick of RaisedButton it consoles the state properly (using approveSelected) till the time updateSelectedRows does not update the state. Once the state is updated inside updateSelectedRows method, onClick of RaisedButton component first calls updateSelectedRows then approveSelected. Below is the code.
export default class MyList extends React.Component {
constructor(props) {
super(props);
this.state = {
pendingList:[],
currentSelectedRows:[]
}
}updateSelectedRows(selectedRows){
console.log("updateCalled");
this.setState({
currentSelectedRows:selectedRows
});
};
approveSelected() {
console.log("approve selected");
console.log(this.state.currentSelectedRows);
};
render() {
return (
<div className="container">
<div className="row_align_right">
<RaisedButton label="APPROVE" backgroundColor={MUIColors.lightGreen500} labelColor={MUIColors.white} onClick={this.approveSelected.bind(this)} />
</div>
<div className="content">
<div className="">
<TableList
selectedRows={this.state.currentSelectedRows}
updateSelectedRows={this.updateSelectedRows.bind(this)}
/>
</div>
</div>
</div>
)
}
}
Any advice would be of great help.
Thanks
You didn't provide the code for TableList so it's hard to know what could be the problem but it seems to work when you just pass a row id upwards to the parent:
const usersList = [
{ name: 'John', age: 33 },
{ name: 'Jane', age: 32 },
{ name: 'David', age: 28 },
{ name: 'Eve', age: 29 },
];
class Row extends React.Component {
onClick = e => {
const { onClick, rowId } = this.props;
onClick(rowId)
}
render() {
const { user } = this.props;
return (
<tr onClick={this.onClick}>
<td>{user.name}</td>
<td>{user.age}</td>
</tr>
);
}
}
class TableList extends React.Component {
onClick = rowId => {
this.props.updateSelectedRows(rowId);
}
render() {
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
{
usersList.map((user, i) => <Row key={i} rowId={i} user={user} onClick={this.onClick}/>)
}
</tbody>
</table>
);
}
}
class MyList extends React.Component {
constructor(props) {
super(props);
this.state = {
pendingList: [],
currentSelectedRows: []
}
} updateSelectedRows(selectedRows) {
console.log("updateCalled");
this.setState({
currentSelectedRows: selectedRows
});
};
approveSelected() {
console.log("approve selected");
console.log(this.state.currentSelectedRows);
};
render() {
return (
<div className="container">
<div className="row_align_right">
<button onClick={this.approveSelected.bind(this)}>Click</button>
</div>
<div className="content">
<div className="">
<TableList
selectedRows={this.state.currentSelectedRows}
updateSelectedRows={this.updateSelectedRows.bind(this)}
/>
</div>
</div>
</div>
)
}
}
ReactDOM.render(<MyList />, 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>

How to apply filter on table contents in react

import React, { Component } from 'react';
import {Doughnut} from "react-chartjs-2"
import {bindActionCreators} from "redux";
import {connect} from 'react-redux';
import {fetchBeacons} from '../actions/';
const DummyDoughnutData = {
labels: ['beacon 1 - zone a', 'beacon 2 - zone c', 'beacon 3 - zone a', 'beacon 4 - zone b', 'beacon 5 - zone b'],
datasets: [
{
borderColor: 'rgba(255,255,255,.55)',
data: [ 30, 9, 17, 22, 11],
backgroundColor: [
'#063e70',
'#107bb5',
'#1A1C1D',
'#666666',
'#2F4F4F'
]
}
],
};
// const beacons=[
// {zone:"zone a", status: "active", _id:1},
// {zone:"zone c", status: "active", _id:2},
// {zone:"zone a", status: "active", _id:3},
// {zone:"zone b", status: "active", _id:4},
// {zone:"zone b", status: "active", _id:5},
// {zone:"zone b", status: "active", _id:6},
// {zone:"zone c", status: "active", _id:7}
// ];
// class BeaconZoneRow extends Component {
// render() {
// return (
// <tr>
// <th colSpan="2">
// {this.props.zone}
// </th>
// </tr>
// )
// }
// }
class BeaconRow extends Component {
render() {
return (
<tr>
<td>{this.props.beacon.name}</td>
<td>{JSON.stringify(this.props.beacon.status)}</td>
<td> {this.props.beacon.zone.name} </td>
</tr>
)
}
}
class BeaconList extends Component {
// Sort = (prop) => { return (a,b) => a[prop].localeCompare(b[prop])};
render() {
const rows = [];
this.props.beacons.map( beacon => {
return rows.push(<BeaconRow beacon={beacon} key={beacon._id}/>)
});
return (
<div className="col-lg-6">
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Zone</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
)
}
}
class BeaconDoughnutAnalysis extends Component {
render() {
return (
<div className="col-lg-6">
<Doughnut data={DummyDoughnutData} />
<br/>
<center>visits</center>
</div>
)
}
}
class BeaconListComponent extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this)
}
handleSubmit(){
this.props.router.push('/new-beacon');
}
componentWillMount = () => {
this.props.fetchBeacons();
};
render() {
return (
<div>
<div className="row">
<div className="col-sm-5">
<button className="btn btn-sm btn-info" onClick={this.handleSubmit}> Add Beacon</button>
</div>
</div>
<br/>
{ this.props.beacons && this.props.beacons.length > 0 ?
<div className="row">
<BeaconList beacons={this.props.beacons}/>
<BeaconDoughnutAnalysis/>
</div> :
<center><h1>...Loading</h1></center>
}
</div>
)
}
}
function mapStateToProps(state) {
return {
beacons: state.beacons
}
}
function matchDispatchToProps(dispatch){
return bindActionCreators({fetchBeacons: fetchBeacons}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(BeaconListComponent);
i had fetched data from the server and i wanted to know how to filter that data in the table using react redux
the code is shown above using which table is being displayed and i wanted to filter its contents
Assuming you are providing the zone as a prop to the BeaconList component you just need to provide a check while mapping like below
class BeaconList extends Component {
// Sort = (prop) => { return (a,b) => a[prop].localeCompare(b[prop])};
render() {
const rows = [];
//Assuming you are filtering based on zone and you are giving the zone you want to filter as a prop zone
this.props.beacons.map( beacon => {
if(beacon.zone === this.props.zone) {
return rows.push(<BeaconRow beacon={beacon} key={beacon._id}/>)
}
});
return (
<div className="col-lg-6">
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Zone</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
)
}
}
I hope this helps

Resources