class Personne extends React.Component {
// constructor(props){
// super(props);
// }
birthdayHandler = () => {
let Age = this.props.age;
let ageToNumber = parseInt(Age);
}
render(){
return(
<Fragment>
<div className={classes.maintitle}>
<h1 style={Name}> {this.props.name}</h1>
<div> Job : {this.props.job}</div>
<AgePersonne age={this.props.age}/>
<div> Sexe : <strong style={sex}>{this.props.sexe ? "Homme" : "Femme"}</strong></div>
<button onClick={(event) => this.birthdayHandler(event)} style={Button}>Birthday</button>
</div>
</Fragment>
)
}
}
I would like to increment the age of the person by clicking on the button.
the AgePersonne component looks just like this :
const agePersonne = (props) => {
const now = new Date();
const year = now.getFullYear();
return(
<div>Age : {props.age} - année de naissance :{year - props.age -1}</div>
)
};`
I did it already in a parent component with a button, but it increments all of my person's age.
The APP component looks like this :
class app extends Component {
state = {
personne: [
{name: "Andy GARCIA", age: "28", job:"Web Dev", sexe: true},
{name: "Sylvie MOISAN", age: "60", job:"nurse", sexe: false},
{name: "Benjamin BARIOHAY", age: "27", job:"Web Dev", sexe: true},
{name: "Galina RAZLIVANOVA", age: "29", job:"Web Security consultant", sexe: false},
{name: "Maxime GIRARDEAU", age: "28", job:"Sailer", sexe: true},
]
}
render() {
return (
<Fragment>
<Horloge />
<Personne {...this.state.personne[0]}/>
<Personne {...this.state.personne[1]}/>
<Personne {...this.state.personne[2]}/>
<Personne {...this.state.personne[3]}/>
<Personne {...this.state.personne[4]}/>
</Fragment>
)
}
}
could you help me please ? I'm really lost, thank you
You need to create a function in your App that properly edit the state, something like :
const editAge = (index, newAge) => {
const newState = Object.assign({}, this.State);
newState[index] = {...newState[index], age: newAge};
this.SetState(newState);
}
And pass it to your Personne component, as well as its index :
<Personne editAge={editAge} index={index} (... your other props) />
You will be able to call the function as follow :
this.props.editAge('29', 0);
This will set 29 as the age of the first element of your App state.
The editAge function could also jsut accept a personne object, and the index. You would have to pass the entire object as props, it's as you wish.
Related
I'm learning a react course online. When I try to display the list of items from an array using map to display in a child component , I keep getting "cannot read property map of undefined.
Error is thrown while fetching data from users
import React, { Component } from "react";
import ReactDOM from "react-dom";
let userList = [
{ name: "John", age: 24, place: "India" },
{ name: "Henry", age: 24, place: "India" },
{ name: "Ulrich", age: 24, place: "India" }
];
const AppChild = ({ name, age, place, Graduated }) => {
return (
<section>
<p>name: {name}</p>
<p>age: {age}</p>
<p>place: {place}</p>
{/* access the value via props */}
<p>Graduated: {Graduated ? "yes!" : "no!"}</p>
</section>
);
};
export default class App extends Component {
state = {
userExists: true,
isGraduated: true,
loading: true,
};
toggleStatus = () => {
this.setState(prevState => ({
userExists: !prevState.userExists // value : false
}));
};
render() {
const { users } = this.props;
return (
<div>
<h2>Profile</h2>
<h4>
Profile Status is {this.state.userExists ? "Updated" : "Outdated"}
<br />
<button onClick={this.toggleStatus}>Check Status</button>
</h4>
{users.map(user => (
<AppChild
name={user.name}
age={user.age}
place={user.place}
Graduated={this.state.isGraduated} // passing state to child component
/>
))}
</div>
);
}
}
ReactDOM.render(<App users={userList} />, document.getElementById("root"));
To figure out the problem, we follow the bouncing ball. From the error message, I guess that the problem occurs on the line
{users.map(user => (
(You can confirm this from the stack trace given with the error message.)
The error tells you that users is undefined. So we look at the declaration for users:
const { users } = this.props;
Ok, so it is really this.props.users. So we look where this is passed in:
ReactDOM.render(<App users={userList} />, document.getElementById("root"));
Here you are passing the value of userList to a prop named users. However, in the code you show here, there is no variable named userList. This is as far as we can go with the information you have given. You need to find where this variable is declared and initialized to continue solving the problem.
Below is the correct code. In the previous code I was trying to render <App/> in both index.js and App.js. Thanks everyone for helping me out
=>index.js
import React from "react"
import ReactDOM from "react-dom"
import App from "./App"
let userList = [
{ name: "John", age: 24, place: "India" },
{ name: "Henry", age: 24, place: "India" },
{ name: "Ulrich", age: 24, place: "India" }
];
ReactDOM.render(<App users={userList} />, document.getElementById("root"));
=> App.js
import React, { Component } from "react";
// child component
const AppChild = ({ name, age, place, Graduated }) => {
return (
<section>
<p>name: {name}</p>
<p>age: {age}</p>
<p>place: {place}</p>
{/* access the value via props */}
<p>Graduated: {Graduated ? "yes!" : "no!"}</p>
</section>
);
};
// parent component
export default class App extends Component {
state = {
userExists: true,
isGraduated: true,
loading: true,
};
toggleStatus = () => {
this.setState(prevState => ({
userExists: !prevState.userExists // value : false
}));
};
render() {
const { users } = this.props;
return (
<div>
<h2>Profile</h2>
<h4>
Profile Status is {this.state.userExists ? "Updated" : "Outdated"}
<br />
<button onClick={this.toggleStatus}>Check Status</button>
</h4>
{users.map((user) => {
return(
<AppChild
name={user.name}
age={user.age}
place={user.place}
Graduated={this.state.isGraduated} // passing state to child component
/>
)})}
</div>
);
}
}
If you try to log users after following line of code
const { users } = this.props;
you'll see users is undefined.
Error message "cannot read property map of undefined" says the same thing, you can not apply map helper on an undefined variable. The map works with arrays
I'm not extending component class, trying to use usestate to manage state. Now I want to add a person component on certain conditions to personList variable inside the method togglePersonsHanler.
I'm expecting a list of HTML tags to be added like
<person name="person1" age=31>
<person name="person2" age=26>
<person name="person3" age=35>
but on console log, I'm getting personList as below
{$$typeof: Symbol(react.element), type: "div", key: null, ref: null, props: {…}, …}$$typeof: Symbol(react.element)type: "div"key: nullref: nullprops: {children: Array(3)}_owner: null_store: {validated: false}_self: null_source: {fileName: "D:\data\react\my-app\src\App.js", lineNumber: 72, columnNumber: 7}
and person tag is not getting added to DOM, any advice, please
import React, { useState } from 'react';
import './App.css';
import Person from './Person/Person';
const App = props => {
const [personState, setPersonState] = useState({
persons: [
{name: "person1", age:31},
{name: "person2", age:26},
{name: "person3", age:25}
],
other: "some Other Value"
} );
const [otherState,setOtherState]=useState({otherState :'some other value'});
const [showPersonsState,setShowPersonsState]=useState({showPersons :false});
let personList=null;
const togglePersonsHanler =() =>{
personList=null;
setShowPersonsState(
{showPersons : !showPersonsState.showPersons}
)
console.log(showPersonsState.showPersons);
if(showPersonsState.showPersons){
personList=(
<div>{personState.persons.map (person =>{
return <person name={person.name} age={person.age}/>
}
)}</div>
);
}
console.log(personList);
}
return (
<div className="App">
<h1> HI, I'm the react app</h1>
<button
//onClick={switchNameHandler.bind(this,'Gopu Ravi')}
onClick={togglePersonsHanler}
style={style}> Toggle Person </button>
{ personList }
</div>
);
}
export default App;
You're mapping the object literals by using them as an html tag. You likely meant to use the imported Person component.
<div>
{personState.persons.map (person => (
<Person name={person.name} age={person.age}/>
)}
</div>
And to fix a react-key warning since all mapped elements need unique keys, add a key prop with a value that is unique to the data in the array, like name:
<div>
{personState.persons.map (person => (
<Person key={name} name={person.name} age={person.age}/>
)}
</div>
To correctly toggle the display of the "personList":
Conditionally render the mapped persons array if showPersonsState is true
Simplify showPersonsState state to simply be the boolean value
Use functional state update to correctly toggle showPersonsState from previous state
Updated component code
const App = props => {
const [personState, setPersonState] = useState({
persons: [
{ name: "person1", age: 31 },
{ name: "person2", age: 26 },
{ name: "person3", age: 25 }
],
other: "some Other Value"
});
const [otherState, setOtherState] = useState({
otherState: "some other value"
});
const [showPersonsState, setShowPersonsState] = useState(false);
const togglePersonsHandler = () => setShowPersonsState(show => !show);
return (
<div className="App">
<h1> HI, I'm the react app</h1>
<button onClick={togglePersonsHandler}>Toggle Person</button>
{showPersonsState &&
personState.persons.map(({ age, name }) => (
<Person key={`${name}`} name={name} age={age} />
))}
</div>
);
};
In below code i have not declared showPerson property in person object. But am getting result. Button has hide and show content when you click on button. Its working fine for me. But still i have doubt how come without declaring the property in object. Please explain it in simplest way.
import React, { Component } from "react";
import "./App.css";
import Person from "./Person/Person";
class App extends Component {
state = {
person: [
{ name: "Andrew", age: 32 },
{ name: "Stephen", age: 42 },
{ name: "Samuel", age: 62 }
]
};
changeTxt = () => {
const doesShow = this.state.showPerson;
this.setState({ showPerson: !doesShow });
};
render() {
let person = null;
if (this.state.showPerson) {
person = (
<div>
<Person
name={this.state.person[0].name}
age={this.state.person[0].age}
/>
<Person
name={this.state.person[1].name}
age={this.state.person[1].age}
changed={this.changeMethod}
/>
<Person
name={this.state.person[2].name}
age={this.state.person[2].age}
/>
</div>
);
}
return (
<div>
<button onClick={this.changeTxt}>Click here</button>
{person}
</div>
);
}
}
export default App;
If you console.log(showPerson) without setting it. You will see that, its undefined. But after setting it you will see that it has the value. You don't have to initialize them.
Now the reason this code still works is that in javascript there are falsy and truthy values. These values react as true or false values in if statements.
undefined is a falsy value so it pretends like false in if statements. And when you change the value to this: !undefined. Since !falsy === true showPerson becomes true
Your question not clear but from my understanding, your code works and you want to make your code much simple
If so separate you if-else to different function and render it
import React, { Component } from "react";
import "./App.css";
import Person from "./Person/Person";
class App extends Component {
state = {
person: [
{ name: "Andrew", age: 32 },
{ name: "Stephen", age: 42 },
{ name: "Samuel", age: 62 }
]
};
changeTxt = () => {
const doesShow = this.state.showPerson;
this.setState({ showPerson: !doesShow });
};
renderPerson = () => {
if (this.state.showPerson) {
return (
<div>
<Person
name={this.state.person[0].name}
age={this.state.person[0].age}
/>
<Person
name={this.state.person[1].name}
age={this.state.person[1].age}
changed={this.changeMethod}
/>
<Person
name={this.state.person[2].name}
age={this.state.person[2].age}
/>
</div>
)
}else{
return null // your fallback
}
}
render() {
return (
<div>
<button onClick={this.changeTxt}>Click here</button>
{this.renderPerson()}
</div>
);
}
}
export default App;
could you please tell me how to render a list in react js.
I do like this
https://plnkr.co/edit/X9Ov5roJtTSk9YhqYUdp?p=preview
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
hello
</div>
);
}
}
You can do it in two ways:
First:
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>);
return (
<div>
{listItems }
</div>
);
}
Second: Directly write the map function in the return
render() {
const data =[{"name":"test1"},{"name":"test2"}];
return (
<div>
{data.map(function(d, idx){
return (<li key={idx}>{d.name}</li>)
})}
</div>
);
}
https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions
You can pass any JavaScript expression as children, by enclosing it within {}. For example, these expressions are equivalent:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
This is often useful for rendering a list of JSX expressions of arbitrary length. For example, this renders an HTML list:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);
}
class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [{name: 'bob'}, {name: 'chris'}],
};
}
render() {
return (
<ul>
{this.state.data.map(d => <li key={d.name}>{d.name}</li>)}
</ul>
);
}
}
ReactDOM.render(
<First />,
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>
Shubham's answer explains very well. This answer is addition to it as per to avoid some pitfalls and refactoring to a more readable syntax
Pitfall : There is common misconception in rendering array of objects especially if there is an update or delete action performed on data. Use case would be like deleting an item from table row. Sometimes when row which is expected to be deleted, does not get deleted and instead other row gets deleted.
To avoid this, use key prop in root element which is looped over in JSX tree of .map(). Also adding React's Fragment will avoid adding another element in between of ul and li when rendered via calling method.
state = {
userData: [
{ id: '1', name: 'Joe', user_type: 'Developer' },
{ id: '2', name: 'Hill', user_type: 'Designer' }
]
};
deleteUser = id => {
// delete operation to remove item
};
renderItems = () => {
const data = this.state.userData;
const mapRows = data.map((item, index) => (
<Fragment key={item.id}>
<li>
{/* Passing unique value to 'key' prop, eases process for virtual DOM to remove specific element and update HTML tree */}
<span>Name : {item.name}</span>
<span>User Type: {item.user_type}</span>
<button onClick={() => this.deleteUser(item.id)}>
Delete User
</button>
</li>
</Fragment>
));
return mapRows;
};
render() {
return <ul>{this.renderItems()}</ul>;
}
Important : Decision to use which value should we pass to key prop also matters as common way is to use index parameter provided by .map().
TLDR; But there's a drawback to it and avoid it as much as possible and use any unique id from data which is being iterated such as item.id. There's a good article on this - https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
Try this below code in app.js file, easy to understand
function List({}) {
var nameList = [
{ id: "01", firstname: "Rahul", lastname: "Gulati" },
{ id: "02", firstname: "Ronak", lastname: "Gupta" },
{ id: "03", firstname: "Vaishali", lastname: "Kohli" },
{ id: "04", firstname: "Peter", lastname: "Sharma" }
];
const itemList = nameList.map((item) => (
<li>
{item.firstname} {item.lastname}
</li>
));
return (
<div>
<ol style={{ listStyleType: "none" }}>{itemList}</ol>
</div>
);
}
export default function App() {
return (
<div className="App">
<List />
</div>
);
}
import React from 'react';
class RentalHome extends React.Component{
constructor(){
super();
this.state = {
rentals:[{
_id: 1,
title: "Nice Shahghouse Biryani",
city: "Hyderabad",
category: "condo",
image: "http://via.placeholder.com/350x250",
numOfRooms: 4,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 43
},
{
_id: 2,
title: "Modern apartment in center",
city: "Bangalore",
category: "apartment",
image: "http://via.placeholder.com/350x250",
numOfRooms: 1,
shared: false,
description: "Very nice apartment in center of the city.",
dailyPrice: 11
},
{
_id: 3,
title: "Old house in nature",
city: "Patna",
category: "house",
image: "http://via.placeholder.com/350x250",
numOfRooms: 5,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 23
}]
}
}
render(){
const {rentals} = this.state;
return(
<div className="card-list">
<div className="container">
<h1 className="page-title">Your Home All Around the World</h1>
<div className="row">
{
rentals.map((rental)=>{
return(
<div key={rental._id} className="col-md-3">
<div className="card bwm-card">
<img
className="card-img-top"
src={rental.image}
alt={rental.title} />
<div className="card-body">
<h6 className="card-subtitle mb-0 text-muted">
{rental.shared} {rental.category} {rental.city}
</h6>
<h5 className="card-title big-font">
{rental.title}
</h5>
<p className="card-text">
${rental.dailyPrice} per Night · Free Cancelation
</p>
</div>
</div>
</div>
)
})
}
</div>
</div>
</div>
)
}
}
export default RentalHome;
Try this:
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
{listItems}
</div>
);
}
}
Currently, I render Material-UI's <Table>'s <TableRow> (http://www.material-ui.com/#/components/table) with an array of <TableRow>s and by using .map(). Each <TableRow> has a <TableRowColumn> that represents a first name, like so <TableRowColumn>Josh</TableRowColumn>.
But, if a user presses a button, I would like to sort the <TableRow> array alphabetically by the <TableRowColumn>'s first name. So say for example out of 10 <TableRow>s, if the array[0] had a first name Conny and array[1] had Adrian, would like the array[1] to become array[0].
What would the right approach to this? Any guidance or insight would be greatly appreciated it.
EDIT
Each row would be rendered like so with the array rows, that has objects with properties firstName and favColor:
{
rows.map((row) => {
return(
<UserRow
firstName={row.firstName}
favColor={row.favColor}
/>
)
})
}
And each row is defined like so:
const UserRow = (props) => {
const {firstName, favColor} = props
return (
<TableRow>
<TableRowColumn>{firstName}</TableRowColumn>
<TableRowColumn>{favColor}</TableRowColumn>
</TableRow>
)
}
I would sort the array before applying the map operation that will create the TableRows.
The react way of thinking is declarative. This means that on a visual level, you should provide the elements as they should be displayed. Hence they get sorted before they are passed to the view component.
For example (I couldn't use material-ui elements since the example didn't run in the stackoverflow setup. Just replace all elements of TableComponent with their material-ui alter ego.):
const data = [
{firstname: "John", lastname: "Rover", id:12},
{firstname: "Bob", lastname: "Taylor", id:24},
{firstname: "Lucy", lastname: "Heart", id:43}
]
// The table component is unaware of the data order operations
const TableComponent = ({tableData}) => <table><tbody>
{tableData.map(d=> <tr key={d.id}>
<td>{d.firstname}</td>
<td>{d.lastname}</td>
</tr>)}
</tbody></table>
// The parent component takes care of feeding the Table
// component with the data in the correct order.
class App extends React.Component {
state = { sortBy: "firstname"}
handleChange = (event) => this.setState(
{sortBy: event.target.value}
);
render () {
const {data} = this.props;
const {sortBy} = this.state;
const sortedData = data.sort((a,b) => a[sortBy]>b[sortBy]?1:-1)
return <div>
Sort by
<select value={sortBy} onChange={this.handleChange}>
<option value="firstname">First Name</option>
<option value="lastname">Last Name</option>
</select>
<h2>The table: </h2>
<TableComponent tableData={sortedData} />
</div>
}
}
ReactDOM.render(
<App data={data} />,
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>
Here's a full example of an app with a table where its rows can be sorted by clicking on the header. Comments are inline and the full example is available here
The table's state contains the rows which are sorted whenever a table column header is clicked as well as the property name of the sorted column.
import React from 'react';
import { MuiThemeProvider} from 'material-ui';
import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui';
// properties of TableHeader component
let headerProps = {
enableSelectAll: false,
displaySelectAll: false,
adjustForCheckbox: false
};
// initial set of rows, simulating data from the database
let rows = [
{firstName: "Adrian", favColor: "gold", uniqueId: 0 },
{firstName: "Alma", favColor: "green", uniqueId: 1 },
{firstName: "Conny", favColor: "black", uniqueId: 2 },
{firstName: "Jane", favColor: "blue", uniqueId: 3 }
];
// our table hader information, key is the name of the
// property to sort by when the header is clicked
let headers = [
{name: "First Name", key: "firstName"},
{name: "Favorite Color", key: "favColor"}
];
// our table component that can sort columns
class SortableTable extends React.Component {
constructor(props){
super(props);
this.state = {rows, sortBy: 'firstName'};
}
renderHeaders(){
let header= headers.map( (h) => {
return <SortableHeader
key={h.key}
name={h.name}
onClicked={()=>this.updateSortBy(h.key)}
isSortColumn={this.state.sortBy == h.key}/>
});
return <TableRow>{header}</TableRow>;
}
renderRows() {
return this.state.rows.map( (row, i) => <UserRow {...row} key={row.uniqueId}/> );
}
updateSortBy(sortBy){
// multiple clicks on the same column reverse the sort order
if( sortBy == this.state.sortBy ){
this.setState( {rows: [...this.state.rows.reverse()]} );
return;
}
let rows = [...this.state.rows];
rows.sort( (a,b) => {
if (a[sortBy] < b[sortBy])
return -1;
if(a[sortBy] > b[sortBy])
return 1;
return 0;
});
this.setState({rows, sortBy});
}
render() {
return (
<MuiThemeProvider>
<Table>
<TableHeader {...headerProps}>
{this.renderHeaders()}
</TableHeader>
<TableBody>
{this.renderRows()}
</TableBody>
</Table>
</MuiThemeProvider>
);
}
}
function SortableHeader(props){
let style = {
cursor: "pointer"
}
if(props.isSortColumn){
style.fontWeight = "bold";
style.color = "black";
}
return (
<TableHeaderColumn>
<div style={style} onClick={() => props.onClicked()}>{props.name}</div>
</TableHeaderColumn>
);
}
function UserRow(props){
return (
<TableRow>
<TableRowColumn>{props.firstName}</TableRowColumn>
<TableRowColumn>{props.favColor}</TableRowColumn>
</TableRow>
);
}
export default SortableTable;