External dependencies


Everything in FDS is defined using JavaScript, including templates and styling. To achieve this, we used two main dependencies: React and Glamor.

React: UI

React is Facebook's library for building User Interfaces using JavaScript. If you are completely unfamiliar with it, their documentation is quite extensive and approachable.

In the following sections we'll highlight some basic concepts and best practices we use extensively in FDS and Fx components. If you like more detailed information about them, follow the links spread throughout.

React best practices (written for React 16.1 and earlier)

This whole section serves as a foundation to understand the actual documentation on the new concepts we created using React (which follow afterwards). So if you are an experienced React developer, you can try to skip ahead. If you haven't used React (extensively) before. We would recommend starting with the Quick Start set of articles in the React documentation. We will refer to parts of that documentation, and some of the advanced guides and reference articles where appropriate.

Components, elements, Higher-order Components, JSX and ReactDOM.

React Component is a definition of a piece of UI (both the look and the feel). To use it somewhere you have to render it to the DOM(if using React for the web, which we assume to do for the rest of this guide). This is done using ReactDOM.render().

If you look closely at that documentation, you'll notice the first parameter to be 'element'. To create a React element, you generally use JSX.

JSX is compiled into JavaScript using a compiler like Babel. The compiled JavaScript uses React.createElement() to create React elements which describe a part of the resulting DOM that'll be created by React.

A React element can describe an instance of a React Component or a generic DOM node. In JSX, a Component is always <UppercasedLikeThis />. A DOM node is <always-lowercased-like-this />.

A special kind of Component (definition) is a so-called Higher-order Component, HoC for short. These are more advanced types of components explained well in the previously linked React documentation. Their main purpose is to encapsulate and reuse behavior and logic across different components by only implementing it once. An alternative would be to implement that logic into a component which adheres to the 'children as a function' paradigm explained below.

Even though React components can be defined using both classes and functions, you'll notice when working with React, and FDS for that matter, a more functional approach in general for structuring your application.

Props, callbacks, render functions and children as a function

When defining a React Component, you can use props to accept data from parent components. A prop can also be in the form of a function/callback and can then be used to supply additional context from the component to the parent component.

So in simple terms, by accepting a callback, a component could make the parent component responsible for implementing certain parts of it. These parts can be anything from pieces of an algorithm (like a filter callback on an autocomplete to match the current text input to the appropriate item) or pieces of the actual UI (like a callback to render a specific card's content in a generic cards list component, these are usually called render functions/callbacks).

There is also a special prop in React called children, it is automatically filled with a special opaque data structure by React. You can also choose to expect (and call) a function instead of that special data structure when rendering children. This again allows you to pass some of the component's data to the parent component (where the children prop, now a function, is implemented / handled). This paradigm is called 'children as a function' and allows you to encapsulate behavior or logic into a single component, which can be instantiated and reused by other components. For example, a component like MousePosition could be used like this: <MousePosition>{(x, y) => ...}</MousePosition>.

This impacts the API of your component; the way it feels when instantiating it in JSX, they are otherwise functionally equivalent.

Context

As you might know, Context is a special set of APIs found on React Components to pass data along the whole component hierarchy without explicitly passing it via props. This can be very useful for certain features (routing, theming and localisation are the usual examples). In FDS and Fx, we also use context for similar system-wide concerns.

Over time, a lot of great recommendations around the use of Context have emerged. These basically entail: do not use it directly, use HoCs to wrap Context in your own APIs for easy upgrading as Context is eventually deprecated/altered by React.

We've followed this advice and therefore have our own components / HoCs that encapsulate our usages of Context.

When you’re customizing Fonto, you shouldn't have to use Context directly yourself. If you think you do, there might be a better solution available using plain React props and setState.

setState as a function of the previous state

When using setState to set a new state based on the previous one. Make sure to use setState with a function as the first argument (whose first parameter is the previousState). This ensures an atomic update / prevents race conditions.

setState callback vs componentDidUpdate

When you want to ensure something happens after React has set a new state, you could use the second parameter of setState, which is a callback, fired when React has re-rendered the component. There is a lifecycle method on components that is also fired after each re-render, called componentDidUpdate().

We found this to be more reliable to use as it always fires after every re-render, not just after the re-render caused by a specific setState call, which is usually what you want to have happen anyway.

componentWillMount vs componentDidMount

When we started with FDS, we used a lot of componentWillMount() to initialize timers, add callbacks to a Notifier on a manager, etc. After reading the documentation more carefully, we realized we should've used componentDidMount() for most of those instead.

This also forces you to create a state in your component where it can render before all (external) data is available. Making your component more robust in case the (external) data is slow to arrive for whatever reason.

This is especially relevant in Fx components which use managers to query for data they visualize as it becomes available. Most, if not all, managers expose their data asynchronously via some sort of change Notifier and a getter / property. Handling this correctly means adding a callback to the Notifier in componentDidMount and using setState inside the callback to trigger a re-render.

Lifting up state

One of the core principles of React is that to share data between several components, state (data) should be lifted up(in the component hierarchy) to the closest common ancestor.

When you build a component library like FDS. You'll realize that by following this principle, most components shouldn't manage their own state directly.

Instead they should accept a prop to inject data in the component and another prop (as a callback) to be triggered when the user interacts with the component in a certain way.

(Eg. a TextInput component has a prop called value to set the value, and an onChange callback prop which is called whenever the user (tries to) type a character in the rendered input DOM element. The component in which you render TextInput should implement the value as a state property and call setState whenever TextInput's onChange is called.)

This allows you to further lift this state as you need. If the state was already defined in TextInput, you couldn't lift it as this would require rewriting the TextInput.

Glamor: CSS-in-JS

Glamor is the name of the JavaScript library we use to declare styles inline; inside a component file a technique that is has come to be known as CSS-in-JS. It allows you to specify CSS instructions using JavaScript, which are then extracted at runtime and placed in <style> elements in the <head> of the page. The selectors are generated automatically and are guaranteed to be unique (selector class names contain a generated id, based on the CSS rules that are used).

We've made a utility function called applyCss() and a special container components with an applyCss prop such as Block or Flex. These are used to compose and reuse inline styles more easily and are explained in more detail in the API reference.

Importing directly from 'glamor' is possible but discouraged. We might change our CSS-in-JS implementation to another library in an upcoming minor release. The utility and prop applyCss will be supported during the whole 7.x release.