- Fix potential unhandled promise rejection in
useRecoilCallback()
(#2075) - Add OSS support for GateKeeper feature toggling via
RecoilEnv.RECOIL_GKS_ENABLED
(#2078) - Fix resolving suspense of async selectors used with SSR (#2073, #1960)
- Fix SSR with some versions of React DOM used with Next.JS 13 (#2082, #2086)
Recoil 0.7.6
Expose flag to disable "duplicate atom key" checking / logging, as it was too noisy in environments such as NextJS or some dev environments using Fast Refresh. (#733, #2020, #2046)
- Import
RecoilEnv
from the recoil package, and setRecoilEnv.RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED = false
in code to disable the checking and logging. - We also support
process.env.RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED=false
in NodeJS environments such as NextJs - Caution: This disables all checks for duplicate atom keys including legitimate errors, so use with caution!
- Import
Workaround for React 18 environments with nested renderers that don't support
useSyncExternalStore()
. (#2001, #2010)
Recoil Sync 0.2
- Export
updateItems()
for thelisten
prop callback in<RecoilSync>
in addition toupdateItem()
andupdateAllKnownItems()
. (#2017, #2035) - Removing a parameter from the URL will reset atoms when using location
queryParams
with aparam
. This is a slight breaking change when an atom might sync with multiple URL params. (#1900, #1976) - Add a dev warning if an unstable
handlers
prop is detected for<RecoilURLSyncTransit>
. (#2044)
Refine 0.1.1
- Rename
boolean()
export tobool()
sinceboolean
is a reserved word (#1922, #1962, #1971) - Remove reference to
native
directory inpackage.json
to cleanup errors forreact-native
. (#1931) - Export
Path
class for custom checkers. (#1950, #1956) - Extend the failure message of
union()
andor()
with each type. (#1961)
Recoil 0.7.5
- Fix
useRecoilSnapshot()
with React's Fast Refresh during development (#1891) - Fix
useRecoilSnapshot()
andrecoil-sync
with changed browser behavior starting with Chrome v104 (#1943, #1936)
Recoil Sync 0.1
Initial open source release for the recoil-sync
NPM package! Recoil Sync provides an add-on library to help synchronize Recoil state with external systems. Simple asynchronous data queries can be implemented via selectors or useEffect()
, or atom effects can be used for bi-directional syncing of individual atoms. The recoil-sync
add-on package provides some additional functionality:
- Batching Atomic Transactions - Updates for multiple atoms can be batched together as a single transaction with the external system. This can be important if an atomic transaction is required for consistent state of related atoms.
- Abstract and Flexible - This API allows users to specify what atoms to sync separately from describing the mechanism of how to sync. This allows components to use atoms and sync with different systems in different environments without changing their implementation. For example, a component may use atoms that persist to the URL when used in a stand-alone tool while persisting to a custom user database when embedded in another tool.
- Validation and Backward Compatibility - When dealing with state from external sources it is important to validate the input. When state is persisted beyond the lifetime of an app it can also be important to consider backward compatibility of previous versions of state.
recoil-sync
andrefine
help provide this functionality. - Complex Mapping of Atoms to External Storage - There may not be a one-to-one mapping between atoms and external storage items. Atoms may migrate to use newer versions of items, may pull props from multiple items, just a piece of some compound state, or other complex mappings.
- Sync with React Hooks or Props - This library enables syncing atoms with React hooks or props that are not accessible from atom effects.
The recoil-sync
library also provides built-in implementations for external stores, such as syncing with the browser URL.
The basic idea is that a syncEffect()
can be added to each atom that you wish to sync, and then a <RecoilSync>
is added inside your <RecoilRoot>
to specify how to sync those atoms. You can use built-in stores such as <RecoilURLSyncJSON>
, make your own, or even sync different groups of atoms with different stores.
Example
URL Persistence
Here is a simple example syncing an atom with the browser URL:
const currentUserState = atom<number>({
key: 'CurrentUser',
default: 0,
effects: [
syncEffect({ refine: number() }),
],
});
Then, at the root of your application, simply include <RecoilURLSyncJSON>
to sync all of those tagged atoms with the URL
function MyApp() {
return (
<RecoilRoot>
<RecoilURLSyncJSON location={{part: 'queryParams'}}>
...
</RecoilURLSyncJSON>
</RecoilRoot>
)
}
That's it! Now this atom will initialize its state based on the URL during initial load, any state mutations will update the URL, and changes in the URL (such as the back button) will update the atom. See more examples in the Sync Effect, Store Implementation, and URL Persistence guides.
Refine 0.1
Initial open source release for the @recoiljs/refine
library for type refinement and input validation for Flow and TypeScript! To get started learning about Refine, check out the documentation on the core concepts of Utilities and Checkers.
The Recoil Sync library leverages Refine for type refinement, input validation, and upgrading types for backward compatibility. See the recoil-sync
docs for more details.
Why would I want to use Refine?
- Refine is useful when your code encounters
unknown
TypeScript type ormixed
Flow type values and you need to assert those values have a specific static type. - Refine provides an API for building type-refinement helper functions which can validate that an unknown value conforms to an expected type.
- Refine can validate input values and upgrade from previous versions.
Type Refinement Example
Coerce unknown types to a strongly typed variable. assertion()
will throw if the input doesn't match the expected type while coercion()
will return null
.
const myObjectChecker = object({
numberProperty: number(),
stringProperty: optional(string()),
arrayProperty: array(number()),
});
const myObjectAssertion = assertion(myObjectChecker);
const myObject: CheckerReturnType<myObjectChecker> = myObjectAssertion({
numberProperty: 123,
stringProperty: 'hello',
arrayProperty: [1, 2, 3],
});
Backward Compatible Example
Using match()
and asType()
you can upgrade from previous types to the latest version.
const myChecker: Checker<{str: string}> = match(
object({str: string()}),
asType(string(), str => ({str: str})),
asType(number(), num => ({str: String(num)})),
);
const obj1: {str: string} = coercion(myChecker({str: 'hello'}));
const obj2: {str: string} = coercion(myChecker('hello'));
const obj3: {str: string} = coercion(myChecker(123));
JSON Parser Example
Refine wraps JSON
to provide a built-in strongly typed parser.
const myParser = jsonParser(
array(object({num: number()}))
);
const result = myParser('[{"num": 1}, {"num": 2}]');
if (result != null) {
// we can now access values in num typesafe way
assert(result[0].num === 1);
} else {
// value failed to match parser spec
}
Recoil 0.7.4
Recoil Relay 0.1
Initial open source release for the recoil-relay
library for using GraphQL!
This library helps Recoil perform type safe and efficient queries using GraphQL with the Relay library. It provides selectors which can easily query with GraphQL. The queries are synced with the Recoil data-flow graph so downstream selectors can derive state from them, they can depend on upstream Recoil state, and they are automatically subscribed to any changes in the graph from Relay. Everything stays in sync automatically.
Example
A GraphQL query is as simple as defining a GraphQL selector:
const userNameQuery = graphQLSelector({
key: 'UserName',
environment: myEnvironment,
query: graphql`
query UserQuery($id: ID!) {
user(id: $id) {
name
}
}
`,
variables: ({get}) => ({id: get(currentIDAtom)}),
mapResponse: data => data.user?.name,
});
Then use it like any other Recoil selector:
function MyComponent() {
const userName = useRecoilValue(userNameQuery);
return <span>{userName}</span>;
}
Recoil 0.7.3
- Enable atoms and selectors to be used in family parameters (#1740)
- Add
parentStoreID_UNSTABLE
to atom effects for the parent Recoil store the atom instance was cloned from. This enables the pre-fetch pattern for GraphQL. (#1744) - Atom effects can initialize or set atoms to wrapped values (#1681)