Iterate through a dictionary with React to construct a Table - reactjs

I want to iterate a dictionary to construct a table using React, but I am stuck with this error:
PricingPlanTable.jsx:33 Uncaught TypeError: Cannot read property 'map'
of undefined
Here's my code:
BillingAccount.jsx
import React, { PropTypes, Component } from 'react';
import PricingPlanTable from './PricingPlanTable';
export default class BillingAccount extends React.Component {
render() {
var pricingPlans = {
'planNames': ['Starter', 'Bronze', 'Silver', 'Gold', 'Enterprise'],
'planPrices': ['free', '$10', '$25', '$49', 'Contact Us'],
'planOptions': [
{'option': 'A', 'values': ['1', '2', '3', '4', '5']},
{'option': 'B', 'values': ['1', '2', '3', '4', '5']},
{'option': 'C', 'values': ['1', '2', '3', '4', '5']}
]
};
return (
<div>
<PricingPlanTable table={pricingPlans}/>
</div>
);
}
}
PricingPlanTable.jsx
import React, { PropTypes, Component } from 'react';
export default class PricingPlanTable extends React.Component {
render() {
const table = this.props.table.map((table, i) => {
return (
<div key={i}>
<table>
<tbody>
<tr>
<th></th>
<th>Starter</th>
<th>Bronze</th>
<th>Silver</th>
<th>Gold</th>
<th>Enterprise</th>
</tr>
<tr>
<td></td>
<td>free</td>
<td>19€ /mo</td>
<td>79€ /mo</td>
<td>190€ /mo</td>
<td>custom</td>
</tr>
</tbody>
</table>
</div>
)})
return (
<div>
{table}
</div>
);
}
}
This is a mockup of what I am trying to achieve:
The PricingPlanTable.jsx has the table hardcoded but I am trying to use the 'this.props' functionality of React to iterate through it. I would like to use a skeleton of the template and populate it with the pricingPlans var from the BillingAccount.jsx file.

pricingPlans that you are passing as a prop is an object and cannot be iterated over. You would need to access each object within pricing plans since they actually contain an array and iterate over them.
Please look at the following documenatation on how to use Array.map() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
So with your current data structure you could do something like the following :
createHeaders() {
this.props.table.planNames.map((plan) => {
return <th>{plan}</th>
});
}
createContent() {
this.props.table.planPrices.map((price) => {
return <tr>{price}</tr>
});
}
render() {
const table = this.props.table;
return(
<table>
<tr>
{this.createHeaders}
</tr>
<tr>
{this.createContent}
</tr>
</table>
)
}

At first you should use an array with map.Use map in planOptions instead. Secondly in map you are returning the table again and again rather you must return only rows. This is what it should be like.
import React, { PropTypes, Component } from 'react';
export default class PricingPlanTable extends React.Component {
render() {
const table = this.props.table.planOptions.map((obj, i) => {
return (
<tr key={i}>
<td>{obj.option}</td>
{obj.value.map(value => {
return (
<td>{value}</td>
);
})}
</tr>
)})
return (
<div>
<table>
<tbody>
<tr>
<th></th>
<th>Starter</th>
<th>Bronze</th>
<th>Silver</th>
<th>Gold</th>
<th>Enterprise</th>
</tr>
<tr>
<td></td>
<td>free</td>
<td>19€ /mo</td>
<td>79€ /mo</td>
<td>190€ /mo</td>
<td>custom</td>
</tr>
{tbody}
</tbody>
</table>
</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>
);
}

How to display the list response which inside the object - react js

How to display the data in the below from the below json.
{
"a":
{
"b":[
{"id":"ef718cce-1269-4fbd-827c-832f7824c025","name":"Veera6"},
{"id":"0cda5ae9-e287-4666-804a-03f25e642d1f","name":"Veera9"},
{"id":"31f8f042-dbc0-4dbf-ada8-b94c7e2d2a39","name":"Veera8"},
{"id":"6292054c-8bfc-4d2d-b2f8-92e2bac5a578","name":"Veera7"},
{"id":"c6756e5c-8fa5-40a9-ab92-5242bda97de3","name":"Veera10"}]
}
}
code snipped below.
render() {
return (
<table>
<thead>
<tr>
{
this.headers.map(function(h) {
return (
<th key = {h.key}>{h.label}</th>
)
})
}
</tr>
</thead>
<tbody>
{
this.state.tags.b.map(function(item, key) {
return (
<tr key = {key}>
<td>{item.id}</td>
<td>{item.name}</td>
</tr>
)
})
}
</tbody>
</table>
)
}
}
How to display the data in table. Here i need to get the array/list b. Tried different approaches to get the data from the object array but no luck.
Don't know what you were going to do in first < tr >.
Maybe this will point you to the right direction.
import React from "react";
import "./styles.css";
const headers = {
a: {
b: [
{ id: "ef718cce-1269-4fbd-827c-832f7824c025", name: "Veera6" },
{ id: "0cda5ae9-e287-4666-804a-03f25e642d1f", name: "Veera9" },
{ id: "31f8f042-dbc0-4dbf-ada8-b94c7e2d2a39", name: "Veera8" },
{ id: "6292054c-8bfc-4d2d-b2f8-92e2bac5a578", name: "Veera7" },
{ id: "c6756e5c-8fa5-40a9-ab92-5242bda97de3", name: "Veera10" }
]
}
};
let keys = Object.getOwnPropertyNames(headers.a.b[0]);
let head = keys.map(propertyName => <th key={propertyName}>{propertyName}</th>);
export default function App() {
return (
<table>
<thead>
<tr>{head}</tr>
</thead>
<tbody>
{headers.a.b.map(function(item, key) {
return (
<tr key={key}>
<td>{item.id}</td>
<td>{item.name}</td>
</tr>
);
})}
</tbody>
</table>
);
}
So you should access b with headers.a.b and then map().
Your b array is nested inside the headers a object, which is nested in headers object.
Result will be:
id name
ef718cce-1269-4fbd-827c-832f7824c025 Veera6
0cda5ae9-e287-4666-804a-03f25e642d1f Veera9
31f8f042-dbc0-4dbf-ada8-b94c7e2d2a39 Veera8
6292054c-8bfc-4d2d-b2f8-92e2bac5a578 Veera7
c6756e5c-8fa5-40a9-ab92-5242bda97de3 Veera10
Also be sure to check sandbox demo out.
Try this once :
{
this.state.tags.a.b.map(function(item, key) {
return (
<tr key = {key}>
<td>{item.id}</td>
<td>{item.name}</td>
</tr>
)
})
}
Hope it helps. feel free for doubts
Try this
this.state.tags.a.b.map
import React from 'react';
import './App.css';
import { useQuery } from '#apollo/react-hooks';
import gql from "graphql-tag";
const GET_GRPHQL_API = gql`
{
getTags
{
id
tagName
tagDesc
tagVersion
tagVersion
}
}
`
function App() {
const { data, loading, error } = useQuery(GET_GRPHQL_API);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error</p>;
return (
<React.Fragment>
<table>
<thead>
</thead>
<tbody>
{data &&
data.getTags &&
data.getTags.map(function(item, key) {
return (
<tr key={key}>
<td>{item.id}</td>
<td>{item.tagName}</td>
<td>{item.tagDesc}</td>
<td>{item.tagVersion}</td>
</tr>
);
})}
</tbody>
</table>
</React.Fragment>
);
}
export default App;

Beginner Question about ReactJS error TypeError: Cannot read property 'map' of undefined

