Summary
This post contains notes from chapter 2 in Fullstack React - "Components". The purpose of this chapter is to learn the methodology for building React applications. We are also introduced to all of the different CRUD operations with in memory persistence.
Overview
In this chapter, we build a timer app. The purpose of this chapter is to identify the pattern for building React apps and then build a timer app from scratch so we can get used to following this approach when building React apps. Also in this chapter, we get our first experience with all of the CRUD operations, albeit, still in memory persistence, so when the page is refreshed, we lose everything.
Methodology for developing a React app
- Create a mockup of the app
- Break the app into components
- Build a static version of the app
- Determine what should be stateful
- Determine in which component each piece of state should live
- Hard-code initial states
- Add inverse data flow
- Add server communication
We followed all of those same steps (except 8) in the voting app in chapter 1.
Project Structure - Quick note on project structure...
In the previous chapter, the book source code provided a server as a pre-built Node package (live-server). In this chapter, the book provided own server.js file. So the project structure looks like this:
- time_tracking_app
- node_modules
- public
- js
- app.js - This is where most of our code will be written
- client.js
- helpers.js
- semantic
- vendor
- index.html
- ...
- tests
- server.js
- package.json
- ...
1. Create a mockup of the app
I'm not going to include a mockup of the app, you can see the screenshots in the book for this.
2. Break the app into components
Again, I'm not going to describe the different components in detail. You can see this in the book.
3. Build a static version of the app
This section reinforced a lot of the same concepts that we learned in chapter 1, but with a lot more components. I don't think I learned any new concepts, but it was still a great section because it did reinforce previous concepts.
4. Determine what should be stateful
After you have your static components built, you can start to gauge what should be stored in state versus what should be stored in props. First you should make a list of all of the different pieces of data / properties that are used in your components. For each data point, ask the following:
- Is it passed in from a parent via props? If so, it probably isn’t state.
- Does it change over time? If not, it probably isn’t state.
- Can you compute it based on any other state or props in your component? If so, it’s not state
- Forms are a special circumstance and the properties behind the fields of a form should almost always be stateful. The reason they should be stateful is because we want to store the state of the form in memory as the form changes and then pass that state up during form submission.
5. Determine in which component each piece of state should live
The roles for determining where a piece of data should be stored for state are for each piece of state:
- Identify every component that renders something based on that state.
- Find a common owner component (a single component above all the components that need the state in the hierarchy).
- Either the common owner or another component higher up in the hierarchy should own the state
- If you can’t find a component where it makes sense to own the state, create a new component simply for holding the state and add it somewhere in the hierarchy above the common owner component.
6. Hard Code Initial States
The concepts in this section all pretty much a rehash of what we covered in chapter 1, but with a more complex set of components. As such, I'm not going to repeat them here, but they are definitely worth revisiting in the book if you need a refresher on how to get started with hard coding the initial state. Some of the things that you review are:- Setting up state with property intializers
- Passing down properties (including method handlers) from parent components down to child components
- Updating state when a user makes a change to an input field
- Form components should have a field change handler that updates the state for each field
- There is a chapter later in the book that goes into much more detail about working with forms
- Other Notes:
- Input fields can't have an undefined value, so when initializing state, you want to use empty string ('') instead of setting the value to null
7. Add Inverse Data Flow
Inverse Data Flow refers to the process of a child component invoking the function in a parent component by calling the property that points to the function in the parent component. In the following example, you can see how the parent MoveList component passes down the function for handling the Delete event to the child Movie component. The child Movie component will in turn invoke the delete handler in the MovieList component by calling the property that the parent delete handler function passed down.
This section goes into detail on how to perform all of the CRUD operations. I wrote up a separate blog post on how to perform all of the CRUD Operations in React - Local State.
This section also introduces us to the forceUpdate method and the componentWillUnmount lifecycle method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | class MovieList extends React.Component { state = { movies: [ { title: 'Terminator', id: 1 }, { title: 'Waterboy', id: 2 } ] }; // Delete is handled here handleMovieDelete = (movieId) => { this.deleteMovie(movieId); }; deleteMovie = (movieId) => { this.setState({ movies: this.state.movies.filter(m => m.id !== movieId) }); }; render () { const movieComponents = this.state.movies.map((movie) => ( <Movie key={movie.id} title={movie.title} id={movie.id} onDeleteClick={this.handleMovieDelete} // Delete handler is passed down here /> )); return ( <ul key='ul1'> {movieComponents} </ul> ); } } class Movie extends React.Component { onDeleteClick = () => { this.props.onDeleteClick(this.props.id); // Parent Delete handler is invoked here }; render () { return ( <li>{this.props.title} <button onClick={this.onDeleteClick}>Delete</button> </li> ); } } ReactDOM.render(<MovieList />, document.getElementById('content')); |
This section goes into detail on how to perform all of the CRUD operations. I wrote up a separate blog post on how to perform all of the CRUD Operations in React - Local State.
This section also introduces us to the forceUpdate method and the componentWillUnmount lifecycle method.
- forceUpdate() - this forces a React component to re-render if there were any changes to the properties or state for the component.
- componentWillUnmount - this is called before a component is removed from the app. It is a good place to call any cleanup code that we may have for our component.
Conclusion
In chapter 2, I gained a clearer understanding of how to approach a project in React. There is still a lot to learn to have a fully functional application, but this chapter really reinforced the groundwork that I think will be necessary to start building larger and more complex components and applications. I think this chapter will be a good resource to revisit when I need a reminder on how to implement CRUD in a React app. It also inspired me to make a separate blog post on how to perform CRUD Operations in React - Local State.
No comments:
Post a Comment