Unable to update react state from user input data - reactjs

import React, { Component, Fragment } from "react";
import "./App.css";
export default class App extends Component {
constructor(props){
super(props)
this.state = {
data: [
{
id: 1,
Firstname: "Jill",
Lastname: ["john", "hobss", "smith"],
Age: [1, 2, 3],
company: ["facebook", "google", "netflix"],
skills: ["python", "java", "scala"]
},
{
id: 2,
Firstname: "Jill",
Lastname: ["john", "hobss", "smith"],
Age: [1, 2, 3],
company: ["facebook", "google", "netflix"],
skills: ["python", "java", "scala"]
},
{
id: 3,
Firstname: "Jill",
Lastname: ["john", "hobss", "smith"],
Age: [1, 2, 3],
company: ["facebook", "google", "netflix"],
skills: ["python", "java", "scala"]
},
{
id:4,
Firstname: "Jill",
Lastname: ["john", "hobss", "smith"],
Age: [1, 2, 3],
company: ["facebook", "google", "netflix"],
skills: ["python", "java", "scala"]
}
]
}
}
handleChange = (id, company, event) => {
const data = this.state.data;
for(let d of data){
if(d.id === id){
for(let c of d.company){
if(c === company){
c = event.target.value
}
}
}
}
}
render() {
return (
<div>
<table>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
<th>company</th>
<th>skills</th>
</tr>
{
this.state.data.map(td => {
return (
<tr>
<td>{td.Firstname}</td>
<td>
<table>
<tr>
<td>{td.Lastname[0]}</td>
<td>{td.Lastname[1]}</td>
<td>{td.Lastname[2]}</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>{td.Age[0]}</td>
<td>{td.Age[1]}</td>
<td>{td.Age[2]}</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>
<input type="text" value={td.company[0]} onChange={(e) => this.handleChange(td.id, td.company[0], e)} />
</td>
<td>
<input type="text" value={td.company[1]} onChange={(e) => this.handleChange(td.id, td.company[1], e)}/>
</td>
<td>
<input type="text" value={td.company[2]} onChange={(e) => this.handleChange(td.id, td.company[2], e)}/>
</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>{td.skills[0]}</td>
<td>{td.skills[0]}</td>
<td>{td.skills[0]}</td>
</tr>
</table>
</td>
</tr>
)
})
}
</table>
</div>
)
}
}
Here i am trying to update my table using input data .
I am sending data using event to handleChange() function and changing data of state.
But It is not working please have a look.
I am not able to change input value also.
Please have a look
if any way to solve this issue.
Thanks
I am sending data using event to handleChange() function and changing data of state.
But It is not working please have a look.
I am not able to change input value also.
Please have a look
if any way to solve this issue.
Thanks

You are currently mutating state which is an anit-pattern in react. In order to update state you need to call this.setState(newState) which will then trigger your component to rerender with the new state values;

You should replace the value attribute of the input with defaultValue so it can be changed in the first place, then use setState in your handleChange method to update the data.

Related

Mappin over an array of objects to display it in React

I am learning React, and I been stuck here for a while now, the Middle.js component and table. I am trying to loop over array of objects from the data I am fetching. It is userPools array and display in a table poolProvidersname and then consequently rest of the data.
I am quite confused as to how do I do this?
Here is the the sandbox: https://codesandbox.io/s/naughty-ellis-xrir4?file=/src/components/Table.js
Thank you.
jumping from JS to markup on JSX can bit a bit confusing at first
When iterating an array of objects for display purposes, what you want to do is return a JSX fragment for each item on your array.
So if you have an array that looks like this:
var data = [{ id: 1, name: 'Lucia', age: 20 }, { id: 2, name: 'Karina', age: 21 }, { id: 3, name: 'Maria', age: 22 }];
to display it in your component you would go like this:
const Table = ({ data }) => {
if (!Array.isArray(data)) return null;
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
{
data.map(item => // notice how we jump straight back to JSX here
<tr key={item.id}>
<td>
{item.name}
</td>
<td>
{item.age}
</td>
</tr>)
}
</tbody>
</table>
);
};

How to run map inside map function in Reactjs

I want my axios part should run first inside useEffect so that my state can be update first and then further I can use that.
Here is error:
TypeError: Cannot read property map of undefined
When I console it shows states is not updated it holds SwitchCOM empty array
That means it directly goes for the return statement without running useEffect axios part.
This is what my SwitchCom state look like:
SwitchCOM: {
0: {id: "36", name: "XYZ", progress: "", details: [{id: "36", name: "XYZ", progress: ""}]},
1: {id: "83", name: "ABC", progress: "", details: [{id: "36", name: "XYZ", progress: ""}]},
2: {id: "77", name: "EFG", progress: "", details: [{id: "36", name: "XYZ", progress: "" }]}
}
const initialState = {
SwitchCOM: [],
isFetching: false,
hasError: false
}
{states.SwitchCOM.map(topis => (
<div className="item" key={topis.id}>
<p>{topis.name}</p>
<p>
<progress id="file" value="32" max="100">
{topis.progress}
</progress>
</p>
{topis.activities.map(activity => (
<table key={activity.id}>
<tbody>
<tr>
<td>Name</td>
<td>Progress</td>
<td>Status</td>
</tr>
<tr >
<td>{activity.name}</td>
<td>{activity.prog}</td>
</tr>
</tbody>
</table>
))}
</div>
))}
You are trying to map through an object which won't work. Instead you need to use Object.keys(...) to accomplish what you want here.
You should do something like this:
{Object.keys(states.SwitchCOM).map(key => (
<div className="item" key={states.SwitchCOM[key].id}>
<p>{states.SwitchCOM[key].name}</p>
<p>
<progress id="file" value="32" max="100">
{states.SwitchCOM[key].progress}
</progress>
</p>
{states.SwitchCOM[key].details.map(detail => (
<table key={detail.id}>
<tbody>
<tr>
<td>Name</td>
<td>Progress</td>
</tr>
<tr>
<td>{detail.name}</td>
<td>{detail.progress}</td>
</tr>
</tbody>
</table>
))}
</div>
))}

how to map subarray by key of parent array reactjs

