Sitemap

Tips for success with React and Redux.

9 min readSep 29, 2017

--

As a contractor over the past two years I’ve had the pleasure to bounce around several teams in London working on React & Redux apps. On the job I find myself doling out the same nuggets of advice. Some of which are received like a stroke of genius, some like I’m speaking double dutch, and some like the nugget I offer is of the chicken variety… and rotten.

Undeterred I am now turning to the people of Medium to doll out more unsolicited advice. I’m going to cover some basic React/Redux lessons I’ve learnt along the way, and some general project problems you’re likely to run into. A lot of this is opinionated, I am aware, but it’s been born through experience and many failures along the way. Hopefully it will help some people avoid some of the mistakes I’ve made.

React

Lets kick off with some quick points around React. If you haven’t heard of it, I’m not sure why you’re here, but thanks for sticking around!

Data fetching

I like to follow the container/presentation component approach written about at length. Simply put: container components handle the data, and presentational components handle the markup and style. Keeping the two separate makes everything much simpler — and much easier to refactor later on.

I’ve often seen an approach where teams use a single top level “container” which is provided access to the store/router, then everything is passed down as props in one giant tree. When asked why this restriction has been imposed it’s common for people to suggest that connecting many components to the store leads to performance problems. I’m fairly confident that this is both a myth and the opposite is true. Passing props to components which don’t need them and just pass down, means upon change the lifecycle will run unnecessarily. Take the data to where it’s needed, it’s faster, simpler, and much more reusable.

Further to that I like each container to be responsible for obtaining the data it needs. That way if you remove or move it around the data is fetched if and when it’s needed. This approach has worked for me, though I concede it may be too simplistic for some project’s needs. I wrote another piece on using a component to fetch your data to facilitate this approach — and I used a similar approach on another repo but using a higher order component instead. The overall approach may feature in another blog post soon, but feel free to get in contact if you are intrigued!

Non HTML components

Components need not output markup either, they can have many other uses. — Analytics for example. React-helmet is the perfect example of this, although it does output markup (meta/title/links) in the header, it does not output markup where you render it. Similarly you can use components to trigger effects for example page-view analytic events.

class Analytics extends React.Component {
sendEvent(event, props) {
// this is a connected redux action to fire analytics
console.log('Event', event, 'Props', props)
}

track({ event, ...props }) {
if (process.browser) this.sendEvent(event, props)
}
componentDidMount() {this.track(this.props)}

componentDidUpdate() {this.track(this.props)}
render() {return null}
}
const PageView = (props) => <Analytics event='pageview' {...props} /><PageView page='search' page={page} />

This approach uses the power of the React lifecycle to take care of half the work for you. If the props you are interested in (the props which represent a page) change, this will automatically fire off page view events. More complicated scenarios can be catered to using shouldComponentUpdate(), but the basic process remains the same.

Folder Structure

Folder structure is a commonly bike-shedded issue. I personally like to mirror atomic design in my components. Folders for atoms, molecules etc, and using template components to keep my responsive layout CSS away from my component styling — work in progress example. In the end though folder structure is not going to affect your project much, and is easily changed later.

A component library is a great idea, if you need it — again though theres no need to go straight for it, it’s easy to move your presentational components out into a library at a later point, say when you take on a second project using similar UI. At that point you can extract your components, and re-use them easily. I can recommend react-storybook as a nice and simple way to showcasing your component library.

React router

This one is straight forward— use version 4, it’s so much simpler. React-router 3 feels like having a giant squid wrapped around and inside your codebase, and trying to extract it is a major piece of code surgery. The team at react-training took a lot of flak for the breaking changes to their API, but it was worth it, version 4 is so much much nicer and definitely the right direction. If you’re building a greenfield project I really think there is no good reason to go back to version 3.

Redux

Redux is such a great library, and with these top tips hopefully you’ll live an easy bug free life!

Top redux tip #1: normalise your state

This tip is so good that it’s in the docs nowadays, but normalising your state will make everything simpler, and reduce bugs when dealing with data. Plenty has been written about this I just want to re-iterate how important it is to get right. The further you go down the road without doing this, the bigger problem and harder to fix it will be. Another great library if you find it cumbersome extracting the data from your normalised state or performance is becoming an issue is reselect. Great at what it does, but I tend to only introduce it when I need it rather than everywhere all the time.

Top redux tip #2: don’t simply discard data

A common anti-pattern I’ve seen in redux stores, is to discard data that could be useful later, or to ‘share’ a namespace rather than have unique keys. This is easier to explain with an example; Imagine a reducer handling search results for a clothes shop. e.g.

{searches: {searchTerm: ‘pyjamas’, results: [‘id1’, ‘id2’]}}

