React Retrospective

I worked on the following small projects to familiarize myself with React:

While there were many lessons - here are some points that stood out:


I found components of more than a few hundred lines of code increasingly difficult to refactor or extend. I ported my ES6 code to Typescript and found this reduced the complexity curve and revealed a few subtle defects in the process.

export type Action =
  | UndoAction
  | RedoAction
  | OpSetTypeAction
  | OpSetColorAction
  | OpCreateAction
  | OpUpdateAction;

export type Dispatch = (action: Action) => void;

Stateless Components

Unsurprisingly, I found stateless components easier to understand and less error prone.

Dependency Injection

I used higher order functions to inject dependencies and isolate tests to easily replicate different corner cases.

const getFeedFn = (userName) => Promise.resolve([]),
  component = create(


Redux and its tooling proved effective at detecting and avoiding mutations. I learnt a lot about common javascript functions and their behavior and performance trying to write immutable code.

  return {
    future: state.future.slice(0, -1),
    history: state.history.slice().concat(state.future.slice(-1)),

It took me some time to appreciate mapDispatchToProps and how I could remove knowledge of despatch from my jsx.

const mapDispatchToProps = (dispatch: Dispatch) => {
  return {
    onChangeComplete: (color: any) => {
        payload: { color: color.hex },


Cloning is useful in some more advanced scenarios. e.g. add/override a event listener without knowledge of the props.children component internals.

  <Button variant="contained">
    // ...
function ColorPicker({ children, onChangeComplete, color }) {
  // ...
  return (
      {React.cloneElement(children, { onClick: handleClick })}
      // ...

Error Boundaries

I have a lot of appreciation for this pattern and would love to see it applied more widely. I did had some initial difficulty applying them to async component lifecycle.

componentDidMount() {
  // ...
  .catch((error) => this.setState({ error }));

render() {
  if (this.state.error) throw this.state.error;
  // ...

Create React App

This was the easiest way to be productive quickly without the common catch of being locked-in.