This training workshop will cover the fundamentals of React. React.js is a an open-source JavaScript library for creating user interfaces with a focus on the UI and has become the tool of choice for easily building dynamic user interfaces.
- Laptop
- Node/NPM (https://nodejs.org/en/download/)
- Chrome (https://www.google.com/chrome/)
- Chrome Extension - React Developer Tools (https://goo.gl/g16a7N)
- Text editor (https://code.visualstudio.com/)
This project was bootstrapped with Create React App.
Make sure you have Node 8.10 or later on your local development machine.
node -v
If you don’t, install the latest version: https://nodejs.org/en/.
Verify that everything works by running:
git clone https://github.com/feedzai/first-react-app-workshop
cd first-react-app-workshop
npm install
npm start
Open http://localhost:3000 to view it in the browser.
If there are any questions, feel free to email me! jose.sousa@feedzai.com
First we need to render a feed of posts so we will need to create the PhotoFeed
component. To start this will render only a <div>
with a text inside.
// src/components/PhotoFeed.js
export default class PhotoFeed extends PureComponent {
render() {
return (
<div className="App-body">
PhotoFeed
</div>
);
}
}
Now we need to display the component in the PhotoFeedPage
, first import the PhotoFeed
in the PhotoFeedPage
.
// src/routes/PhotoFeedPage.js
import PhotoFeed from "../components/PhotoFeed";
After importing we need to render the component, in the render method of PhotoFeedPage
add the previously created component and pass by props the posts
and the onLikeIncrement
function.
// src/routes/PhotoFeedPage.js
render() {
return (
<PhotoFeed
posts={this.state.posts}
onLikeIncrement={this._onLikeIncrement}
/>
);
}
In our PhotoFeed
component, we need to show all the posts passed throught props. On the render method we need to iterate through a list of Posts.
Import the Photo
component and Col
, Row
from Ant Design.
// src/components/PhotoFeed.js
import Photo from "./Photo";
To render multiple items in React, we pass an array of React elements. The most common way to build that array is to map over your array of data. Let’s do that in the render method of PhotoFeed:
// src/components/PhotoFeed.js
export default class PhotoFeed extends PureComponent {
render() {
const { posts, onLikeIncrement } = this.props;
return (
<div className="App-body">
<Row gutter={40}>
{posts.map((post) => (
<Col key={`col_${post.id}`} span={8}>
<Photo {...post} onLikeIncrement={onLikeIncrement} />
</Col>
))}
</Row>
</div>
);
}
}
React components can have state by setting this.state
in the constructor, which should be considered private to the component.
In this application the state is stored in the PhotoDetailsPage
component and then passed to the children components via props.
Whenever this.setState
is called, an update to the component is scheduled, causing React to merge in the passed state update and re-render the component along with its descendants.
// /src/components/Photo.js
{likes} <Icon type="heart" onClick={this._onClickLike} />
On Photo
component we need to add a callback _onClickLike
to the existing Icon component. The _onClickLike
will call onLikeIncrement
that is passed to Photo component via props by PhotoDetailsPage
component, this function updates the posts that are stored in state and calls the setState function with the updated posts.
// src/components/Photo.js
_onClickLike = () => {
this.props.onLikeIncrement(this.props.id);
}
Now in the PhotoFeedPage
we need to save the posts
state.
// src/routes/PhotoFeedPage.js
_onLikeIncrement = (postId) => {
const posts = likeIncrement(this.state.posts, postId);
this.setState({
posts
});
};
After this the Photo
component will re-render with the updated number of likes.
Now we will want to create a new Route to enable us when clicking on a post to go to the details page.
// /src/app/App.js
<Route
path="/:postId"
component={PhotoDetailsPage}
/>
We setup a Route
in App
component defining a path, in this case /:postId
. This path parameter can be accessed by this.props.match.params.{nameOfTheParameter}
and the component that should be rendered, in this case PhotoDetailsPage
.
Finally for each Photo
component we need to add a Link
that when clicked will change the route of our application to PhotoDetailsPage
component.
// /src/components/Photo.js
<Link to={`/${id}`}>
<Meta description={caption} />
</Link>
As your app grows, you can catch a lot of bugs with typechecking. For some applications, you can use JavaScript extensions like Flow or TypeScript to typecheck your whole application. But even if you don’t use those, React has some built-in typechecking abilities. To run typechecking on the props for a component, you can assign the special propTypes property.
Import the PropTypes
.
// src/components/PhotoFeed.js
import PropTypes from 'prop-types';
On the PhotoFeed
component set the prop posts
to the type array
and required
and the prop onLikeIncrement
to the type func
and required
.
// src/components/PhotoFeed.js
static propTypes = {
posts: PropTypes.array.isRequired,
onLikeIncrement: PropTypes.func.isRequired
};
You're at the end of your journey, and you've accomplished a lot. Congrats, You are awesome!
You can learn more in the Create React App documentation.
To learn React, check out the React documentation.
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify