diff --git a/docs/api/container.md b/docs/api/container.md index 1a6f2f1..badbbca 100644 --- a/docs/api/container.md +++ b/docs/api/container.md @@ -52,3 +52,68 @@ const UserTodos = ({ initialTodos }) => ( ); ``` + +### createDynamicContainer + +```js +createDynamicContainer(config); +``` + +##### Arguments + +1. `config` _(Object)_: containing one or more of the following keys: + + - `displayName` _(string)_: used by React to better identify a component. Defaults to `DynamicContainer` + + - `matcher` _(Function)_: a function returning `true` for stores that need to be contained. Required. + + - `onStoreInit` _(Function)_: an action that will be triggered on each store initialisation. If you define multiple containers sharing the same scope, this action will still only be run **once** by one of the container components, so ensure they receive the same props. + + - `onStoreUpdate` _(Function)_: an action that will be triggered when a store state changes. + + - `onStoreCleanup` _(Function)_: an action that will be triggered after a store is no longer listened to (usually after container unmounts). Useful in case you want to clean up side effects like event listeners or timers. As with `onStoreInit`, if you define multiple containers this action will trigger by the **last one** unmounting. + + - `onPropsUpdate` _(Function)_: an action that will be triggered when props on a container change. + +##### Returns + +_(Component)_: this React component allows you to change the behaviour of child components by providing different Store instances or custom props to actions. It accept the following props: + +- `isGlobal` _(bool)_: by default, Container defines a local store instance. This prop will allow child components to get data from the global store's registry instance instead + +- `scope` _(string)_: this option will allow creating multiple global instances of the same store. Those instances will be automatically cleaned once all the containers pointing to the scoped version are removed from the tree. Changing a Container `scope` will: create a new Store instance, make `onInit` action run again and all child components will get the data from it. + +- `...props` _(any)_: any additional prop set on the Container component is made available in the actions of child components + +##### Example + +Let's create a Container that contains and initializes all theme-related stores, for instance. + +```js +import { createDynamicContainer } from 'react-sweet-state'; + +// Assume we have a ColorsStore and a FontSizesStore with `tags: ['theme']` + +const ThemeContainer = createDynamicContainer({ + matcher: (Store) => Store.tags.includes('theme'), + onStoreInit: + () => + ({ setState, getState }, { initialTheme }) => { + const state = getState(); + if ('colors' in state) { + // refining to colors store + setState({ colors: initialTheme.colors }); + } + if ('fontSizes' in state) { + // refining to sizes store + setState({ sizes: initialTheme.sizes }); + } + }, +}); + +const UserTheme = ({ colors, sizes }) => ( + + + +); +``` diff --git a/examples/advanced-scoped-dynamic/components/color.tsx b/examples/advanced-scoped-dynamic/components/color.tsx new file mode 100644 index 0000000..0c8ef02 --- /dev/null +++ b/examples/advanced-scoped-dynamic/components/color.tsx @@ -0,0 +1,29 @@ +import { + createStore, + createHook, + type StoreActionApi, +} from 'react-sweet-state'; + +type State = { + color: string; +}; + +const initialState: State = { + color: 'white', +}; + +const actions = { + set: + (color: string) => + ({ setState }: StoreActionApi) => { + setState({ color }); + }, +}; + +const Store = createStore({ + initialState, + actions, + tags: ['theme'], +}); + +export const useColor = createHook(Store); diff --git a/examples/advanced-scoped-dynamic/components/width.tsx b/examples/advanced-scoped-dynamic/components/width.tsx new file mode 100644 index 0000000..3fa1135 --- /dev/null +++ b/examples/advanced-scoped-dynamic/components/width.tsx @@ -0,0 +1,29 @@ +import { + createStore, + createHook, + type StoreActionApi, +} from 'react-sweet-state'; + +type State = { + width: number; +}; + +const initialState: State = { + width: 200, +}; + +const actions = { + set: + (width: number) => + ({ setState }: StoreActionApi) => { + setState({ width }); + }, +}; + +const Store = createStore({ + initialState, + actions, + tags: ['theme'], +}); + +export const useWidth = createHook(Store); diff --git a/examples/basic-flow/index.html b/examples/advanced-scoped-dynamic/index.html similarity index 85% rename from examples/basic-flow/index.html rename to examples/advanced-scoped-dynamic/index.html index 7738059..f012687 100644 --- a/examples/basic-flow/index.html +++ b/examples/advanced-scoped-dynamic/index.html @@ -2,7 +2,7 @@ - Basic example with Flow + Advanced dynamic scoped example