Comparing version 0.1.2 to 0.1.3
@@ -61,23 +61,21 @@ 'use strict'; | ||
// State selector gets entire state if no selector was passed in | ||
var selectState = typeof selector === 'function' ? selector : getState; | ||
var stateSelector = typeof selector === 'function' ? selector : getState; | ||
var selectState = react.useCallback(stateSelector, dependencies); | ||
var selectStateRef = react.useRef(selectState); | ||
var dependenciesRef = react.useRef(dependencies); | ||
var _useReducer = react.useReducer(reducer, state, selectState), | ||
stateSlice = _useReducer[0], | ||
dispatch = _useReducer[1]; // Call new selector if no dependencies were passed in and selector has changed or dependencies were passed in and have changed | ||
dispatch = _useReducer[1]; // Call new selector if it has changed | ||
if (!dependencies && selectState !== selectStateRef.current || !shallowEqual(dependencies, dependenciesRef.current)) stateSlice = selectState(state); // Store in ref to enable updating without rerunning subscribe/unsubscribe | ||
if (selectState !== selectStateRef.current) stateSlice = selectState(state); // Store in ref to enable updating without rerunning subscribe/unsubscribe | ||
var stateSliceRef = react.useRef(stateSlice); // Update refs only after view has been updated | ||
react.useEffect(function () { | ||
return void (selectStateRef.current = selectState); | ||
}, [selectState]); | ||
react.useEffect(function () { | ||
return void (stateSliceRef.current = stateSlice); | ||
}, [stateSlice]); // Subscribe/unsubscribe to the store only on mount/unmount | ||
react.useLayoutEffect(function () { | ||
selectStateRef.current = selectState; | ||
stateSliceRef.current = stateSlice; | ||
}, [selectState, stateSlice]); // Subscribe/unsubscribe to the store only on mount/unmount | ||
react.useEffect(function () { | ||
react.useLayoutEffect(function () { | ||
return subscribe(function () { | ||
@@ -84,0 +82,0 @@ // Use the last selector passed to useStore to get current state slice |
@@ -1,2 +0,2 @@ | ||
import { useRef, useReducer, useEffect } from 'react'; | ||
import { useCallback, useRef, useReducer, useLayoutEffect } from 'react'; | ||
@@ -53,15 +53,17 @@ function shallowEqual(objA, objB) { | ||
// State selector gets entire state if no selector was passed in | ||
const selectState = typeof selector === 'function' ? selector : getState; | ||
const stateSelector = typeof selector === 'function' ? selector : getState; | ||
const selectState = useCallback(stateSelector, dependencies); | ||
const selectStateRef = useRef(selectState); | ||
const dependenciesRef = useRef(dependencies); | ||
let [stateSlice, dispatch] = useReducer(reducer, state, selectState); // Call new selector if no dependencies were passed in and selector has changed or dependencies were passed in and have changed | ||
let [stateSlice, dispatch] = useReducer(reducer, state, selectState); // Call new selector if it has changed | ||
if (!dependencies && selectState !== selectStateRef.current || !shallowEqual(dependencies, dependenciesRef.current)) stateSlice = selectState(state); // Store in ref to enable updating without rerunning subscribe/unsubscribe | ||
if (selectState !== selectStateRef.current) stateSlice = selectState(state); // Store in ref to enable updating without rerunning subscribe/unsubscribe | ||
const stateSliceRef = useRef(stateSlice); // Update refs only after view has been updated | ||
useEffect(() => void (selectStateRef.current = selectState), [selectState]); | ||
useEffect(() => void (stateSliceRef.current = stateSlice), [stateSlice]); // Subscribe/unsubscribe to the store only on mount/unmount | ||
useLayoutEffect(() => { | ||
selectStateRef.current = selectState; | ||
stateSliceRef.current = stateSlice; | ||
}, [selectState, stateSlice]); // Subscribe/unsubscribe to the store only on mount/unmount | ||
useEffect(() => { | ||
useLayoutEffect(() => { | ||
return subscribe(() => { | ||
@@ -68,0 +70,0 @@ // Use the last selector passed to useStore to get current state slice |
{ | ||
"name": "zustand", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "🐻 Bear necessities for state management in React", | ||
@@ -5,0 +5,0 @@ "main": "dist/cjs/index.js", |
@@ -197,1 +197,36 @@ <p align="center"> | ||
``` | ||
## Memoizing selectors, performance concerns, etc. (this is just additional info) | ||
Zustand tries to be as performant as possible while still being flexible but there are limitations. This is an attempt to breakdown how Zustand works to enable better estimations of the computational cost. | ||
A component is always subscribed to the part of the store that the latest selector returned: | ||
```js | ||
const foo = useStore(state => state.foo) // subscribed only to state.foo | ||
``` | ||
The selector is called first to return the selected state and again on ANY modification to the store, even updates made to a different part of the store: | ||
```js | ||
const [useStore, { setState }] = create(() => ({ foo: 'foo', bar: 'bar' })) | ||
function ComponentFoo() { | ||
return useStore(state => state.foo) | ||
} | ||
function ComponentBar() { | ||
return useStore(state => state.bar) | ||
} | ||
setState({ bar: 'new bar' }) // All selectors are called but only ComponentBar renders again | ||
``` | ||
Zustand calls selectors to compare the selected state (the return value of the selector) with the previous selected state. An update is dispatched to the component if the new selected state is different. The comparison is done with a shallow equality check. The component will then render again with the new selected state. Zustand has to check if the selector is new during the re render because it can be changed at any time. If the selector is new, it's called and the return value is used instead of the selected state that was dispatched. | ||
It's best to use selectors that are not computationally expensive as they are called on every update to the store. You can also skip the additional call to the selector by extracting the selector and passing it in as a static reference: | ||
```js | ||
const fooSelector = state => state.foo | ||
const foo = useStore(fooSelector) // fooSelector only called on initialization and store updates | ||
``` | ||
You can also pass an optional dependencies array to let Zustand know when the selector updates: | ||
```js | ||
// selector only called on initialization, store updates, and props.key updates | ||
const part = useStore(state => state[props.key], [props.key]) | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
17929
232