Recoil: React Native Support

Created on 18 May 2020  路  14Comments  路  Source: facebookexperimental/Recoil

The repo currently uses ReactDOM in order to communicate with the DOM.

When will we be able to use Recoil within React Native?

enhancement infra / build

Most helpful comment

Neat, I didn't update the index.js file that's why! Recoil is surely great, can't wait to officially use it with RN.

Thanks for the tip man!

For anyone willing to use it before the PR gets merged, my fork is public and the package built:

npm install eveningkid/Recoil#react-native --save

All 14 comments

For clarity Recoil is using ReactDOM to use ReactDOM.unstable_batchedUpdates, which communicates with the timers available in a browser as opposed to the DOM itself.

https://github.com/facebookexperimental/Recoil/blob/c38012d92a292a4a867163cf7b14cfb3debddf01/src/hooks/Recoil_Hooks.js#L482

I don't know if ReactNative has a similar way of doing scheduling.

It does:

import {unstable_batchedUpdates} from 'react-native'

MobX also makes use of batched updates, and allows you to specify the batch function. You can either import mobx-react-lite/batchingForReactDom or mobx-react-lite/batchingForReactNative, or call observerBatching(customBatchingFn) with your custom function. Docs and MobX PR here for context.

We could go for the same approach, or could export a bundle for React DOM and one for React Native. The latter might be more convenient for library users, because they won't have to worry about specifying a batching function.

I'd be interested to hear what the maintainers think. I'm happy to put up PRs for both approaches.

Hey @jacques-blom, the separate bundle approach sounds convenient, but does it scale to additional React renderers? Each one has its own API for batching, correct? If somebody was using both React DOM and React ART, for example, in the same project, we wouldn't want them to need two copies of Recoil in their own bundle. And we wouldn't want them to have to wait for us to update our build system before using another renderer.

That said, I don't want to have to pass in a batching function :) Maybe we should just make it easy for the common case like you suggested.

Anyway, would love to have a PR on this, thanks for offering to help.

I can look at the rollup config for this within the next day or two and send a PR for the common case proposed in this thread

Rollup aliases/externals for stubbing out react-dom and react-native depending on build context

https://github.com/mobxjs/mobx-react/blob/1e8d6b5009377badcc5ab11ef8a605a071bb60e3/build-rollup.js#L29-L49

That looks great, @dustinsoftware. I've gone for a similar approach in https://github.com/facebookexperimental/Recoil/pull/114. The main difference is that RN-specific code can be placed in .native.js files, and they'll be used over .js files in the native build. Let me know what you think. :)

Thanks everybody for contributing on this. I really don't feel qualified to choose between these approaches. Maybe someone else with experience in this area can weigh in? Here are the things I would want, am I missing any other considerations?

1) Users don't have to think about this.
2) Users' bundles only include the code for their platform.
3) Users don't have to wait on us to use other renderers.

I wonder if in the future this could be part of the core React API to avoid each React library having to solve this same problem. Imagining something like this:

function RecoilRoot({children}) {
  const batchedUpdate = React.useUnstableBatchedUpdate();
  const storeRef = useRef(initiaRecoilStore(batchedUpdate));

  return (
    <AppContext.Provider value={storeRef}>
      {children}
    </AppContext.Provider>
  );
}

Any information on progress, or should one use pr #114 while waiting?

Any information on progress, or should one use pr #114 while waiting?

Well, even when using his PR for now it does not work yet.

RN support would really be appreciated @jacques-blom! :)

Any information on progress, or should one use pr #114 while waiting?

Well, even when using his PR for now it does not work yet.

RN support would really be appreciated @jacques-blom! :)

I'm currently using this as we speak. And it's super fun. Recoil allows me to import my global state and portalize it anywhere.

To use it in React Native I am using a forked branch of @jacques-blom react-native branch and my index.js for my recoil node_module looks like this:

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @emails oncall+perf_viz
 * @format
 */
/* eslint-disable */

'use strict';

  module.exports = require('./recoil.production.native.js'); // @oss-only

I have to do this everytime I npm install but that's fine, I just drag the recoil.production.native.js back in and change index.js.

Temporary until we have official RN support

Neat, I didn't update the index.js file that's why! Recoil is surely great, can't wait to officially use it with RN.

Thanks for the tip man!

For anyone willing to use it before the PR gets merged, my fork is public and the package built:

npm install eveningkid/Recoil#react-native --save

If someone is using patch-package here's a patch (recoil+0.0.8.patch) to be able to use it in RN:

diff --git a/node_modules/recoil/dist/index.js b/node_modules/recoil/dist/index.js
index 06d3b46..30bc725 100644
--- a/node_modules/recoil/dist/index.js
+++ b/node_modules/recoil/dist/index.js
@@ -11,8 +11,10 @@

 'use strict';

-if (process.env.NODE_ENV === 'production') { // @oss-only
-  module.exports = require('./recoil.production.js'); // @oss-only
-} else { // @oss-only
-  module.exports = require('./recoil.development.js'); // @oss-only
-} // @oss-only
+// if (process.env.NODE_ENV === 'production') { // @oss-only
+//   module.exports = require('./recoil.production.js'); // @oss-only
+// } else { // @oss-only
+//   module.exports = require('./recoil.development.js'); // @oss-only
+// } // @oss-only
+
+module.exports = require('./recoil.development.js'); // @oss-only
diff --git a/node_modules/recoil/dist/recoil.development.js b/node_modules/recoil/dist/recoil.development.js
index 90321c4..e0506e9 100644
--- a/node_modules/recoil/dist/recoil.development.js
+++ b/node_modules/recoil/dist/recoil.development.js
@@ -5,7 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
 function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

 var react = _interopDefault(require('react'));
-var reactDom = _interopDefault(require('react-dom'));
+var reactDom = _interopDefault(require('react-native'));

 /**
  * Copyright (c) Facebook, Inc. and its affiliates.
@@ -188,7 +188,8 @@ function registerNode(node) {
     // prettier-ignore
     // @fb-only: } else {

-    Recoil_recoverableViolation(message); // @fb-only: }
+    console.warn(message) // RN exception manager is somehow broken with recoil
+    // Recoil_recoverableViolation(message); // @fb-only: }
   }

   nodes.set(node.key, node);

Btw, I've got errors due to duplicated keys, but the RN exception manager couldn't deal with the recoil message and hid the recoil warning with a exception (nice, the exception manager throws exceptions while dealing with them)... - not sure if it's due to me forcing the use of recoil dev 馃

Was this page helpful?
0 / 5 - 0 ratings

Related issues

polemius picture polemius  路  3Comments

ymolists picture ymolists  路  3Comments

art1373 picture art1373  路  4Comments

karevn picture karevn  路  3Comments

yuantongkang picture yuantongkang  路  3Comments