Package Exports
- react-stately
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (react-stately) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
react-stately
A library for simple management of shared React state
Introduction
Stately is a simple, easy-to-use state management library for React relying on the render props pattern. It has components for managing both local state and global state in a React component tree. When managing global state, it scopes state access and mutations under a Ramda lens. This helps you be declarative about which parts of the global state your components rely upon.
Resources
Managing Local State
You can manage local state in Stately using the Stately
component. First,
set the initial state with a prop on the Stately
component, which is
equivalent to setting the state in the constructor of a React stateful class
component. Then, provide the Stately
component with a render prop, which
gives you access to the local state and the setState
method, which work
exactly the same as this.state
and this.setState
in a React stateful class
component.
<Stately
initialState={{ isAsleep: true }}
render={(state, setState) => (
<button onClick={() => setState({ isAsleep: false })}>
{state.isAsleep ? 'zzz... (click to wake me)' : 'good morning'}
</button>
)}
/>
This example renders a button that initially renders a sleeping message. When
clicked, the button displays a "good morning" message. To manage the state of
whether the button is "asleep," we use an isAsleep
boolean value, which starts
with an initial value of true
in the initialState. When the user clicks the
button, we use the setState method to update the isAsleep
value to false
.
Since we use this state to control which message is displayed inside the button,
clicking the button will change the displayed message.
Note that you may provide a function to setState
to base it off the previous
state, which works exactly as it does in React. If you needed to, you could
provide a callback as the second argument to setState
as well, which is also
the same as in React. Generally, you should assume any setState
in Stately
works similarly to React's this.setState
method. There is one caveat to this
when managing global state, which is explained below.
Managing Global State
Stately also supports managing global state. This uses the Provider pattern to
share a Stately
component with the entire React tree. You must provide the
StatelyProvider
with an initial state, which will be passed down to the
Stately
component it manages. Then, anywhere in the tree below the
StatelyProvider
, you can use a ConnectedStately
component to access the
global state. This takes a render prop which is similar to the Stately
component's render prop. However, when using ConnectedStately
, you must
provide a Ramda lens to scope your access to the global state. This is to help
you declare which part of the global state this specific ConnectedStately
is
trying to manage. See the Resources section of this document for some links to
help you learn about Ramda lenses, or check out the Ramda documentation.
<StatelyProvider
initialState={{ auth: { isLoggedIn: false }, counter: { value: 0 } }}
>
<ConnectedStately
lens={R.lensProp('counter')}
render={(state, setState) => (
<button
onClick={() => {
setState(({ value: oldValue }) => ({ value: oldValue + 1 }))
}}
>
Increment the value
</button>
)}
/>
<ConnectedStately
lens={R.lensProp('authentication')}
render={(state, setState) => (
<div>
<button
onClick={() => {
setState(({ isLoggedIn: wasLoggedIn }) => ({
isLoggedIn: !wasLoggedIn
}))
}}
>
{state.isLoggedIn ? 'Log out' : 'Log in'}
</button>
<ConnectedStately
lens={R.lensProp('counter')}
render={state => (
<span>We can access the counter here too: {state.value}</span>
)}
/>
</div>
)}
/>
</StatelyProvider>
In the above example, we have a global state with some authentication
information and a counter value. It works very similarly to the local state
example, except we provide the initial state in the provider and access it
using the ConnectedStately
component. We have a counter button at the top
which accesses the global state under the counter
key to increment the value
when the button is pressed. Below that, there's an authentication button which
is scoped under the global auth
key. This allows you to click to log in and
out, changing the text of the button. But also, inside the component managing
the authentication button, we also display the value of the counter using a
nested ConnectedStately
component.
If you need to access multiple parts of the global state, you should use nested
ConnectedStately
components with different Ramda lenses, one for each scope
in the global state to which you need access. Note that we do this above to
access the counter value inside the authentication section. If you find
yourself doing this a lot, maybe it's important to re-evaluate the structure of
the global state to place similar information together. This should lead to
cleaner global state management code, which is one of the goals of Stately.
Notice how using lenses allows us to separate the concerns of authentication and the counter. This helps you to build global state management solutions that play together nicely. There's no guessing about which part of the state each piece of the application manages. Even when we do things like accessing various parts of the state in the same piece of the application, we still get the same declarative nature. This is one of the major strong points of using Stately over a normal Javascript global.
License
Copyright 2018 Christian Howe
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.