Last week I completed a project using React. This used an API to generate news stories that a user could view, upvote, comment on and like individual comments. In general the project was fun to build and I was quite pleased with the finished product.
React’s method for creating components made implementation nice and easy. I was able to make very small reuse-able components such as an upvote button. The approach takes a lot of preplanning, and an understanding of how individual parts will affect the architecture as a whole. I implemented material-ui so this approach made custom CSS easy as I only needed to alter the CSS in one area that was specific to the individual component.
Component lifecycle and flow of information
However, the biggest problem I encountered was the flow of data from one over-arching component and how I needed to pass relevant data from area to the next. This lead to confusion on where I needed to have a state and how I would change the state so that the app would render in an appropriate way. An example of this is;
- News container would pull information from an external API. The response was an array of articles, and would be stored in state within the container.
- Iterating through the articles array, a component would be generated per article. The article data was then passed down to the component.
- The article component then created two more components: CardHeader and Summary. The data passed down from the article would then be split between these two components as it was passed down.
This seems relatively simple, but the problem I encountered was when I needed state to change as the user interacted with the page. When a user clicked on the title of the article, I needed to use a callback to change the view of the page using another container. When I changed the state within the news component, even though I was changing the URL, the page would not display the content that I wanted. The problem was in React’s component lifecycle, and how routes worked when using react-router-dom. Even though I had changed the route and was enacting a re-render of the page. Only the page that the user was on would be re-rendered, the URL would change and look like it was doing what it was meant to but did not work as intended. This required me to:
- Use a callback to the App component(the overarching component) and update the state.
- Store the particular article that was clicked in localStorage to prevent the app from crashing if the user refreshed the page.
- Change the URL.
The change was only small, rather than updating the state in the most immediate component, I actually needed to update the state in the App component. What this did was rather than re-rendering the specific component, it re-rendered the App component as a whole, as the routes were set in this component, the re-render would mean that the appropriate component was displayed in the DOM rather than sticking on the current component.
As I further built out the project, passing data via props to specific components lead to a lot of confusion as to which components needed what, which components needed to cause changes, which components would handle those changes and where I was actually coding theses things. Naming conventions became quite important very quickly so that I could easily identify which components needed to do what. I had take a modular approach when designing the components, which made quite handy, reuse-able components. It also increased the length of the chain that I needed to pass the data along.
If only I could have global state…
Redux is a way for react apps to have a global state which components can use to get data and change that data in a more specific, targeted way. What this means in terms of the project I made was that rather than have a long chain of props being passed down again and again, so that I could cause a tiny change in one far away component, I could get the state that I needed in the component that required it, cutting out the need to pass them all the way down. It also means that instead of entire sections of the app re-rendering when state would change, only specific components would re-render based on the state that they required.
Whats also really useful is that you can still pass data down via props in the react conventional way. Whilst this may seem like it defeats the point of redux, smaller presentational components could remain as they are. They would not need to be aware of redux and not need to be connected to the store either. It means that reuse-able components could be written and could be implemented in redux apps and also non-redux apps. Making them uber reuse-able.
Go forward I would like to implement redux in this particular app as it was surprising how quickly things started to get out of control with a relatively simple state. I plan on extended the project further and would require more states in more components, so redux would be a great fit for scaling the app for the future.