Recoil 0.4.1 has been released with some performance optimizations and fixes focused on optimizing when React will re-render components based on Recoil state changes.
Components using selectors will no longer re-render if the selector evaluates to an equivalent value, based on reference equality.
Components previously rendered twice on initial render when not using React's Concurrent Mode.
When selectors have async dependencies that resolve, some environments of React that previously caused unnecessary re-renders no longer will.
Components did not always re-render properly when selectors changed async dependencies based on other dependencies.
We are pleased to announce the release of Recoil 0.4 with configurable selector caches, improved API for transactions with multiple atoms, and other optimizations and fixes.
The new cachePolicy_UNSTABLE property in selectors and selector families allows you to configure the caching behavior of a selector's internal cache. This property can be useful for reducing memory in applications that have a large number of selectors or selectors that have a large number of changing dependencies.
Below is an example of how you might use this new property:
const clockState =selector({ key:'clockState',get:({get})=>{const hour =get(hourState);const minute =get(minuteState);const second =get(secondState);// will re-run every secondreturn`${hour}:${minute}:${second}`;}, cachePolicy_UNSTABLE:{// Only store the most recent set of dependencies and their values eviction:'most-recent',},});
In the example above, clockState recalculates every second, adding a new set of dependency values to the internal cache, which may lead to a memory issue over time as the internal cache grows indefinitely. Using the most-recent eviction policy, the internal selector cache will only retain the most recent set of dependencies and their values, along with the actual selector value based on those dependencies, thus solving the memory issue.
Current eviction options are:
lru - evicts the least-recently-used value from the cache when the size exceeds maxSize.
most-recent - retains only the most recent value.
keep-all (default) - keeps all entries in the cache and does not evict.
NOTE:The default eviction policy (currently keep-all) may change in the future.
Introducing an improved API for updating multiple atoms together as a single transaction. The new useRecoilTransaction_UNSTABLE() hook is easier, more efficient, and safer than before. This new hook should eventually replace most uses of useRecoilCallback(), however this release is only an initial implementation with certain limitations that will be addressed in future releases.
Suppose we have two atoms, positionState and headingState, and we'd like to update them together as part of a single action, where the new value of positionState is a function of both the current value of positionState and headingState. You can accomplish this with a transaction, which must be a pure function without side-effects:
Then you can execute the transaction by just calling goForward(distance) in an event handler. This will update state based on the current values, not the state when the components rendered. You can also read the values of previous writes during a transaction. Because no other updates will be committed while the updater is executing, you will see a consistent store of state.
the previous approach using useRecoilCallback() might have looked like the following:
There is performance overhead for managing the full generality of snapshots.
There is more opportunity for bugs: The snapshot might be retained and used in the future. Since a snapshot contains the complete set of Recoil state, not just a changeset, that could accidentally rewind changes that occurred between creating and committing the snapshot.
Fix TypeScript typing for selectorFamily(), getCallback(), useGetRecoilValueInfo(), and Snapshot#getNodes() (#1060, #1116, #1123)
Allow mutable values in selectors (enabled via the dangerouslyAllowMutability selector option) to be used with waitFor*() helpers such as waitForAll() (#1074, #1096)
Fix onSet() handler to get the proper new value when an atom is reset or has an async default Promise that resolves (#1059, #1050, #738) (This is a slightly breaking change because the actual new value will be provided to the handler instead of a DefaultValue placeholder)
Fix support for multiple Atom Effects cleanup handlers (#1125)
Fix selector subscriptions when atoms with effects are initialized via a Snapshot (#1135, #1107)
Optimization for async selectors when dependencies resolve to cached values (#1037)
Welcome to Recoil version 0.1.1! This release has performance improvements and introduces several experimental features such as support for React Native, working with Snapshots outside of React, and atom effects for managing side-effects of atoms such as logging, synchronization with external stores, persistence, etc.
Today we are releasing Recoil 0.0.11. It contains bug fixes, new features, better performance, and experimental compatibility with Concurrent Mode. Thank you so much to everyone who contributed to this release!
Recoil 0.0.9 and 0.0.10 is being released with some bug fixes, TypeScript support, and a new API for Recoil Snapshots to observe, inspect, and manage global Recoil atom state. Thanks again to everyone who helped make this possible and stay tuned for more exciting developments coming soon!
Today we are releasing Recoil 0.0.8. It contains bug fixes and new features. Thanks so much to everyone who contributed to this release! It's been amazing to see so many people contribute.