how to map subarray in react based on key of parent array?
I have tried mapping by id key of main array to map elements of dish_count array
<TableCell align="left">
{this.state.persons.map((items,name) =>
<div key={this.state.persons.id}>
{(typeof(items.dish_count)=="object")? (<div>
{ items.dish_count.map((subdata) =>
<table>
<td >
{subdata.meal_type}
</td>
</table>
)
}
</div>): (null)}</div>)}
</TableCell>
<TableCell align="left"> {this.state.persons.map((items,name) =>
<div key={this.state.persons.id} >{(typeof(items.dish_count)=="object")? (<div>
{
items.dish_count.map((subdata) =>
<table>
<td >
{subdata.dish_count}
</td>
</table>
)
}
</div>): (null)}</div>)}</TableCell>
i want to map subarray dish_count by key id of parent array .I am able to map but the mapping is multiple and is not exclusive by parent array key.dish_count is the subarray of package array
persons array
"data": [
{
"id": 1,
"name": "Gold",
"dish_count": [
{
"dish_count": 4,
"meal_type": "Starters"
},
{
"dish_count": 4,
"meal_type": "Main Course"
},
{
"dish_count": 4,
"meal_type": "Dessert"
},
{
"dish_count": 4,
"meal_type": "Lunch"
}
]
},
{
"id": 2,
"name": "Basic",
"dish_count": [
{
"dish_count": 2,
"meal_type": "Starters"
},
{
"dish_count": 2,
"meal_type": "Main Course"
},
{
"dish_count": 2,
"meal_type": "Dessert"
},
{
"dish_count": 2,
"meal_type": "Lunch"
}
]
}
]
I want
Meal Type No of Dishes
Gold Starters 4
Main Course 4
Desert 4
Lunch 4
Basic Starters 2
Main Course 2
Desert 2
Lunch 2
You have a few problems in your code:
this.state({persons:''});: This will set the initial persons to be an empty string and will fail with map.
console.log('package',this.state.persons): setState is async and the console.log will not print the desired state but the previous state. Use the callback of setState as second parameter to access the new state:
this.setState({persons:res.data.data.data}, () => console.log('package',this.state.persons) );
this.state.persons.map((items, name) =>: The map function will provide different parameters: the first is the person and the second is the index of that person within the array.
div key = {this.state.persons.id}: since persons is an array, the key will be undefined. If you use the map function correctly, you can use person.id.
When you fixed these problems, the code should work as expected.
To only show the expected dishes per person and not to print the duplication you have to write it like this:
class Table extends React.Component {
render() {
return <table>
<thead>
<tr>
<td>ID</td>
<td>Name</td>
<td>Meal Type</td>
<td>Number of Dishes</td>
</tr>
</thead>
<tbody>
{this.state.persons.map(person =>
<tr>
<td>{person.id}</td>
<td>{person.name}</td>
<td>
<table>
<tbody>
{person.dish_count.map(dish => <tr>
<td>{dish.meal_type}</td>
</tr>
)}
</tbody>
</table>
</td>
<td>
<table>
<tbody>
{person.dish_count.map(dish => <tr >
<td>{dish.dish_count}</td>
</tr>
)}
</tbody>
</table>
</td>
</tr>
)
}
</tbody>
</table >
}
}
By not iterating over the person for each sub-table, you can remove the duplicated data.
codepen
Hope this helps.

Mapping an array in react, descending order

I want to use the following data
[
{
"id": "1",
"label": "Score",
"tabledata": [
{"label": "Day 1", "data": {"score": 73}},
{"label": "Day 2", "data": {"score": 64}},
{"label": "Day 3", "data": {"score": 72}}
]
}, {
"id": "2",
"label": "Success",
"tabledata": [
{"label": "Day 1", "data": {"score": 73 }},
{"label": "Day 2", "data": {"score": 64 }},
{"label": "Day 3", "data": {"score": 72}}
]
} ]
<table>
<tr>
<td>
</td>
<td>
Score
</td>
<td>
Success
</td>
</tr>
<tr>
<td>
Day 3
</td>
<td>
72
</td>
<td>
72
</td>
</tr>
<tr>
<td>
Day 2
</td>
<td>
64
</td>
<td>
64
</td>
</tr>
<tr>
<td>
Day 1
</td>
<td>
73
</td>
<td>
73
</td>
</tr>
</table>
The solution i came up is:
<table >
<tr>
<td> </td>
<td>
{this.props.GraphData[0].label}
</td>
<td>
{this.props.GraphData[1].label}
</td>
</tr>
<tr>
<td> </td>
<td>
{this.props.GraphData[0].tabledata.data.map(row => ([ <tr key={i}> <td> {row.score}</td> </tr> )])};
</td>
<td>
{this.props.GraphData[1].tabledata.data.map(row => ([ <tr key={i}> <td> {row.score}</td> </tr> )])};
</td>
</tr>
</table>
How can I turn with reverse.map the values to appear in descending order (the first row (day 3) and last row (day 1).
Finally is there a way to avoid using [0] or [1] from the data file but to use mapping for all the rows and columns of the table?
first of all, your data structure is adding complexity as hell, and i advice you to structure it well so you could easily consume it, I've made a refactoring for your code and also restructured your data with a generic way so even day4, ...dayn could be shown, that shows well how complex the consumption became if we think generically, so this is what I've got, so rename this file as Table.jsx and try to import it as so import Table from './Table';:
import React from 'react';
import { get, map, reduce, uniq, find, orderBy } from 'lodash';
const data = [
{
id: '1',
label: 'Score',
tabledata: [
{ label: 'Day 1', data: { score: 73 } },
{ label: 'Day 2', data: { score: 64 } },
{ label: 'Day 3', data: { score: 72 } },
{ label: 'Day 5', data: { score: 60 } }
]
},
{
id: '2',
label: 'Success',
tabledata: [
{ label: 'Day 1', data: { score: 73 } },
{ label: 'Day 2', data: { score: 64 } },
{ label: 'Day 3', data: { score: 73 } }
]
}
];
const columnsHeaders = ['day', ...map(data, 'label')];
const days = uniq(
reduce(
data,
(acc, item) => [...acc, ...map(get(item, 'tabledata'), 'label')],
[]
)
);
const restructuredData = reduce(
days,
(acc, day) => {
const dayData = reduce(
map(data, 'label'),
(dayDataAcc, colName) => {
return {
...dayDataAcc,
day,
[colName]: get(
find(get(find(data, { label: colName }), 'tabledata'), {
label: day
}),
['data', 'score']
)
};
},
{}
);
return [...acc, dayData];
},
[]
);
const sortedData = orderBy(restructuredData, 'day', 'desc');
const TableHeaders = () => (
<thead>
<tr>{map(columnsHeaders, (col, index) => <th key={index}>{col}</th>)}</tr>
</thead>
);
// checking our data
console.log('restructuredData', restructuredData);
console.log('sortedData', sortedData);
const TableRows = ({ data }) => (
<tbody>
{map(data, ({ day, Score: score, Success: success }) => (
<tr key={day}>
<td>{day || '-'}</td>
<td>{score || '-'}</td>
<td>{success || '-'}</td>
</tr>
))}
</tbody>
);
export default () => (
<table>
<TableHeaders />
<TableRows data={sortedData} />
</table>
);

react table row show column on button click

I have a table being built dynamically by mapping over an array. Each item in the array gets a row. One of the columns in each of these rows is a select. I only want that column's content to show when a button in the same row's next column is clicked.
My plan was to add some sort of a toggle bool property to each object in my array, but then when I try to toggle it in my button's onclick, my eslint is complaining because I'm trying to modify a property of the parameter I sent into the function called by the onclick.
What is the appropriate way to do this?
Here's the code for the table:
<table>
<tbody>
{myArray.map(row => (
<tr key={`test-${row.name}`}>
<td>
<div className="testClass">{row.id}</div>
</td>
<td>{row.name}</td>
<td>
<Select
options={this.getOptions(row.id)}
onSelect={this.onOptionSelect}
placeholder="Select something"
/>
</td>
<td><button onClick={() => { changeStuff(row); }}>{ row.myToggle ? 'Save' : 'Change something' }</button></td>
</tr>
))}
</tbody>
</table>
In click handler, you can update your array altogether to show/hide the select option.
Based on my understanding, I have tried creating below snippet. This is the way i could come up with, as per my understanding. I have maintained 'hidden' field in the array of objects. Instead of 'Select' I have used a simple button. You can change accordingly. Hope this helps.
const list = [
{
name: "Person 1",
phone: "123-4567",
id: 11,
hidden:true
},
{
name: "Person 2",
phone: "123-4567",
id: 12,
hidden:true
},
{
name: "Person 3",
phone: "123-4567",
id: 23,
hidden:true
},
{
name: "Person 4",
phone: "123-4567",
id: 34,
hidden:true
},
{
name: "Person 5",
phone: "123-4567",
id: 45,
hidden:true
}
];
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
list: list
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(item) {
let updatedList = this.state.list.map(obj => {
if(obj.id === item.id) {
return Object.assign({}, obj, {
hidden:!item.hidden
});
}
return obj;
});
this.setState({
list : updatedList
});
}
render() {
return (
<div>
<table>
<tbody>
{this.state.list.map(item =>
<tr key={item.itemId}>
<td>
{item.name}
</td>
<td>
{item.phone}
</td>
<td >
<button hidden={item.hidden}> Action </button>
</td>
<td>
<button
className="delete"
onClick={() => this.handleClick(item)}
>
Change
</button>
</td>
</tr>
)}
</tbody>
</table>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
table td {
font-size: 14px;
font-weight: normal;
padding: 10px;
border: 1px solid #eee;
}
<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="app"></div>

Resources