Passing properties through components in ReactJS, ES6 example - javascript

I'm new to React and need some help. I'm trying to rewrite this Facebook's offical example into something own in ES6:
http://codepen.io/gaearon/pen/rrJNJY?editors=0010#0
My code looks like this:
class Person extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>{this.props.user.name}</h3>
<h4>{this.props.user.surname}</h4>
<h4>{this.props.user.age}</h4>
</div>
)
}
}
class VisualAppearance extends Component {
render() {
return(
<div>
<p>{this.props.user.visuals.eyes}</p>
<p>{this.props.user.visuals.height}</p>
<p>{this.props.user.visuals.hair}</p>
</div>
);
}
}
class CreatePerson extends Component {
render() {
return(
<div>
<h1>Personal Info: </h1>
<Person user={this.props.user}/>
<h1>Visual Appearance: </h1>
<VisualAppearance user={this.props.user}/>
<h1>Time Created:</h1>
<p>{this.props.dateCreated}</p>
</div>
);
}
}
var use = {
user: {
name: 'Dude',
surname: 'Dude Surname',
age: 30,
visuals: {
eyes: 'blue',
height: 180,
hair: 'dark'
}
},
dateCreated: new Date()
}
ReactDOM.render(
<CreatePerson name={use.user.name}
surname={use.user.surname} age={use.user.age} eyes={use.user.visuals.eyes} height={use.user.visuals.height}
hair={use.user.visuals.height} date={use.user.dateCreated}
/>
, document.getElementById('project'));
I get the following error: Cannot read property 'name' of undefined
If I change this just to this.props.user it goes through but the same error as above is reported on the surname.
In the link provided there is: props.user.avatarUrl , so it's a nested structure of the object.
How can I make this work and nesting object's properties like this.props.sth.sthElse.sthElse1 on ES6 Classes in React?

CreatePerson expects a property called user here:
class CreatePerson extends Component {
render() {
return(
<div>
<h1>Personal Info: </h1>
<Person user={this.props.user}/> // <====
<h1>Visual Appearance: </h1>
<VisualAppearance user={this.props.user}/> // <====
<h1>Time Created:</h1>
<p>{this.props.dateCreated}</p>
</div>
);
}
}
You're not passing it one. You're passing it name, surname, and a bunch of others, but not user.
It works if you remove all those individual properties and pass it user instead:
ReactDOM.render(
<CreatePerson user={use.user} />
, document.getElementById('project'));
Example:
class Person extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>{this.props.user.name}</h3>
<h4>{this.props.user.surname}</h4>
<h4>{this.props.user.age}</h4>
</div>
)
}
}
class VisualAppearance extends React.Component {
render() {
return(
<div>
<p>{this.props.user.visuals.eyes}</p>
<p>{this.props.user.visuals.height}</p>
<p>{this.props.user.visuals.hair}</p>
</div>
);
}
}
class CreatePerson extends React.Component {
render() {
return(
<div>
<h1>Personal Info: </h1>
<Person user={this.props.user}/>
<h1>Visual Appearance: </h1>
<VisualAppearance user={this.props.user}/>
<h1>Time Created:</h1>
<p>{this.props.dateCreated}</p>
</div>
);
}
}
var use = {
user: {
name: 'Dude',
surname: 'Dude Surname',
age: 30,
visuals: {
eyes: 'blue',
height: 180,
hair: 'dark'
}
},
dateCreated: new Date()
}
ReactDOM.render(
<CreatePerson user={use.user} />
, document.getElementById('project'));
<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="project"></div>

Related

Adding an Object to an Object's Array and setting the state in React

