Being more concise React - reactjs

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

Related

Frontend page doesn't display unless i comment out my table making code

Here is my code. I used typescript and my database is in a .json file. My page displays fine when I don't try to display the table and disappears completely
import React, { useState } from "react";
import "./viewAvailableShifts.css";
import "bootstrap/dist/css/bootstrap.min.css";
import MockData from "./data.json";
export class ViewAvailableShifts extends React.Component {
render() {
const [data] = useState(MockData);
return (
<>
<div className="row">
<div className="leftcolumn">
<div className="center">
<h1>Available Shifts</h1>
<div>
<table>
<thead>
<th>First Name</th>
<th>Last Name</th>
</thead>
<tbody>
{data.map((d) => (
<tr key={d.id}>
<td>{d.first_name}</td>
<td>{d.last_name}</td>
<td>{d.email}</td>
<td>{d.gender}</td>
</tr>
))}
</tbody>
</table>
</div>
Have you tried mapping the table rows outside of the return? Also wondering why data was in square brackets? Maybe curley braces or none at all, depending on how you return it from state? so if it's already an array just data if you need to make it an array maybe spread [...data]?
export class ViewAvailableShifts extends React.Component {
render() {
const data = useState(MockData)
const rows = data.map((d) => (
<tr key={d.id}>
<td>{d.first_name}</td>
<td>{d.last_name}</td>
<td>{d.email}</td>
<td>{d.gender}</td>
</tr>
))
return (
<>
<div className="row">
<div className="leftcolumn">
<div className="center">
<h1>Available Shifts</h1>
<div>
<table>
<thead>
<th>First Name</th>
<th>Last Name</th>
</thead>
<tbody>{rows}</tbody>
</table>
</div>
</div>
</div>
</div>
</>
)
}
}
Hooks doesn't work inside class component
import React, { useState } from "react";
import "./viewAvailableShifts.css";
import "bootstrap/dist/css/bootstrap.min.css";
import MockData from "./data.json";
export const ViewAvailableShifts = () => {
const [data] = useState(MockData);
return (
<>
<div className="row">
<div className="leftcolumn">
<div className="center">
<h1>Available Shifts</h1>
<div>
<table>
<thead>
<th>First Name</th>
<th>Last Name</th>
</thead>
<tbody>
{data.map((d) => (
<tr key={d.id}>
<td>{d.first_name}</td>
<td>{d.last_name}</td>
<td>{d.email}</td>
<td>{d.gender}</td>
</tr>
))}
</tbody>
</table>
</div>
What are you trying to accomplish with useState? useState is a hook that listens for changes to data and then changes the UI accordingly. Use state returns two values though, it would be used like this...
const [data, setData]= useState(someDataOrEmptyValueButNeverActuallyEmpty)
onSomeEvent((eventOrDataOrWhatNot) => setData(eventOrDataOrWhatNot))
and then whatever in your UI that was depending on data will adjust to the new values.
So, are you ready?You can't us hooks in class components
export const ViewAvailableShifts = () => {
const [data] = useState(MockData);
‏}
Should be
export default class ViewAvailableShifts extends Component {
constructor() {
super();
this.state: {data: MockData}
}
render(){...}
}

Cannot update a component (`App`) while rendering a different component (`UserTable`)

I'm trying to learn React Hooks in functional components, and am following along with React Hooks tutorial but am getting the error: Cannot update a component (App) while rendering a different component (UserTable), and the error stack indicates this is related to the onClick={props.deleteUser(user.id)} property in the delete button in UserTable.js. I saw several posts indicating that one should try useEffect() to get around this issue, so I tried having deleteUser update a state variable, and then have useEffects change the users array. While the code compiled fine, the page simply hung and eventually timed out with an "out of memory" error (I assume caused by an endless cycle of trying to render and re-render?). Any ideas how to fix this situation?
App.js
import React, { useState } from 'react';
import UserTable from './tables/UserTable';
import AddUserForm from './forms/AddUserForm';
const App= () => {
const usersData = [
{id: 1, name: "Tania", username: "floppydiskette"},
{id: 2, name: "Craig", username: "siliconeidolon" },
{id: 3, name: "Ben", username: "benisphere"}
]
const [users, setUsers] = useState(usersData);
const addUser = (user) => {
user.id = users.length+1;
setUsers([...users,user])
}
const deleteUser = (id) => {
setUsers(users.filter((user)=>user.id !== id))
}
return (
<div className="container">
<h1> SIMPLE CRUD APP WITH HOOKS</h1>
<div className="flex-row">
<div className = "flex-large">
<h2> Add User </h2>
<AddUserForm addUser={addUser}/>
</div>
<div className = "flex-large">
<h2>View Users</h2>
<UserTable users={users} deleteUser={deleteUser}/>
</div>
</div>
</div>
);
}
export default App;
UserTable.js
import React from 'react';
const UserTable = (props) => {
return(
<table>
<thead>
<tr>
<th>Name</th>
<th>UserName</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{props.users.length > 0 ? (
props.users.map((user) => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.username}</td>
<td>
<button className="button muted-button">Edit</button>
>>> This triggers the `cannot update a component . . .` error:
<button className="button muted-button" onClick={props.deleteUser(user.id)}>Delete</button>
</td>
</tr>
))
) : (
<tr colspan={3}>No Users</tr>
)}
</tbody>
</table>
);
}
export default UserTable
You just have to change
onClick={props.deleteUser(user.id)}>Delete</button>
to
onClick={()=> props.deleteUser(user.id)}>Delete</button>
Otherwise your delete function will get automaticaly fired on render itself

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

How to avoid inline functions in React/Redux

I follow a React/Redux tutorial and from what I saw on a few articles on internet I realized that inline functions are bad for performance in React.
From what I understood functions are reference type and if you use an inline function, for every re-render, this function will take a different spot in memory.
In the tutorial example I have this deleteExperience() method, that the instructor used inline.
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Moment from 'react-moment';
import { Link, withRouter } from 'react-router-dom';
import { deleteExperience } from '../../actions/profileActions';
const Experience = ({ experience, deleteExperience }) => {
const experiences = experience.map(exp => (
<tr key={exp._id}>
<td>{exp.company}</td>
<td className="hide-sm">{exp.title}</td>
<td>
<Moment format="YYYY/MM/DD">{exp.from}</Moment> -
{exp.to === null ? (
' Now '
) : (
<Moment format="YYYY/MM/DD">{exp.to}</Moment>
)}
</td>
<td>
<button className="btn btn-danger" onClick={() => deleteExperience(exp._id)}>
Delete
</button>
</td>
</tr>
));
return (
<Fragment>
<h2 className="my-2">Experience Credentials</h2>
<table className="table">
<thead>
<tr>
<th>Company</th>
<th className="hide-sm">Title</th>
<th className="hide-sm">Years</th>
<th />
</tr>
</thead>
<tbody>{experiences}</tbody>
</table>
</Fragment>
);
};
Experience.propTypes = {
experience: PropTypes.array.isRequired,
deleteExperience: PropTypes.func
};
export default connect(
null,
{deleteExperience}
)(withRouter(Experience));
So the instructor said that he used inline function
onClick={() => deleteExperience(exp._id)}
and not just called directly the function
onClick={deleteExperience(exp._id)}
to not be execute immediately.
So, please someone tell me, if the theory about bad practice to use inline function is true, how to handle this situation? I tried many ways, without any success.
The performance issue isn't from using arrow functions, but rather from creating fresh ones on every render. In your case, you can use useCallback() to memoize them. (You'll need to extract a component to render each exp object to avoid breaking the rules of hooks.) Something like this should work:
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Moment from 'react-moment';
import { Link, withRouter } from 'react-router-dom';
import { deleteExperience } from '../../actions/profileActions';
const Exp = ({ exp, deleteExperience }) => {
const del = useCallback(() => deleteExperience(exp._id), [deleteExperience, exp._id]);
return (
<tr>
<td>{exp.company}</td>
<td className="hide-sm">{exp.title}</td>
<td>
<Moment format="YYYY/MM/DD">{exp.from}</Moment> -
{exp.to === null ? (
' Now '
) : (
<Moment format="YYYY/MM/DD">{exp.to}</Moment>
)}
</td>
<td>
<button className="btn btn-danger" onClick={del}>
Delete
</button>
</td>
</tr>
);
};
const Experience = ({ experience, deleteExperience }) => {
const experiences = experience.map(exp => (
<Exp key={exp._id} exp={exp} deleteExperience={deleteExperience} />
));
return (
<Fragment>
<h2 className="my-2">Experience Credentials</h2>
<table className="table">
<thead>
<tr>
<th>Company</th>
<th className="hide-sm">Title</th>
<th className="hide-sm">Years</th>
<th />
</tr>
</thead>
<tbody>{experiences}</tbody>
</table>
</Fragment>
);
};
Experience.propTypes = {
experience: PropTypes.array.isRequired,
deleteExperience: PropTypes.func
};
export default connect(
null,
{deleteExperience}
)(withRouter(Experience));

Iterate through a dictionary with React to construct a Table

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

Resources