React

May 5, 2019
10 minute read

To get started:

`create-react-app yacra`

This will scaffold out a functioning React app, with webpack and babel ready to go. Then bootstrap.

npm i bootstrap@4.1.1

In React, everything is just Javascript. JSX takes this to the next level, providing syntactic sugar to crunch out lots of React.createElement, based on a HTML-esk syntax. babel.js takes care of the transpilation from HTML looking tags to actual Javascript. To get a real sense of this, go to babeljs.io/repl and type in const element = <h1>hello world</h1>;. You’ll see this get translated to:

DOM control

JSX expressions must have a single parent element, because babel needs a single React.createElement parent, before populating it with many child elements. Using a single outer <div would be one option, but if you really don’t want to include any outer DOM, can use the React.Fragment shown above.

Styling

Because JSX needs to boil down into JS, reserved JS keywords like class cannot be used in JSX. To set the class of an element, must use className.

State Management

In the above click handler, the console.log fails with:

TypeError: this is undefined

this in JS is context dependent. If a method is called on an object obj.method() then this is a reference to that object. However if a function is called statically i.e. function(); then this is a reference to the window object, or in strict mode undefined.

React rule of thumb:

The component that owns some state, should be responsible for mutating it.

Option 1: Binding

In the constructor of the component, after calling super() can bind this to the static function like so:

Option 2: Arrows

Now that the event handler has this access, cannot just start mutating it, for example this.state.count++ will not affect the UI, as React is not aware that this custom piece of state has changed, and what is impacted by the state change.

render() {
return (
<React.Fragment>
{this.props.children}
<span className={this.getBadgeClasses()}>{this.formatCount()}</span> This will render the children as defined in the calling component, in this case an `h2` tag will be emitted.

Interestingly props is immutable, and can’t be modified, state should be used.

Raising and Handling Events between Components

State management rule of thumb:

The component that owns some state, should be responsible for mutating it.

A common scenario is for parent or outer components to define the state that is consumed by downstream components. Given the rule of thumb above, how should a downstream component go about modifying the original state?

One good option is the observer pattern, in which a child component raises an event, which can be handled by its parent component to react and respond to a state change.

For example, the Counters component defines several Counter components. A component can elect to delete itself by displaying a delete button to the user. If clicked, the Counter instance could raise an onDelete event. Counters could handle this event with handleDelete().

In the Counters component:

create event handler e.g. handleDelete responsible for mutating the original state that relates to the event. important in React, you can’t just mutate state and expect React to know about it, instead you must reassign the state using Reacts setState function (see below)

Controlled Components

Local state within components, can cause components to get out of wack. For example, when setting the initial state of a child component from props only happens when the component is created. Future changes to state in the parent, that was passed down as props to its children, will not flow through after initial creation.

A controlled component is one that:

Receives essential data needed to render via props from its parent.

Never manages this as state locally, but instead fires events to request the data be updated back in the parent.

Refactoring steps:

Remove any local state

Any references to this.state should be updated to use props directly, and trigger events to communicate with the parent (observer) where needed.

Synchronising Components

Sometimes, as the architecture of the view changes, new components get introduced. This can modify the shape of the component tree.

For example, introducing a navbar component that requires access to the state of another unrelated component.

The general pattern for this is known as lifting the state upwards. The higher in the tree the state lives, the more widely it can be propagated through other downstream components.

The Counters component used to be responsible for managing the counters in its own state, rendering each child Counter component. Lifting this state upwards to top level App component, means refactoring this.state access with this.props accessors. Event handlers must bubble upwards too:

In the top level App component, the render can now propagate state as needed, for example only passing the totalCounters to the NavBar component, while passing down the full counter objects to Counters: