From 6d1bacefd6e1389f466daeed7f58de6ddfd8c0af Mon Sep 17 00:00:00 2001 From: MaySoMusician Date: Wed, 3 May 2023 15:41:43 +0900 Subject: [PATCH 1/4] Add functionality to replace null in props with undefined --- react_ujs/index.js | 9 ++++++++- react_ujs/src/options.js | 13 +++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 react_ujs/src/options.js diff --git a/react_ujs/index.js b/react_ujs/index.js index 6b8effc85..667605bef 100644 --- a/react_ujs/index.js +++ b/react_ujs/index.js @@ -8,6 +8,7 @@ var constructorFromRequireContext = require("./src/getConstructor/fromRequireCon var constructorFromRequireContextWithGlobalFallback = require("./src/getConstructor/fromRequireContextWithGlobalFallback") var constructorFromRequireContextsWithGlobalFallback = require("./src/getConstructor/fromRequireContextsWithGlobalFallback") const { supportsHydration, reactHydrate, createReactRootLike } = require("./src/renderHelpers") +const { replaceNullWithUndefined } = require("./src/options") var ReactRailsUJS = { // This attribute holds the name of component which should be mounted @@ -31,6 +32,11 @@ var ReactRailsUJS = { components: {}, + // Set default values for options. + options: { + replaceNull: false, + }, + // helper method for the mount and unmount methods to find the // `data-react-class` DOM elements findDOMNodes: function(searchSelector) { @@ -106,7 +112,8 @@ var ReactRailsUJS = { var className = node.getAttribute(ujs.CLASS_NAME_ATTR); var constructor = ujs.getConstructor(className); var propsJson = node.getAttribute(ujs.PROPS_ATTR); - var props = propsJson && JSON.parse(propsJson); + var props = propsJson && (ujs.options.replaceNull ? replaceNullWithUndefined(JSON.parse(propsJson)) + : JSON.parse(propsJson)); var hydrate = node.getAttribute(ujs.RENDER_ATTR); var cacheId = node.getAttribute(ujs.CACHE_ID_ATTR); var turbolinksPermanent = node.hasAttribute(ujs.TURBOLINKS_PERMANENT_ATTR); diff --git a/react_ujs/src/options.js b/react_ujs/src/options.js new file mode 100644 index 000000000..e56ac6e39 --- /dev/null +++ b/react_ujs/src/options.js @@ -0,0 +1,13 @@ +export function replaceNullWithUndefined(obj) { + Object.entries(obj).forEach((entry) => { + const key = entry[0] + const value = entry[1] + if(!!value && typeof value === 'object') { + return replaceNullWithUndefined(value) + } + if (value === null) { + obj[key] = undefined + } + }) + return obj +} From 01dc206bb3601e8bf7fa9e20e113bd7ff69118dd Mon Sep 17 00:00:00 2001 From: MaySoMusician Date: Wed, 3 May 2023 15:42:25 +0900 Subject: [PATCH 2/4] Add option system to allow to selectively enable options --- react_ujs/index.js | 6 +++++- react_ujs/src/options.js | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/react_ujs/index.js b/react_ujs/index.js index 667605bef..484cc98bc 100644 --- a/react_ujs/index.js +++ b/react_ujs/index.js @@ -8,7 +8,7 @@ var constructorFromRequireContext = require("./src/getConstructor/fromRequireCon var constructorFromRequireContextWithGlobalFallback = require("./src/getConstructor/fromRequireContextWithGlobalFallback") var constructorFromRequireContextsWithGlobalFallback = require("./src/getConstructor/fromRequireContextsWithGlobalFallback") const { supportsHydration, reactHydrate, createReactRootLike } = require("./src/renderHelpers") -const { replaceNullWithUndefined } = require("./src/options") +const { replaceNullWithUndefined, overwriteOption } = require("./src/options") var ReactRailsUJS = { // This attribute holds the name of component which should be mounted @@ -37,6 +37,10 @@ var ReactRailsUJS = { replaceNull: false, }, + setOptions: function(newOptions) { + overwriteOption(ReactRailsUJS.options, newOptions, "replaceNull") + }, + // helper method for the mount and unmount methods to find the // `data-react-class` DOM elements findDOMNodes: function(searchSelector) { diff --git a/react_ujs/src/options.js b/react_ujs/src/options.js index e56ac6e39..4153ad1f4 100644 --- a/react_ujs/src/options.js +++ b/react_ujs/src/options.js @@ -11,3 +11,8 @@ export function replaceNullWithUndefined(obj) { }) return obj } + +export function overwriteOption(ujsOptions, newOptions, key) { + if (!Object.prototype.hasOwnProperty.call(newOptions, key)) return + ujsOptions[key] = newOptions[key] +} From 333667a73da296b97e0fab178c3578299601bd7c Mon Sep 17 00:00:00 2001 From: MaySoMusician Date: Wed, 3 May 2023 15:56:41 +0900 Subject: [PATCH 3/4] :memo: Add how to use setOptions function to README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 6941d39d6..1041c5635 100644 --- a/README.md +++ b/README.md @@ -528,6 +528,19 @@ use it like so: ReactUJS.getConstructor = ReactUJS.constructorFromRequireContext(require.context('components', true)); ``` +### Configure UJS + +You can change the behaviours of `ReactRailsUJS` by calling `setOptions(options)` function: + +```js +ReactRailsUJS.setOptions({ replaceNull: false }); +``` + +Current acceptable options are the following: + +| Key | Value type | Description | Default | +| --- | ---------- | ----------- | ------- | +| `replaceNull` | boolean (`true` / `false`) | Whether to replace all `null`s in the props from Rails (originally `nil` in Rails) with `undefined`. May be helpful when defining the types of the props in TypeScript. See [discussion#1272](https://github.com/reactjs/react-rails/discussions/1272). | `false`| ## Server-Side Rendering From f2ae2e26dc07616678d1f4acadbeca5dc6cf8b81 Mon Sep 17 00:00:00 2001 From: MaySoMusician Date: Wed, 3 May 2023 16:17:42 +0900 Subject: [PATCH 4/4] :memo: Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c128e6c6..ddfb19edb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ If you need help upgrading `react-rails`, `webpacker` to `shakapacker`, or JS pa Changes since last non-beta release. _Please add entries here for your pull requests that are not yet released._ +- Add option to replace `null`s in props with `undefined` via `ReactRailsUJS.setOptions` #1273 ### Breaking Changes - Remove support & testing for Webpacker 3/4.