(where the ids are products normalised in tip #1!). Then when the user searches for something else, the searchTerm is updated and the results deleted.

This is a mistake — that data is not wrong and you might need it again. Unless you’re dealing with huge amounts of data and memory is tight, don’t throw it away. Instead store your search results using a key too e.g.

{searches: { pyjamas: {results: [‘id1’, ‘id2’]}}. 

This will save a lot of hassle trying to work out when you have results that you need to clear, and it makes going back to previous pages much simpler (and faster!). Remember though that the store itself is held in memory and unless you persist it somehow you can’t assume that data is always there.

Top redux tip #3: Don’t use immutableJS

This tip is also known as the shameless self promotion tip, ImmutableJS is not always a good idea, and you can read why in another of my posts. This also needs an update now that flow is so widespread, as using immutable basically erases any typing you’ve done.

Top redux tip #4: Use actions for all the things

Something that is regularly misunderstood, actions aren’t restrained to store updates. If a user interacts with one of your components, all I ever want to see it doing is dispatching an action. Yes if it’s just throwaway ui state then setState can be used, but thats the only exception. Everything else should go through actions, it doesn’t matter if it eventually changes the store or not, it doesn’t need to, actions can do anything.

Press enter or click to view image in full size

The most common violation of this I see is analytics, people just bolt on analytics methods everywhere, and then they get forgotten deleted or broken. Treating your analytics in the above pattern means you see them alongside your actions in the amazing redux dev tools. They’re easy to debug, they have more visibility, and follow the same lifecycle as your app.

Top redux tip #5: Don’t forget it’s one way

This is one of the obvious ones and most of the time it’s not violated, but don’t forget that everything is based on the flux one way data flow. One dead give away to watch out for — if you’re using await or .then in a component. If you see this, then you’re probably violating this basic principle of the flux architecture and you’ll run in to confusion with state or callback hell. Your components should react to changes in state, not await completion of actions or any other async operations. Holding on to that kind of information is violating the single source of truth that is your store and is likely pushing business logic from your actions into your components.

Opinionated coding style

Coding style wise, everyone has their opinions, functional programming is all the rage right now but I think the bar to entry is very high. I think taking on board the practices of functional programming (i.e. pure functions, no mutation, composition, etc.) without going full fantasyland is a good middleground. Regardless of where you land, you should always agree as a team the coding style, stick to it and evolve it over time. My basics tips for easier to read code:

  • Generally avoid ‘let’ as reassignment adds complication.
  • Don’t mutate anything you create — always create a new thing.
  • Small pure functions are good and easy to understand / test
  • Nested conditional statements are code smell.
  • Once you’ve decided on your style — enforce it strongly through linting.

That last point can make some devs mad. Personally I like a codebase to look as if one person wrote it, the consistency makes it easy for team members to move to unfamiliar areas of code, and assists with refactoring. If you do go down the linting route, best to start from a widely used preset . It can speed up on-boarding new devs, it automatically updates with new rules, and theres less arguing about what should be on/off. Obviously customise it to your team, but don’t go crazy.

Project management

Ok so you’ve decided it’s time to redo your website, question— is your API stable? I’ve been in many projects where the answer is “no”, or “we’re rebuilding that too”. Building a website on an ever moving api, although it can lead to a very resilient front end, is always a pain. You end up taking twice as long to rework code to adapt to changes up stream. Get your data stable first, and make sure it’s either complete, or optional.

Another regular concern is the team — do you have enough design resource, and do you have a BA working in advance of the devs. If the tickets dry up or are badly filled out you’ll be surprised how quickly things go wrong, end up needing rewrites, or even worse - the devs leave. I hate nothing more than sitting twiddling my thumbs, and I know I’m not the only one. Make sure there is a plan more than a week in advance, nothing comes across as more amateur than a company who can’t fill the next sprint.

Finally more angled at the development — keep it simple. Do all the basic stuff first, or you’ll end up with an over complicated solution which is brittle and too complicated to redo so you just keep bolting on to it. Eventually you’ll realise it’s no better than the one before it! Bundle splitting and loading is a very common example of this. There are many easier optimisations that you can do before you need to tackle this. For example if you do the basics and your site works without JS, then arguably your bundle load time can be much longer with no impact on the user. Don’t get me wrong, perf is very important, but get your app stable and complete before you go after those 1% gains.

Conclusion

There is a lot of projects being built in the React/Redux stack now, and with the constant backing that Facebook is giving it, I think it is around to stay. Couple that with an uptake in React-Native, React VR, and ReasonML, Facebook is bridging platform gaps to make React a ubiquitous library.

Armed with the lessons above I hope you’ll be able to avoid some of the mistakes I’ve made along the way and focus more on the complex problems in life — like, quantum computing, world peace, or why Apple decided to put a notch in the new iphone screen.

--

--

No responses yet