I'm studying a React app made up by one main component: App.js (the main one) and three other external components: Dog.js, DogItem.js, AddDog.js The App contain a set of items (Dogs): Dog.js, made up of single dog elements, DogItem.js, and a form: AddDog.js to add a new item: dog. In the AddDog.js file, the only line I don't realize is this.props.addDog(this.state.newDog); I have highlighted it below.
I'd like to underline that addDog in this.props.addDog(this.state.newDog); is different from the name of the component AddDog.
Thank you.
Here's AddDog.js
import React, { Component } from 'react';
class AddDog extends Component {
constructor() {
super();
this.state = {
newDog:{}
}
}
static defaultProps = {
categories: ['Web Design', 'Web Development', 'Mobile Development']
}
handleSubmit(e) {
if(this.refs.name.value === '') {
alert('Title is required');
} else if (this.refs.image.value === '') {
alert('Image link is required');
} else if (this.refs.breed.value === '') {
alert('Breed is required');
} else {
this.setState({newDog:{
name: this.refs.name.value,
breed: this.refs.breed.value,
image: this.refs.image.value
}}, function() {
this.props.addDog(this.state.newDog); // <<<<<<<<<<<<<<<<<
});
}
e.preventDefault();
}
render() {
return (
<div>
<h3 id="addDog">Add Dog</h3>
<form onSubmit={this.handleSubmit.bind(this)}>
<div>
<label>Name</label><br />
<input id="dogName" type="text" ref="name" />
</div>
<div>
<label>Image</label><br />
<input id="imageURL" type="text" ref="image" />
</div>
<div>
<label>Breed</label><br />
<input id="dogBreed" type="text" ref="breed" />
</div>
<br />
<input id="submitButton" type="submit" value="Submit" />
<br />
</form>
</div>
);
}
}
export default AddDog;
Here's the App.js
import React, { Component } from 'react';
import Dogs from './components/Dogs';
import DogItem from './components/DogItem';
import AddDog from './components/AddDog';
import './App.css';
class App extends Component {
constructor() {
super();
this.state = {
dogs: []
};
}
getDogs() {
var defaultDogs = {dogs: [
{
name: 'Princess',
breed: 'Corgi',
image: 'https://s-media-cache-ak0.pinimg.com/originals/51/ae/30/51ae30b78696b33a64661fa3ac205b3b.jpg'
},
{
name: 'Riley',
breed: 'Husky',
image: 'http://portland.ohsohandy.com/images/uploads/93796/m/nice-and-sweet-siberian-husky-puppies-for-free-adoption.jpg'
},
]};
this.setState(defaultDogs);
}
componentWillMount() { // this soon display the two dogs before the render
this.getDogs();
}
handleAddDog(dog) {
let dogs = this.state.dogs;
dogs.push(dog);
this.setState({dogs:dogs});
}
handleDeleteDog(name) {
let dogs = this.state.dogs;
let index = dogs.findIndex(x => x.name === name); // function (x) {return x.name === name} is like x => x.name === name
dogs.splice(index, 1);
this.setState({dogs:dogs});
}
render() {
return (
<div className="App">
<Dogs dogs={this.state.dogs} onDelete={this.handleDeleteDog.bind(this)} />
<AddDog addDog={this.handleAddDog.bind(this)} />
<hr />
</div>
);
}
}
export default App;
Here's Dog.js
<pre>
import React, { Component } from 'react';
import DogItem from './DogItem';
class Dogs extends Component {
deleteDog(name) {
this.props.onDelete(name);
}
render() {
let dogItem;
if (this.props.dogs) {
dogItem = this.props.dogs.map(dog => {
return (
<DogItem onDelete={this.deleteDog.bind(this)} key={dog.name} dog={dog} />
);
});
}
return (
<div className="Dogs">
<h1>Good Dogs</h1>
{dogItem}
</div>
);
}
}
export default Dogs;
Here's DogItem.js
import React, { Component } from 'react';
class DogItem extends Component {
deleteDog(name) {
this.props.onDelete(name);
}
render() {
return (
<ul className="Dog">
<img src={this.props.dog.image} href={this.props.dog.image} role="presentation" width="100" height="100"></img>
<br></br>
<strong>{this.props.dog.name}</strong>: {this.props.dog.breed} <a href="#" onClick={this.deleteDog.bind(this, this.props.dog.name)}>X</a>
<br></br>
</ul>
);
}
}
export default DogItem;
Top comments (2)
Ok, I've just found the meaning.
It creates a new dog item, sets the state of the child and passes to the parent component the state of the child to the prop addDog that will fire the bound function handleAddDog in App.js.
Yes. I think you got it.
React has one way data flow.
So when you want to pass child component's data (a new dog) back to the parent (which is the one that maintains the list of dogs), you pass a callback to the child component, which will call the handler with the newly created dog object.
Simply put,
this.props.addDog
passes form data back toApp
component.I've spotted a bug in
App.handleAddDog
, in which you are mutating thethis.state.dogs
by pushing the dog to the state directly.You should not mutate the state object directly as React would not know if the
this.state.dogs
has not changed.So instead of
create a copy (a new reference of dogs) and set it as a new state.
The reason for passing a new
reference
ofdogs
is an advanced concept on how React reconciles changes.Simply put, it's for React not having to do deep property change checks
If you want to know more on how React reconcilation diff'ing algorithm works, check out this post.
css-tricks.com/how-react-reconcili...