I am new at React and I come up with an Idea for learning many things in one shot. I have this component, Its initial state is an array with an object of baseball Players, I need to add new baseball Player's name through an Input field to the state and then, once a baseball Player is added, a second component appears with input fields to add data.
How can I do that?
export default class BaseballPlayerList extends React.Component {
constructor() {
super();
this.state = {
baseBallPlayers: [
{
name: "Barry Bonds",
seasons: [
{
year: 1994,
homeRuns: 37,
hitting: 0.294
},
{
year: 1996,
homeRuns: 40,
hitting: 0.294
}
]
}
]
};
this.addPlayer = this.addPlayer.bind(this);
}
addPlayer(e) {
e.preventDefault();
const newPLayer = {
baseBallPlayers: this.state.baseBallPlayers.name,
seasons: []
};
console.log(newPLayer);
this.setState(prevState => ({
baseBallPlayers: [...prevState.baseBallPlayers, newPlayer]
}));
}
render() {
return (
<div>
<div>
<ul>
{this.state.baseBallPlayers.map((player, idx) => (
<li key={idx}>
<PlayerSeasonInfo player={player} />
</li>
))}
</ul>
</div>
<input value={this.state.baseBallPlayers.name} />
<button onClick={this.addPlayer}>AddPlayer</button>
</div>
);
}
}
export default class PlayerSeasonInfo extends Component {
constructor(props) {
super(props);
this.player = this.props.player;
}
render() {
return (
<div>
{this.player && (
<div>
<span>{this.baseBallPlayers.name}</span>
<span>
<input placeholder="year" />
<input placeholder="homeRuns" />
<input placeholder="hitting" />
<button>AddInfo</button>
</span>
</div>
)}
</div>
);
}
}
here do you have a working example: https://codesandbox.io/s/nervous-yonath-9u2d6
the problem was where you where storing the new name and how you where updating the whole players state.
hope the example helps!

React tutorial via PluralSight - props is not defined

I've been following a React tutorial on PluralSight when I ran into an error. Could be mine, I don't know.
I've been using JS Complete. The tutorial directed me to this URL, which is the starting point:
https://jscomplete.com/playground/rgs2.4
As the tutorial progressed, it led me to the following code:
const testData = [
{name: "Dan Abramov", avatar_url: "https://avatars0.githubusercontent.com/u/810438?v=4", company: "#facebook"},
{name: "Sophie Alpert", avatar_url: "https://avatars2.githubusercontent.com/u/6820?v=4", company: "Humu"},
{name: "Sebastian Markbåge", avatar_url: "https://avatars2.githubusercontent.com/u/63648?v=4", company: "Facebook"},
];
const CardList = (props) => (
<div>
{props.profiles.map(profile => <Card {...profile}/>)}
</div>
);
class Card extends React.Component {
render() {
const profile = this.props;
return (
<div className="github-profile">
<img src={profile.avatar_url} />
<div className="info">
<div className="name">{profile.name}</div>
<div className="company">{profile.company}</div>
</div>
</div>
);
}
}
class Form extends React.Component {
render() {
return (
<form action="">
<input type="text" placeholder="GitHub username" />
<button>Add Card</button>
</form>
);
}
}
class App extends React.Component {
constructor() {
super(props);
this.state = {
profiles: testData,
};
}
render() {
return (
<div>
<div className="header">{this.props.title}</div>
<Form />
<CardList profiles={this.state.profiles} />
</div>
);
}
}
ReactDOM.render(
<App title="The GitHub Cards App" />,
mountNode,
);
On the JS Complete site, it prints the error as follows:
ReferenceError: props is not defined
at new App
at constructClassInstance
at updateClassComponent
at beginWork$1
at HTMLUnknownElement.callCallback
at HTMLUnknownElement.sentryWrapped
at Object.invokeGuardedCallbackDev
at invokeGuardedCallback
at beginWork$$1
at performUnitOfWork
I would like to say I followed the tutorial exactly as instructed, but maybe I need a set of new eyes. I'm new to React.
You forgot to put the props in the constructor method
App extends React.Component {
constructor() {...
should be
App extends React.Component {
constructor(props) {...
Please find below the updated working code,
Observed that you are not passing the props from like title and referring from CardList
const CardList = (props) => (
<div>
{props.testData.map(profile => <Card {...profile}/>)}
</div>
);
class Card extends React.Component {
render() {
const profile = this.props;
return (
<div className="github-profile">
<img src={profile.avatar_url} />
<div className="info">
<div className="name">{profile.name}</div>
<div className="company">{profile.company}</div>
</div>
</div>
);
}
}
class App extends React.Component {
render() {
return (
<div>
<div className="header">{this.props.title}</div>
<CardList testData={this.props.data}/>
</div>
);
}
}
const testData = [
{name: "Dan Abramov", avatar_url: "https://avatars0.githubusercontent.com/u/810438?v=4", company: "#facebook"},
{name: "Sophie Alpert", avatar_url: "https://avatars2.githubusercontent.com/u/6820?v=4", company: "Humu"},
{name: "Sebastian Markbåge", avatar_url: "https://avatars2.githubusercontent.com/u/63648?v=4", company: "Facebook"},
];
ReactDOM.render(
<App title="The GitHub Cards App" data={testData}/>,
mountNode,
);

React - iterating over key value pairs in array

I cant get this snippet to output tacos
im not sure what I am doing wrong
let tacos = [{ John: "Guacamole" }, { Sally: "Beef" }, { Greg: "Bean" }];
class Parent extends React.Component {
render() {
return (
<div className="parent-component">
<h3>List of tacos:</h3>
<TacosList tacos={tacos} />
</div>
);
}
}
class TacosList extends React.Component {
render() {
return (
<div className="tacos-list">
{this.props.tacos.map((taco) => {
return
<Parent taco={taco}/>
})}
</div>
);
}
}
render(<Parent />, document.getElementById("root"));
Your problem is that you are breaking into a new line in after return which it's returning undefined while iterating the tacos list.
Furthermore, You will create an infinite loop rendering if you call <Parent /> inside <TacosList />
Either you create a new component to render the items or you do it within the <TacosList /> component
let tacos = [{
person: "John",
ingredient: 'Guacamole'
}, {
person: 'Sally',
ingredient: 'Beef'
}, {
person: 'Greg',
ingredient: 'Bean'
}];
class Parent extends React.Component {
render() {
return (
<div className="parent-component">
<h3>List of tacos:</h3>
<TacosList tacos={tacos} />
</div>
);
}
}
class TacosList extends React.Component {
render() {
return (
<div className="tacos-list">
{this.props.tacos.map((taco, index) => (
<p key={index}>{taco.person}: {taco.ingredient}</p>
))}
</div>
);
}
}
ReactDOM.render(<Parent />, 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>
The problem is
<Parent taco={taco}/>
First parent is not expecting a taco property.
Second I think you intend to actually render the elements to display the taco information there, not a Parent component for each taco.
Start up with creating an atomic component (div, span or IMG) to show the tacos list, in TacosList.
The map in TacosList will work only at the first level, because every item is a JavaScript object, which means you have to know the key, to have the value, or use Object.keys and Object.items to show names.

Updating attributes with search bar in react

I am trying to dynamically render and update views when string contains substring with addition of attribute.
I need to use JavaScript object like this: var ObjectArray =[{"title:"Great Title"},{"title":"Interesting Title"},{"title":"Boring Title"}];
This is what i found but it uses react kind of object and renders only fitting matches.
let contacts = [{
id: 1,
name: 'Sherlock',
phone: '221 221 221'
}, {
id: 2,
name: 'Watson',
phone: '332 333 331'
}]
class App extends React.Component {
render() {
return (
<div>
<h2>Contact List</h2>
<br />
<ContactList contacts={this.props.contacts} />
</div>
)
}
}
class Contact extends React.Component {
render() {
return (
<li>{this.props.contact.name} {this.props.contact.phone}</li>
)
}
}
class ContactList extends React.Component {
constructor() {
super();
this.state = {
search: ''
};
}
updateSearch(event) {
this.setState({
search: event.target.value.substr(0, 10)
});
}
render() {
let filteredContacts = this.props.contacts.filter(
(contact) => {
return contact.name.toLowerCase().includes(this.state.search.toLowerCase());
}
);
console.log(filteredContacts);
return (
<div>
<input className="text" type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} />
<hr />
<ul>
{filteredContacts.map((contact) => {
return <Contact contact={contact} key={contact.id} />
})}
</ul>
</div>
)
}
}
ReactDOM.render(<App contacts={contacts} />, document.getElementById('container'));
ReactDOM.render(
<FilterableProductTable products={PRODUCTS} />,
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>
<body>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
I had my attempts at changing this code but it used all static solutions which did not update.
This is a concept i had:
var ObjectArray =[{"title":"Great Title"},{"title":"Interesting Title"},{"title":"Boring Title"}];
var BoolArray = Array(ObjectArray.length).fill(false);
class App extends React.Component {
constructor() {
super();
this.state = {
search: ''
};
}
updateSearch(event) {
this.setState({
search: event.target.value.substr(0, 10)
});
}
render() {
return(
<input className="text" type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} />
)
{ObjectArray.map((obj, index) => {
return(
<h1 className={BoolArray[index] ? 'red' : 'blue'}>{obj.title}</h1>
)
}
)
}
}
ReactDOM.render(
<App/>
document.getElementById('root')
);
.red{
color : red;
}
.blue{
color: blue
}
<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">
yes is expected to be an object map but is not defined, that will cause issues.
return(
<input className="text" type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} />
)
so, you return that expression and then continue under it? that's dead code because function has exited.
react can only currently return 1 root level element. if you need to return more, you have to wrap into an element.
so
render(){
return <div>
<input ... />
{something.map(el => <h1>{el.title}</h1>)}
</div>
}

How to render an array of objects in React?

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

Categories

Resources