I have tried out several other answers with this same issue and i still cant figure out why i keep getting this error "TypeError: Cannot read property 'map' of undefined".
Any help would be appreciated.
The code is:
import React from 'react';
import * as $ from 'jquery';
class TeamRaceDetails extends React.Component {
constructor(){
super();
this.state = {
teamResults: [],
loading: true
}
this.getTeamResults = this.getTeamResults.bind(this);
}
componentDidMount(){
this.getTeamResults();
}
getTeamResults(){
const id = this.props.teamid;
var url = 'http://ergast.com/api/f1/2013/constructors/' + id + '/results.json';
//console.log(url);
$.get(url, (teamResultData) => {
//console.log(resultData);
this.setState({ teamResults: teamResultData, loading:false });
});
}
render() {
if (this.state.loading === true){
return <h2>Loading...</h2>;
}
var teamResults = this.state.teamResults.MRData.RaceTable.Races.Results;
return (
<div>
<table>
<thead>
<tr>
<th>Round</th>
<th>Grand prix</th>
<th>{this.state.teamResults.position}</th>
<th>{this.state.teamResults.grid}</th>
<th>Points</th>
</tr>
</thead>
<tbody>
{teamResults.map((race, i) => <TeamResults teamRacesData = {race} key={i}/>)}
</tbody>
</table>
</div>
);
}
}
class TeamResults extends React.Component {
render(){
return(
<tr>
<td>{this.props.teamRacesData.round}</td>
<td>{this.props.teamRacesData.Circuit.circuitName}</td>
<td>{this.props.teamRacesData.Results[0].Constructor.name}</td>
<td>{this.props.teamRacesData.Results[0].grid}</td>
<td>{this.props.teamRacesData.Results[0].position}</td>
</tr>
);
}
}
export default TeamRaceDetails;
Because you call this.getTeamResults() in componentDidMount and this API is async
. So, in the first time of render this.state.teamResults.MRData.RaceTable.Races.Results is undefined. In the second of render, you can got this data.
Try this code:
<tbody>
{teamResults && teamResults.map((race, i) => // make sure teamResults defined
<TeamResults teamRacesData = {race} key={i}/>
)}
</tbody>
When you use map operator to render a list in react, should be check same as above
Or you can defined default parameter like this:
var teamResults = this.state.teamResults.MRData.RaceTable.Races.Results || [];
// teamResults always is an array, will not have an error
Most likely teamResults is not an array. You can mitigate by assigning a default value:
var teamResults = this.state.teamResults.MRData.RaceTable.Races.Results || [];
return (
<div>
<table>
<thead>
<tr>
<th>Round</th>
<th>Grand prix</th>
<th>{this.state.teamResults.position}</th>
<th>{this.state.teamResults.grid}</th>
<th>Points</th>
</tr>
</thead>
<tbody>
{teamResults.map((race, i) => <TeamResults teamRacesData = {race} key={i}/>)}
</tbody>
</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

Creating a component in react and typescript

I am trying to convert this table below from react to typescript. I want to make it universal table component where I can use for every data. This is a sample a table I created in react and its working well. In typescript, the class experts an interface which I have been finding it difficult to apply here.The table must be able to accept data from a webservice and display at any point in time. What am I supposed to add.
class Table extends Component {
render() {
const { characterData, removeCharacter } = this.props;
return (
<table className="table-bordered table-striped">
<TableHeader />
<TableBody characterData={characterData}
removeCharacter={removeCharacter}
/>
</table>
);
}
}
const TableHeader = () => {
return (
<thead>
<tr>
<th width="300">Name</th>
<th width="300">Job</th>
<th width="300">Date</th>
</tr>
</thead>
);
}
const TableBody = props => {
const rows = props.characterData.map((row, index) => {
return (
<tr key={index}>
<td >{row.name}</td>
<td >{row.job}</td>
<td >{row.date}</td>
<td><button onClick={() => props.removeCharacter(index)}>Delete</button></td>
</tr>
);
});
return <tbody>{rows}</tbody>;
}
export default Table;
You can type check your props by adding chevrons next to the Component prototype. The first argument is type checking your props and the second argument will type check your internal state.
interface TableProps {
characterData: //...however the data should be structured
removeCharacter: () => void;
}
interface TableState {
//... this is empty because you haven't defined any internal component state
}
class Table extends Component<TableProps, TableState> {
render() {
const { characterData, removeCharacter } = this.props;
return (
<table className="table-bordered table-striped">
<TableHeader />
<TableBody characterData={characterData}
removeCharacter={removeCharacter}
/>
</table>
);
}
}

Resources