Project

General

Profile

Download (4.03 KB) Statistics
| Branch: | Tag: | Revision:
[[state-management]]
# State Management in Foreman & Plugins
:toc: right
:toclevels: 5

Where do I put data so that it's accessible by the React components that need it?

Currently Foreman has a few places for storing data:

* Component state
* Redux store
* ForemanContext
* Global `window` object
* Other React Context
* localStorage and sessionStorage
* Routing

The following sections will outline

* The architecture around how we use each method
* Current opinions on best practices.

## Local component state

This includes anything that uses `useState` or `useReducer` hooks. Or, in class components, `this.state`. See the React docs for more info.

This is the best place for any data that is _used only locally by the component and its children_: for example
* input value for a controlled UI component
* current form values for form elements
* Other UI element states

Local state is also good for data that affects the component's direct children and can be easily passed down as props.

## Redux store

The Redux store is used to store data that needs to be shared across many components, especially ones that don't share a common ancestry. Another case is when one component can trigger an action that could impact the state of another component that isn't directly in its ancestry.

Currently API responses are also stored in Redux by the API middleware.

Don't default to using Redux when deciding where to put new data. Keep other options in mind as well, and see if local state or context would make more sense.

On the other hand, state management is not the only use for Redux. It can also be useful for logging what happened and in what order, or triggering actions such as API calls.

## ForemanContext

Data that doesn't often change but can impact many components across the application is stored in a special React Context object called ForemanContext. For more info on how to use it, see https://github.com/theforeman/foreman/blob/develop/developer_docs/foreman-context.asciidoc[Foreman Context].

This data includes:

* Current taxonomy (organization, location)
* Current user
* Pagination settings
* Foreman version
* UI Settings
* Documantation url


## Global `window` object

Because Foreman and plugins use both modern and legacy JS frameworks, Foreman has a unique way of storing some data on the global `window` object. (See `webpack/assets/javascripts/bundle.js`.) This `tfm` object includes

* A https://github.com/theforeman/foreman/blob/develop/webpack/assets/javascripts/react_app/components/componentRegistry.js[`componentRegistry`] that makes React components accessible for mounting on Rails ERB pages. For more info, see https://github.com/theforeman/foreman/blob/develop/developer_docs/plugins.asciidoc#mounting-components-into-erb[Mounting components into ERB]

* A method for https://github.com/theforeman/foreman/blob/develop/developer_docs/legacy-js.asciidoc[legacy JS] frameworks to access Foreman's Redux store
* Several other utilities and helpers written in jQuery and vanilla JavaScript

Should be used only if legacy code needs access to such data or methods. Avoid using it if possible.

Other than the `tfm` object, it is not advisable to store anything on the global `window` object.

## Other React Contexts

Consider the `ForemanModal` component, which is a composite React component which needs to pass data down to its subcomponents. However, this data is not used or needed by anything other than ForemanModal internals. For these specific use cases, it makes sense to use a React Context instance that is not connected to `ForemanContext`.

React Router also uses React Context under the hood.

## localStorage and sessionStorage

The browser's `sessionStorage` is currently used to store some user preferences; see `LayoutSessionStorage.js`, `HostSessionStorage.js`, and `NotificationDrawerSessionStorage.js`.

`sessionStorage` should only be used for volatile, temporary state-- i.e. things that won't impact the user if they get lost.

Currently the browser `localStorage` is not used by Foreman. It is recommended to use the Redux store instead.
(21-21/21)