Rendering array inside object to a table using react - reactjs

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>
)

Related

Being more concise React

This is my React hw, (it works, I have been trying to wrap my head around concepts in order to either do less tables for the JSX or anything really). Anything to make it to where I don't have to make a model of anything more than once tables or whatever be it :
import React from 'react';
import ReactDOM from 'react-dom';
const groceryList = (State1, State2, State3, State4,Pop1, Pop2, Pop3,Pop4,Cap1,Cap2, Cap3, Cap4) => {
return (
<table>
<th>State</th>
<th>Population</th>
<th>Capital</th>
<tr>
<td>{State1}</td>
<td>{Pop1}</td>
<td>{Cap1}</td>
</tr>
<tr>
<td>{State2}</td>
<td>{Pop2}</td>
<td>{Cap2}</td>
</tr>
<tr>
<td>{State3}</td>
<td>{Pop3}</td>
<td>{Cap3}</td>
</tr>
<tr>
<td>{State4}</td>
<td>{Pop4}</td>
<td>{Cap4}</td>
</tr>
</table>
);
};
ReactDOM.render(
groceryList('Idaho', 'Tennessee', 'Main', 'Wisconsin', '', '6.65 Million', '1.31 Million', '5.779 Million', 'Boise', 'Nashville', 'Agusta', 'Madison'),
document.getElementById('root')
);
You can define an array of objects and pass it as a prop. This works for you because all objects will have same structure and you are rendering them as <td> elements. So you can map over the array and display your items.
const GroceryList = ({ items }) => {
return (
<table>
<tr>
<th>State</th>
<th>Population</th>
<th>Capital</th>
</tr>
{items.map(({ state, pop, cap }) => (
<tr>
<td>{state}</td>
<td>{pop}</td>
<td>{cap}</td>
</tr>
))}
</table>
);
};
const items = [
{ state: "Idaho", pop: "6.65 Million", cap: "Boise" },
{ state: "Tennessee", pop: "1.31 Million", cap: "Nashville" },
];
ReactDOM.render(<GroceryList items={items} />, document.getElementById("root"));
th { text-align: left }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
map() - is a method which returns a transformed array from an array.
{state,pop,cap} - here we are destructuring the object, by using property names.
I think the best way to approach this to break it into reusable components. I would probably make a table row a component...
// TableRow.js
import React from "react";
function TableRow(props) {
return (
<tr>
<td>{props.state}</td>
<td>{props.population}</td>
<td>{props.capital}</td>
</tr>
);
}
export default TableRow;
A table component that uses the JavaScript map function to map rows to the table from an array...
// Table.js
import React from "react";
import TableRow from "./TableRow";
const states = [
{ state: "Massachusetts", population: 6000000, capital: "Boston" }
];
function Table(props) {
return (
<table>
<th>State</th>
<th>Population</th>
<th>Capital</th>
{states.map((state) => (
<TableRow
state={state.state}
population={state.population}
capital={state.capital}
/>
))}
</table>
);
}
export default Table;
And then an App component that displays the table...
// App.js
import "./styles.css";
import Table from "./Table";
export default function App() {
return (
<div className="App">
<Table />
</div>
);
}

React not displaying data in table row

I am a beginner to React and frontend development in general.
Here is a "simple" code to display a table.
function TableHeader() {
return (
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
);
}
function TableDataRow(row, index) {
return (
<tr key={index}>
<td>{row.name}</td>
<td>{row.job}</td>
</tr>
)
}
function TableBody(props) {
const characterData = props.characterData;
return (
<tbody>
{characterData.map((row, index) => <TableDataRow row={row} index={index}/>)}
</tbody>
);
}
class Table extends Component {
render() {
const { characterData } = this.props;
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
);
}
}
class App extends Component {
render() {
const characters = [
{
'name': 'Charlie',
'job': 'Janitor'
},
{
'name': 'Mac',
'job': 'Bouncer'
},
{
'name': 'Dee',
'job': 'Aspring actress'
},
{
'name': 'Dennis',
'job': 'Bartender'
}
];
return (
<div className="container">
<Table characterData={characters} />
</div>
);
}
}
The error is as follows:
Warning: Each child in a list should have a unique "key" prop.
Check the render method of TableBody. See
https://banned-fb.example.com/react-warning-keys for more information.
in TableDataRow (at Table.js:30)
in TableBody (at Table.js:44)
in table (at Table.js:42)
in Table (at App.js:28)
in div (at App.js:27)
in App (at src/index.js:6)
The data rows are empty in the table. I think there is an issue in the call to TableDataRow. What is that I am possibly doing wrong?
Screenshot:
Key thing is just a warning, but you should fix it too, the reason nothing is rendering because you have your component like this:
function TableDataRow(row, index) {...} // WRONG
Function Component get just one argument that is props, what you need to do is either:
function TableDataRow(props) {
const {row, index} = props; // get row and index out of props inside function
...
}
OR
function TableDataRow({ row, index }) {...} // destructure the props in parameter
Now About fixing the key warning:
Instead of providing key to the <tr> inside TableDataRow you need to provide key to TableDataRow, like this:
function TableDataRow({ row }) { // you have a little error here too, row should be inside curly braces or use props and get row from props inside the function
return (
<tr> // no need of key
<td>{row.name}</td>
<td>{row.job}</td>
</tr>
)
}
function TableBody(props) {
const characterData = props.characterData;
return (
<tbody>
{characterData.map((row, index) => <TableDataRow row={row} key={index}/>)} // key should be here
</tbody>
);
}
Also you should use index as key as last resort (see docs for why). If your data comes from api every item might have an id you can use that as key, or there is maybe something else unique for each character, if not, it's ok to use index.
import React from 'react';
function TableHeader() {
return (
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
);
}
function TableBody(props) {
const characterData = props.characterData;
return (<tbody>
{characterData.map((row, index) =>
<tr key={index}>
<td>{row.name}</td>
<td>{row.job}</td>
</tr>)}
</tbody>
);
}
class Table extends React.Component {
render() {
const { characterData } = this.props;
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
);
}
}
class Hello extends React.Component {
render() {
const characters = [
{
'name': 'Charlie',
'job': 'Janitor'
},
{
'name': 'Mac',
'job': 'Bouncer'
},
{
'name': 'Dee',
'job': 'Aspring actress'
},
{
'name': 'Dennis',
'job': 'Bartender'
}
];
return (
<div className="container">
<Table characterData={characters} />
</div>
);
}
}
export default Hello;
Find your working solution here..
Stackblitz Link

How to access values in Reactjs

I am trying to access the values stored in a list in my react component. When looped through, all data can be accessed but cannot be accessed by the syntax { variable.data_key }
code: https://pastebin.com/wS5SL22n
line 9: I initialized a list of data
line 36: I started looping through the list of data.
line 38: I created a table and tried to access items from the data list.
line 55: take the table as state
line 79: displaying the contents
import React, { Component } from "react";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
/* DATABASE */
const movies = [
{
id: 0,
src:
"https://image.tmdb.org/t/p/w185_and_h278_bestv2/7WsyChQLEftFiDOVTGkv3hFpyyt.jpg",
title: "movie one",
overview: "overview one"
}
];
let movieRows = [];
/* LOOPING THROUGH DATABASE */
movies.forEach(item => {
/* MAKING AN ELEMENT */
const moveDataTable = (
<table key={movies.id}>
<tbody>
<tr>
<td>
<img alt="poster" width="80" src={movies.src} />
</td>
<td>{movies.title}</td>
</tr>
</tbody>
</table>
);
/* PUSING DATA TO THE LIST */
movieRows.push(moveDataTable);
console.log(movieRows);
});
this.state = { rows: movieRows };
}
render() {
return (
<div className="App">
<p> {this.state.rows} </p>
</div>
);
}
}
export default App;
You have accepted an answer but still, I want to provide a different logic.
The main problem here you are trying to reach the wrong item. You are trying with movies but in your forEach loop it is item. Though, I don't recommend using forEach like that then set the state. At some point, there might be some glitches. Use map for such situations. Also, do not use your constructor like defining your functions.
const movies = [
{
id: 0,
src:
"https://image.tmdb.org/t/p/w185_and_h278_bestv2/7WsyChQLEftFiDOVTGkv3hFpyyt.jpg",
title: "movie one",
overview: "overview one"
},
{
id: 1,
title: "moview two",
overview: "something"
}
];
class App extends React.Component {
state = { movies: [] };
componentDidMount() {
this.setState( {movies} );
}
createTable = () => (
<table key={movies.id}>
<tbody>
{
movies.map( movie =>
<tr>
<td>
<img alt="poster" width="80" src={movie.src} />
</td>
<td>{movie.title}</td>
<td>{movie.overview}</td>
</tr>
)
}
</tbody>
</table>
);
render() {
return (
<div className="App">
{this.createTable()}
</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>
movies is an array, not an object.
movies.forEach(item => ...) means for each item in the movies array. The individual item in the array is item, not movies. You are trying to display movies.src and movies.title. There is no src or title property on the movies array. These properties are on the item in the array. You should be using item.src and item.title.
Instead of accessing movie.id i needed to access item.id as i named the variable as item in the foreach loop.

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

reactjs - How to render a component which render return a component?

for the following example I have a component GetCurrentVisitor which renders Visitors.
However it will only render the <h1> tag and the table is empty. I suspect I need to use ReactDOM to render Vistors component as well. But how to do it?
var VISITORS = [
{
first_name: 'Harry',
last_name: 'Potter'
},
{
first_name: 'Hermione',
last_name: 'Granger'
}
]
class GetCurrentVisitors extends React.Component {
constructor(props) {
super(props);
this.state = {
visitors: VISITORS
}
}
render () {
return (
<div>
<h1>Current visitors</h1>
<Visitors visitors={this.state.visitors} />
</div>
);
}
}
class Visitors extends React.Component {
constructor(props) {
super(props);
}
render () {
return (
<table>
{this.props.visitors.forEach(
function(visitor) {
<tr>
<td>
{console.log('from: ', visitor.first_name)}
{visitor.first_name}
</td>
</tr>
})}
</table>
);
}
}
ReactDOM.render(
<GetCurrentVisitors />, document.getElementById('getcurrentvisitors'))
In this case you should use .map instead of .forEach
{this.props.visitors.map(function(visitor, index) {
return <tr key={index}>
<td>{ visitor.first_name } </td>
</tr>
})}
Example
You can also are able to use .forEach but in another way fiddle
render () {
let itemList = [];
this.props.visitors.forEach(function(visitor,index) {
itemList.push(<tr key={index}><td>
{visitor.first_name}
</td></tr>
)
})
return (
<table>
{itemList}
</table>
);
}
As for me Array.prototype.map more easy to use with React. It just another example.
Thanks

Resources