Commit Graph

175 Commits

Author SHA1 Message Date
Jacques Blom
f183edf746 Fix formatting 2020-06-30 21:44:34 +02:00
Jacques Blom
ea7f983f86 Fix formatting 2020-06-30 21:43:38 +02:00
Jacques Blom
3cb1ad8e6a Fix formatting 2020-06-30 21:39:13 +02:00
Jacques Blom
9e3f8e253a Fix formatting 2020-06-30 21:38:35 +02:00
Jacques Blom
fd51737712 Merge remote-tracking branch 'upstream/master' into react-native 2020-06-30 21:25:10 +02:00
generatedunixname89002005287564
b8139e724f html/js/recoil/oss/npm
Differential Revision: D22184490

fbshipit-source-id: 386abf6aab313a2675a19e94120e5655dc4f5ffe
2020-06-30 10:39:59 -07:00
Jacques Blom
be6be8d18c Merge remote-tracking branch 'upstream/master' into react-native 2020-06-26 08:39:41 +02:00
Douglas Armstrong
845e0e4217 Avoid re-renders when setting atom to same value (#386)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/386

When we set an atom to the same value (based on reference equality), or we have redundant resets, we can avoid updating the state, re-evaluating downstream nodes, or re-rendering subscribing components.

Reviewed By: habond

Differential Revision: D21964833

fbshipit-source-id: 132b6870d35a4f209bb8ecb9e81d59dd3866397e
2020-06-25 19:37:36 -07:00
Jacques Blom
e2d6b5bb62 Disable react/prop-types (#392)
Summary:
Disable the `react/prop-types` ESLint rule. It is causing CI to fail because of recently added components in tests. I don't think this rule is needed since we can statically type component props with Flow.
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/392

Reviewed By: aaronabramov

Differential Revision: D22218079

Pulled By: drarmstr

fbshipit-source-id: be7980a73c1265e40a28160d11a98b758ceabd7f
2020-06-25 13:51:11 -07:00
generatedunixname89002005287564
d4343b68eb html/js/recoil/oss/util
Differential Revision: D22184459

fbshipit-source-id: d3a6bb70504b5dc716cbb94667961890e653be7e
2020-06-25 08:57:29 -07:00
Douglas Armstrong
31e5972f22 Normalize handling updater form in setRecoilValue() (#401)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/401

Normalize updating recoil values with `setRecoilValue()` and handle the updater form of new values there instead of callers needing to use `valueFromValueOrUpdater()`

Reviewed By: davidmccabe

Differential Revision: D22224054

fbshipit-source-id: 61afdce501adf370a50bfd6d6ef0ddd332a4d1c6
2020-06-24 21:54:56 -07:00
Douglas Armstrong
ffa82e84a7 Avoid update during atom state initialization (#399)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/399

Avoid replacing state and initiating a render when initializing atom state with an effect.  No need to replace the state since we know there are no other subscribers to an atom if we are the ones initializing it on first use.

Reviewed By: davidmccabe

Differential Revision: D22223025

fbshipit-source-id: 1117be6f1e05fc2843da217ccd47aa29c65e67fb
2020-06-24 21:54:55 -07:00
Douglas Armstrong
0f372332e3 Scope Atoms by Store instead of State (#400)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/400

Scope Atom lifetime per `<RecoilRoot>` Store instead of TreeState per Snapshot.

Reviewed By: davidmccabe

Differential Revision: D22222735

fbshipit-source-id: f9912e265b1bc60028acb203669e8fec070eec07
2020-06-24 21:54:55 -07:00
Douglas Armstrong
1ce4077501 Atom Effects test for useGotoRecoilSnapshot() (#381)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/381

Add a test that going to a snapshot where an atom has not been initialized yet will cause it to be initialized again.  If we had cleanup handlers, then the cleanup handler should also be caused when going to the new snapshot.

Reviewed By: csantos42

Differential Revision: D22033254

fbshipit-source-id: 60a9e847a12f891e20b26d5d361ea9faa7d2d724
2020-06-24 19:01:55 -07:00
Douglas Armstrong
54f6f07d0f Report old value for onSet effect (#385)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/385

Report the old value as well as the new value from an Atom onSet effect.  The snapshot provided to this effect is for the new updated state, so it was not otherwise possible to get the old value.

Reviewed By: habond

Differential Revision: D22015656

fbshipit-source-id: 8d2d2c2b1e24cf1a3e598af5904eee68c3c5b1bf
2020-06-23 17:52:24 -07:00
Douglas Armstrong
21ef33b3ca Atom Effects onSet handler (#384)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/384

Add `onSet()` handler for Atom Effects.  This effect can be used to subscribe to atom changes for side-effects, such as synching with remote storage.

This handler is called after the React batch after the atom is set, but before the global `useRecoilTransactionObserver()`.  There currently isn't a way to cancel the `onSet()` handler, but we could add that if needed.

Example usage:
```
const myAtom = atom({
  key: 'MyAtom',
  default: undefined,

  effects: [({node, setSelf, onSet}) => {
    const storage = getStorage(node.key);

    // set a value for synchronous init that overrides default
    setSelf(storage.get(value));

    // Subscribe to storage updates
    storage.subscribe(value => setSelf(value));

    // Subscribe local changes to update storage
    onSet(value =>
      value === undefined
        ? storage.reset()
        : storage.set(value)
    );
  }],
});
```

Reviewed By: csantos42

Differential Revision: D21949700

fbshipit-source-id: b13929648efbc0b5c643cab254d3764445449a76
2020-06-23 17:52:23 -07:00
Douglas Armstrong
7855776c66 getDeps accessor for Snapshot (#382)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/382

Add a `getDeps_UNSTABLE()` accessor to `Snapshot` that takes a `RecoilValue` and returns an Iterable of current dependencies.

```
class Snapshot {
  ...
  getDeps_UNSTABLE: RecoilValue<T> => Iterable<RecoilValue<mixed>>,
};
```

Reviewed By: csantos42, maxijb

Differential Revision: D21926731

fbshipit-source-id: 318a7da152611f1137a621d6bfc65303bf64ec68
2020-06-23 17:52:23 -07:00
Douglas Armstrong
9562faea50 getNodes accessor for Snapshot (#383)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/383

Add `getNodes` accessor to the `Snapshot` interface

Provide the following interface to allow us to query sets of nodes based on our usage:

```
class Snapshot {
  ...
  getNodes_UNSTABLE: ({
    types?: Array<'atom' | 'selector'>,
    dirty?: boolean,
  }) => Iterable<RecoilValue<mixed>>;
}
```
* **`types`** - An array specifying the types of nodes to return including `atom` and `selector`.  The default is both.
* **`dirty`** - Only return dirty nodes.  Currently this only supports dirty atoms, but we should probably support dirty selectors for debug tools.

To keep scalability in mind, this interface returns an Iterable using a generator function so that we never produces temporary arrays containing all nodes.

NOTE: Feedback on the API for query parameters/options is welcome...  I'm not super keen on the current approach, which by default reports initialized nodes.  The set of initialized nodes in a snapshot my change as selectors are evaluated and discover more.  However, even if we report all globally registered nodes it's really the same problem as nodes can still be dynamically created during selector evaluation.

Reviewed By: csantos42, maxijb

Differential Revision: D21919550

fbshipit-source-id: 306ce337e28ed422b3e30e1fa9f20dc38abfb0fc
2020-06-23 17:52:23 -07:00
Douglas Armstrong
41aceb9c6f Recoil Effects for scopedAtom
Summary:
Add preliminary support for effects to scoped atoms.
Note that we pass the handlers through directly.  So, the typing is off since handlers are typed for `T` while the scope atom stores `T` or `ScopedAtomTaggedValue<T>`.    We can't marshal the underlying type like we do now with validators because we don't want to hard-code the logic for how validation is done when initializing the value.

One difference is that the persisted initialized value is only set for the current scope.  If the user changes the scope then the default value is used.

Current plan is to hack in support for `ScopedAtomTaggedValue` in the URL Persistence library and ignore the Flow errors for now.  Eventually we hope to properly implemented a scoped atom that doesn't try to package all values in a single atom as well as provides some built-in support for backward-compatibility of changing the scope rules.  But, let's go with a gradual migration.

Reviewed By: csantos42

Differential Revision: D21919547

fbshipit-source-id: c7b745066c7a7b491fa9feb2aa9def215a4855a0
2020-06-23 17:52:23 -07:00
Douglas Armstrong
fb029cfe53 Recoil Atom Effects (#380)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/380

Introduce the concept of effects for Recoil Atoms based on [this proposal](https://fb.quip.com/bauvAeBEX5Ee).  This is a similar concept of using React `useEffect()` for side-effects on components, only for atoms.  It can be challenging to use `useEffect()` with Recoil atoms because the Recoil hierarchy is orthogonal to the React component hierarchy, and we have to worry about lifetime and singleton patterns.  Recoil Atom Effects are an array of callbacks which will be called the first time the atom is used with a `<RecoilRoot>`, so they are always part of a React context.  Atom Effects can be used for:

* Synchronization with browser URI history
* Persistence to local storage
* Bi-directional synchronization with remote asynchronous state
* Maintaining state history
* other side-effects such as "set on get"
* &c.

# Proposed Atom Effects

```
type AtomOptions<T> = {
  key: string,
  default: T | RecoilValue<T> | Promise<T>,
  ...

  effects: $ReadOnlyArray<AtomEffect<T>>,
};

// Effect is called the first time node is used with a <RecoilRoot>
type AtomEffect<T> = ({
  node: RecoilState<T>,
  trigger: 'get' | 'set',

  // Can call either synchronously to initialize value or async to change it later
  setSelf: (T | DefaultValue | (T => T | DefaultValue)) => void,
  resetSelf: () => void,
  getSnapshot: () => Snapshot,

  // Subscribe to events
  // Called when React batch ends, but before global RecoilTransactionObserver
  onSet: ((newValue: T | DefaultValue, oldValue: T | DefaultValue) => void) => void,
}) => void | () => void; // Return optional cleanup handler
```

### Current Diff
This diff introduces a subset of the atom effect functionality:

```
// Effect is called the first time node is used with a <RecoilRoot>
type AtomEffect<T> = ({
  node: RecoilState<T>,
  trigger: 'get' | 'set',

  setSelf: (T | DefaultValue | (T => T | DefaultValue)) => void,
  resetSelf: () => void,
  getSnapshot: () => Snapshot,
}) => void;
```

### Example Usage
Example use of an atom as a local cache of state that can be bi-directionally synchronized with remote async storage.
```
const myAtom = atom({
  key: 'MyAtom',
  default: undefined,

  effects: [({node, setSelf, onSet}) => {
    const storage = getStorage(node.key);

    // set a value for synchronous init that overrides default
    setSelf(storage.get(value));

    // Subscribe to storage updates
    storage.subscribe(value => setSelf(value));

    // Subscribe local changes to update storage
    onSet(value =>
      value === undefined
        ? storage.reset()
        : storage.set(value)
    );

    // Subscribe to cleanup
    onCleanup(() => storage.unsubscribe());
  }],
});
```

Reviewed By: csantos42

Differential Revision: D21919545

fbshipit-source-id: b500602d7ca91972d28790ee3f895517fdc52320
2020-06-23 17:52:22 -07:00
Jacques Blom
48e0d86b38 Merge remote-tracking branch 'upstream/master' into react-native 2020-06-23 16:06:52 +02:00
Dmitry Komalov
765a56d160 Add flow to GitHub actions (#338)
Summary:
Add flow to GitHub actions

Also gkx is needed to be resolved correctly so flow step would pass green
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/338

Reviewed By: bezi

Differential Revision: D22176735

Pulled By: aaronabramov

fbshipit-source-id: d91861485223dfdbb0258f8b6f6153600910e84f
2020-06-23 06:15:37 -07:00
Douglas Armstrong
b753027cc2 Add selectorFamily test with array parameter (#363)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/363

Add unit test for `selectorFamily()` with an array parameter

Reviewed By: davidmccabe

Differential Revision: D22133734

fbshipit-source-id: 010f650536c96efde17991e18e3280151a22cd3a
2020-06-22 20:10:44 -07:00
Douglas Armstrong
fbf32fc165 Add unit test for Iterable serialization (#362)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/362

Organize `stableStringify()` unit tests and add test for Iterables

Reviewed By: davidmccabe

Differential Revision: D22133358

fbshipit-source-id: 7281cb8fb29722ce9458f81faf9cd9ddb22ba960
2020-06-22 20:10:43 -07:00
Douglas Armstrong
f3e3a18cfe Cleanup warnings (#360)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/360

Cleanup some warnings such as order requires and returned promises for testing

Reviewed By: davidmccabe

Differential Revision: D22129498

fbshipit-source-id: 2e78ec0cfbcad72734e1aa142e63cb3f47e7c629
2020-06-22 20:10:42 -07:00
Douglas Armstrong
c5e5a020dd Only deep freeze in development (#361)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/361

Only deep freeze stored values during development

Reviewed By: davidmccabe

Differential Revision: D22129190

fbshipit-source-id: c7274acf8ee1dd605d3932fc9a90f4badc52230b
2020-06-22 18:39:37 -07:00
Douglas Armstrong
598bde60da <Link> component (#379)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/379

Provide new Link components for Recoil URL persistence based on [this proposal](https://fb.quip.com/UwKaAGjK0L0E).  There are two variants:

# `<LinkToRecoilSnapshot>`
A Link component based on the provided `uriFromSnapshot` mapping of a URI from a Recoil Snapshot.

The Link element renders an anchor element.  But instead of an href, use a `snapshot` property.  When clicked, the Link element updates the current state to the snapshot without loading a new document.

The href property of the anchor will set using `uriFromSnapshot`.  This allows users to copy the link, choose to open in a new tab, &c.

If an `onClick` handler is provided, it is called before the state transition and may call preventDefault on the event to stop the state transition.

# `<LinkToRecoilStateChange>`
A Link component based on the provided `uriFromSnapshot` mapping of a URI from a Recoil Snapshot.

The Link element renders an anchor element.  But instead of an href, use a `stateChange` property.  When clicked, the Link element updates the current state based on the `stateChange` callback without loading a new document. `stateChange` is a function which takes a `MutableSnapshot` that can be used to read the current state and set or update any changes.

The href property of the anchor will set using `uriFromSnapshot`.  This allows users to copy the link, choose to open in a new tab, &c.

If an `onClick` handler is provided, it is called before the state transition and may call preventDefault on the event to stop the state transition.

*Note that, because the link renders the href based on the current state snapshot it is re-rendered whenever any state change is made.  Keep the performance implications of this in mind.*

Reviewed By: habond

Differential Revision: D21784015

fbshipit-source-id: 9cd6ff2a9fa92bb094175472416a639a2a4f8142
2020-06-22 18:39:37 -07:00
Dmitry Komalov
cd69130101 Fixes lint errors (#368)
Summary:
The only problem of eslint is missing fb-www package. It might be resolved once the corresponding package will be published by adding it to devDeps. Pls let me know if something goes against internal fb build strategy
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/368

Reviewed By: bezi

Differential Revision: D22146011

Pulled By: aaronabramov

fbshipit-source-id: f6d2333b11d1e9f5026e302f7d8c011d8cfa2c1f
2020-06-22 13:06:45 -07:00
Douglas Armstrong
e18d972000 Drop deprecated support for legacy parameterizedAtom support (#313)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/313

Drop support for loading URLs with persisted values containing legacy parameterizedAtom values.  This was deprecated 3 months ago, past our support agreement for stale links.

Reviewed By: csantos42

Differential Revision: D21849217

fbshipit-source-id: 62241c2d205805d56571cfef7390ef7103f8c251
2020-06-18 19:19:37 -07:00
Douglas Armstrong
3661fe6b3b 0.0.10 release (#356)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/356

0.0.10 release with API export fix

Reviewed By: davidmccabe

Differential Revision: D22120348

fbshipit-source-id: 1fb847041d87c92447c4b900e3b3b950422f13c1
2020-06-18 15:21:31 -07:00
Douglas Armstrong
896edf775a useRecoilSnapshotAndSubscribe() -> useRecoilSnapshot()
Summary: useRecoilSnapshotAndSubscribe() -> useRecoilSnapshot()

Reviewed By: davidmccabe

Differential Revision: D22120800

fbshipit-source-id: 4d3871f325d2b6afe8ee5421abcbbf908c59f8bb
2020-06-18 15:21:30 -07:00
Jared Palmer
7d73580f09 Export new snapshot hooks (#352)
Summary:
Add `useRecoilSnapshotAndSubscribe` and `useGotoRecoilSnapshot` to exports.

Fixes https://github.com/facebookexperimental/Recoil/issues/351
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/352

Reviewed By: bezi, davidmccabe

Differential Revision: D22118412

Pulled By: drarmstr

fbshipit-source-id: 3f5bd6d6cd64a682a83d2aa4c49cf5436073d3e8
2020-06-18 15:21:30 -07:00
Douglas Armstrong
2417b23d16 Fix OSS build by using gkx() stub for Snapshots (#345)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/345

Fix OSS build by using gkx() stub for Snapshots

Reviewed By: csantos42

Differential Revision: D22110849

fbshipit-source-id: 5fe40759e6ea0c66e3c3dd0782af0055ff581a4f
2020-06-17 23:33:04 -07:00
Douglas Armstrong
f401f31d85 0.0.9 Release: package and changelog (#337)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/337

Update `package.json` and `CHANGELOG.md` for `0.0.9` release.

Reviewed By: csantos42

Differential Revision: D22070824

fbshipit-source-id: 0b2218461eb31f38e585d128fb967c265d916168
2020-06-17 20:25:48 -07:00
Christian Santos
f0830b58d5 TypeScript types for Snapshots (#339)
Summary:
adds TypeScript types for `Snapshot` and associated changes:

- update `useRecoilCallback()` signature
- update `<RecoilRoot />`'s props
- new `useRecoilTransactionObserver()`
- new `useGotoRecoilSnapshot()`
- new `useRecoilSnapshotAndSubscribe()`
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/339

Reviewed By: drarmstr

Differential Revision: D22084915

Pulled By: csantos42

fbshipit-source-id: b829e57d781ca9f3c8753746f82b3fd9815c7cd3
2020-06-17 19:06:41 -07:00
Jacques Blom
8589b6203c Rebuild 2020-06-17 22:21:22 +02:00
Jacques Blom
09ab13f471 Setup react batching in tests 2020-06-17 21:34:08 +02:00
Jacques Blom
155d01729a Remove ReactDOM batch calls 2020-06-17 21:33:45 +02:00
Jacques Blom
148ec8d6ad Merge branch 'master' into react-native 2020-06-17 21:17:21 +02:00
Douglas Armstrong
3f1d11433d Add test for useRecoilCallback() state consistency (#333)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/333

Add tests to confirm that `useRecoilCallback()` receives a snapshot that is consistent with the stable and committed state that was in place at the begining of the current transaction.  However, the updater form of setting atoms gets a parameter with the previous value that represents previous state changes in that same transaction.

Reviewed By: aaronabramov

Differential Revision: D22062359

fbshipit-source-id: 1ec076256a0056100e2c64c04c3bc304e9461bd9
2020-06-16 19:48:58 -07:00
Aaron Abramov
8be343c531 Fix test and flow in master (#332)
Summary:
`gkx` module was added to the codebase and it doesn't exist outside www.
adding all necessary mocks to fix the build
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/332

Reviewed By: drarmstr

Differential Revision: D22062299

Pulled By: aaronabramov

fbshipit-source-id: e61dbca322321e4a79d01b3c6d5ae954053c2bfb
2020-06-16 15:26:07 -07:00
strangeforloop
be00495bc3 initial set up for eslint (#329)
Summary: Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/329

Reviewed By: bezi

Differential Revision: D22049293

Pulled By: aaronabramov

fbshipit-source-id: 79b697c893457e3151cd63a0b555ce5f093906af
2020-06-16 12:10:36 -07:00
abheist
c6ebc2c26b Readme updated (#189)
Summary:
Documentation:
📃 Added licence badge in README.md
📃 Added the installation and contributing guide in README

This is my first ever contribution to open source. It is quite small, but it'll get me started. 🙌
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/189

Reviewed By: aaronabramov

Differential Revision: D21861635

Pulled By: davidmccabe

fbshipit-source-id: 5197f487cf40c1e3688c929d044e517b7d6e25b6
2020-06-15 21:43:27 -07:00
Douglas Armstrong
0b6061c5d6 <RecoilRoot> initializeState prop (#312)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/312

Deprecate the old `initializeState_DEPRECATED` prop in `<RecoilRoot>` and add a new `initializeSnapshot` with the following signature:

```
  initializeState: MutableSnapshot => void,
```
Alternative signatures could have been:
```
  initializeState: Snapshot => Snapshot,
```
But this is more consistent with `Snapshot.map()` and we don't want to encourage long-term `Snapshot` storage.  We might also consider
```
  initialSnapshot: Snapshot,
```
But, this would require us to expose an API for the user to construct a fresh `Snapshot`, which we want to avoid for now. Use of that pattern of building a `Snapshot` from scratch a lot would miss opportunities to optimize snapshots to encode deltas of a chained history instead of duplicate full state when cloning.

The new API uses the `MutableSnapshot` to be consistent with `Snapshot` usage elsewhere in the API.  In practice, it's mostly the same as the previous `initializeState` prop when using the `set` method.  However, the `setUnvalidatedAtomValues` is not provided.  This functionality will instead be provided via [atom effects](https://fb.quip.com/bauvAeBEX5Ee), so it is more granular, composable, and co-located.  We can remove the deprecated version when we finish migration to the new URL persistence library.

One remaining optimization would be that the state is stored using `useRef()`, which doesn't use a callback for the initial default parameter that `useState()` does.  This means it is recomputing the state initialization each time the `<RecoilRoot>` is re-rendered.  The re-computation is ignored, but is wasted effort. (The old implementation appears to have a bug that rendering this again, while ignoring the re-computed state, may cause components that subscribe to initialized atoms to also re-render; though I suppose we're re-rendering the root anyway at that point)

Reviewed By: csantos42

Differential Revision: D21856852

fbshipit-source-id: eecd999bc0c3f31670c6eb5ac51d2d38a3e77891
2020-06-15 20:38:49 -07:00
Douglas Armstrong
2cb3b85055 useRecoilSnapshotAndSubscribe() hook (#311)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/311

Add `useRecoilSnapshotAndSubscribe()` hook.  This was originally part of [this proposal](https://fb.quip.com/UwKaAGjK0L0E).  We removed it thinking that `useRecoilTransactionObserver()` would be sufficient.  However, we need this hook to be able to synchronously get a snapshot during render in order to support server-side rendering.  We could drop `useRecoilTransactionObserver()` and only use this hook.  However, that one has a more convenient API for persistence/debug tools.  So, keep both as a convenience at the expense of a larger API surface area.

```
declare function useRecoilSnapshotAndSubscribe(): Snapshot;
```

Label hook as `useRecoilSnapshotAndSubscribe()` to make more obvious to the user that using this hook will also subscribe that component to all transactions.  It should be used sparingly.

In the future, we plan to add a parameter to `useRecoilSnapshotAndSubscribe()` and `useRecoilTransactionObserver()` to control debouncing or condition when to update the subscription.

Reviewed By: csantos42

Differential Revision: D21783137

fbshipit-source-id: 51096db1fcd50b59017a9b2ef440f1d9418cbbb9
2020-06-15 20:38:49 -07:00
Douglas Armstrong
de5b0523c2 useGotoRecoilSnapshot() hook (#310)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/310

Add `useGotoRecoilSnapshot()` hook as per [this proposal](https://fb.quip.com/UwKaAGjK0L0E)

```
function useGotoRecoilSnapshot(): Snapshot => void
```

Change current store to use the state in the provided `Snapshot`.  If any atom values changed, then fire subscriptions to update any currently subscribed components for only those updated atoms.

Note that `nodeToComponentSubscriptions` is maintained as the state is updated to match the `Snapshot`.  This won't be necessary to explicitly copy when that state is migrated from the `TreeState` to the `StoreState` for CM.

I think the old implementation had a bug where it would only change atom values that were explicitly "updated" in the snapshot, making it not really a snapshot but a queue of state changes.

Next we will migrate `<Link>` and remove the old deprecated version.

Reviewed By: habond, csantos42

Differential Revision: D21739680

fbshipit-source-id: 5da9b3b13a10af208045413e5a73c65b55bb8c2b
2020-06-15 20:38:48 -07:00
Douglas Armstrong
ddae6de902 useRecoilTransactionObserver hook (#309)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/309

Initial `useRecoilTransactionObserver()` hook based on [this proposal](https://fb.quip.com/UwKaAGjK0L0E)

```
function useRecoilTransactionObserver(
  ({
    snapshot: Snapshot,
    previousSnapshot: Snapshot,
  }) => void,
): void
```

This adds support for selectors that the old `useTransactionObservation()` hook doesn't.  It contains both `snapshot` and `previousSnapshot`, but the snapshots don't yet have a mechanism for iterating the set of atoms/selectors or dirty atoms.  So, keep the old hook for now and migrate users over as we add that functionality.

Also mark `useTransactionSubscription()` as DEPRECATED, we will need to migrate the prototype dev tools support over.

Reviewed By: habond, csantos42

Differential Revision: D21737837

fbshipit-source-id: a9dd99431609e753898edfcb604b38a3508fda52
2020-06-15 20:38:48 -07:00
Douglas Armstrong
e61871bd04 Add Snapshot asyncMap (#258)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/258

add `Snapshot` `asyncMap()` as an async variant of `map()` which allows for easier use of the simpler `getPromise()` vs `getLoadable()` accessor based on [this proposal](https://fb.quip.com/UwKaAGjK0L0E)

```
class Snapshot {
  ...
  map: (MutableSnapshot => void) => Snapshot;
  asyncMap: (MutableSnapshot => Promise<void>) => Promise<Snapshot>;
};
```

Reviewed By: davidmccabe

Differential Revision: D21706818

fbshipit-source-id: 132a848c1434a954bcd04e449c4c9a32311014aa
2020-06-15 20:38:48 -07:00
Douglas Armstrong
687193fcf6 Add Snapshot map (#259)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/259

Add ability to map immutable `Snapshot` with an update function to a new immutable `Snapshot` based on [this proposal](https://fb.quip.com/UwKaAGjK0L0E):

```
class Snapshot {
  ...
  map: (MutableSnapshot => void) => Snapshot;
};

class MutableSnapshot extends Snapshot {
  set: <T>(RecoilState<T>, T | DefaultValue | (T) => T | DefaultValue) => void;
  reset: <T>(RecoilState<T>) => void;
};
```

Reviewed By: davidmccabe

Differential Revision: D21706649

fbshipit-source-id: 1214bea324eb6d208ea19298de7c8a11c135fb3a
2020-06-15 20:38:47 -07:00
Douglas Armstrong
a6452ccc3e Update useRecoilCallback() to use Snapshot (#260)
Summary:
Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/260

Update `useRecoilCallback()` to use the `Snapshot` interface based on [this proposal](https://fb.quip.com/UwKaAGjK0L0E)

```
type CallbackInterface = {
  set: <T>(RecoilState<T>, T | DefaultValue | (T) => T | DefaultValue) => void,
  reset: <T>(RecoilState<T>) => void,
  snapshot: Snapshot,
  gotoSnapsot: Snapshot => void  // TODO
};

function useRecoilCallback(
  CallbackInterface => Args => Return,
): Args => Return
```

Notice that this has a similar interface as the current `useRecoilCallback()` API (with the wrapped callback RFC proposal), but moves the snapshot accessors to use a `Snapshot` object instead.  The `set`/`reset` callbacks affect the current state, not the snapshot.

NOTE: This is a breaking change, but we are still on version `0.0.x` for semantic versioning.

Reviewed By: davidmccabe

Differential Revision: D21705808

fbshipit-source-id: 623f5bfdfed9e4c7e9abe8173b07bf02bd492253
2020-06-15 20:38:47 -07:00