From 2bf4a48a3d5f96704d82e65d3c6b896fa5231a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=A1=E6=99=A8?= Date: Thu, 2 Apr 2020 17:26:26 +0800 Subject: [PATCH] use a custom renderer instead of react-dom --- package.json | 7 ++++--- rollup.config.js | 2 +- src/create-model.tsx | 8 +++----- src/executor.tsx | 20 ++------------------ src/renderer.tsx | 38 ++++++++++++++++++++++++++++++++++++++ yarn.lock | 42 +++++++++++++++++++++++++++++++++++++----- 6 files changed, 85 insertions(+), 32 deletions(-) create mode 100644 src/renderer.tsx diff --git a/package.json b/package.json index 29c0a19..9676857 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,7 @@ "license": "MIT", "private": false, "peerDependencies": { - "react": "^16.8.0", - "react-dom": "^16.8.0" + "react": "^16.8.0" }, "scripts": { "build": "gulp build", @@ -44,6 +43,8 @@ "typescript": "^3.4.5" }, "dependencies": { - "@types/hoist-non-react-statics": "^3.3.1" + "@types/hoist-non-react-statics": "^3.3.1", + "@types/react-reconciler": "^0.18.0", + "react-reconciler": "^0.25.1" } } diff --git a/rollup.config.js b/rollup.config.js index 166d929..1e30fd1 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,5 +1,5 @@ module.exports = { - external: ["react", "react-dom"], + external: ["react"], input: "lib/es/index.js", output: { name: "hox", diff --git a/src/create-model.tsx b/src/create-model.tsx index 438b589..6a50fa7 100644 --- a/src/create-model.tsx +++ b/src/create-model.tsx @@ -1,21 +1,19 @@ import { ModelHook, UseModel } from "./types"; import { Container } from "./container"; -import ReactDOM from "react-dom"; import { Executor } from "./executor"; import React, { useEffect, useRef, useState } from "react"; +import { render } from "./renderer"; export function createModel(hook: ModelHook) { - const element = document.createElement("div"); const container = new Container(hook); - ReactDOM.render( + render( { container.data = val; container.notify(); }} hook={hook} - />, - element + /> ); const useModel: UseModel = depsFn => { const [state, setState] = useState(() => diff --git a/src/executor.tsx b/src/executor.tsx index aff5f94..94954c9 100644 --- a/src/executor.tsx +++ b/src/executor.tsx @@ -1,27 +1,11 @@ import { ModelHook } from "./types"; -import { ReactElement, useEffect, useMemo, useRef } from "react"; +import { ReactElement } from "react"; export function Executor(props: { hook: ModelHook; onUpdate: (data: T) => void; }) { const data = props.hook(); - const initialLoad = useRef(false); - - useMemo(() => { - // notify the initial value - props.onUpdate(data); - initialLoad.current = false; - }, []) - - useEffect(()=>{ - if (initialLoad.current) { - // notify the following value changes - props.onUpdate(data); - } else { - initialLoad.current = true; - } - }) - + props.onUpdate(data); return null as ReactElement; } diff --git a/src/renderer.tsx b/src/renderer.tsx new file mode 100644 index 0000000..efcf78f --- /dev/null +++ b/src/renderer.tsx @@ -0,0 +1,38 @@ +import ReactReconciler from "react-reconciler"; +import { ReactElement } from "react"; + +const rootHostContext = {}; +const childHostContext = {}; + +const hostConfig = { + now: Date.now, + getRootHostContext: () => { + return rootHostContext; + }, + prepareForCommit: () => {}, + resetAfterCommit: () => {}, + getChildHostContext: () => { + return childHostContext; + }, + shouldSetTextContent: () => true, + createInstance: () => {}, + createTextInstance: () => {}, + appendInitialChild: () => {}, + appendChild: () => {}, + finalizeInitialChildren: () => {}, + supportsMutation: true, + appendChildToContainer: () => {}, + prepareUpdate() { + return true; + }, + commitUpdate() {}, + commitTextUpdate: () => {}, + removeChild: () => {} +}; + +const reconciler = ReactReconciler(hostConfig as any); + +export function render(reactElement: ReactElement) { + const container = reconciler.createContainer(null, false, false); + return reconciler.updateContainer(reactElement, container, null, null); +} diff --git a/yarn.lock b/yarn.lock index efe3c13..2b7ff89 100644 --- a/yarn.lock +++ b/yarn.lock @@ -472,13 +472,27 @@ resolved "https://registry.npm.taobao.org/@types/prop-types/download/@types/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha1-KrDV2i5YFflLC51LldHl8kOrLKc= -"@types/react-dom@*", "@types/react-dom@^16.8.0": +"@types/react-dom@*": version "16.9.2" resolved "https://registry.npm.taobao.org/@types/react-dom/download/@types/react-dom-16.9.2.tgz#90f9e6c161850be1feb31d2f448121be2a4f3b47" integrity sha1-kPnmwWGFC+H+sx0vRIEhvipPO0c= dependencies: "@types/react" "*" +"@types/react-dom@^16.8.0": + version "16.9.6" + resolved "https://registry.npm.taobao.org/@types/react-dom/download/@types/react-dom-16.9.6.tgz#9e7f83d90566521cc2083be2277c6712dcaf754c" + integrity sha1-nn+D2QVmUhzCCDviJ3xnEtyvdUw= + dependencies: + "@types/react" "*" + +"@types/react-reconciler@^0.18.0": + version "0.18.0" + resolved "https://registry.npm.taobao.org/@types/react-reconciler/download/@types/react-reconciler-0.18.0.tgz#fce2b444103f44904e73eba349ac6552e2771f64" + integrity sha1-/OK0RBA/RJBOc+ujSaxlUuJ3H2Q= + dependencies: + "@types/react" "*" + "@types/react-test-renderer@^16.8.0": version "16.9.1" resolved "https://registry.npm.taobao.org/@types/react-test-renderer/download/@types/react-test-renderer-16.9.1.tgz#9d432c46c515ebe50c45fa92c6fb5acdc22e39c4" @@ -4215,20 +4229,30 @@ rc@^1.2.7: strip-json-comments "~2.0.1" react-dom@^16.8.0: - version "16.10.2" - resolved "https://registry.npm.taobao.org/react-dom/download/react-dom-16.10.2.tgz#4840bce5409176bc3a1f2bd8cb10b92db452fda6" - integrity sha1-SEC85UCRdrw6HyvYyxC5LbRS/aY= + version "16.13.1" + resolved "https://registry.npm.taobao.org/react-dom/download/react-dom-16.13.1.tgz?cache=0&sync_timestamp=1585594954837&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-dom%2Fdownload%2Freact-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" + integrity sha1-wb03MxoEhsB47lTEdAcgmTsuDn8= dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" - scheduler "^0.16.2" + scheduler "^0.19.1" react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6: version "16.10.2" resolved "https://registry.npm.taobao.org/react-is/download/react-is-16.10.2.tgz#984120fd4d16800e9a738208ab1fba422d23b5ab" integrity sha1-mEEg/U0WgA6ac4IIqx+6Qi0jtas= +react-reconciler@^0.25.1: + version "0.25.1" + resolved "https://registry.npm.taobao.org/react-reconciler/download/react-reconciler-0.25.1.tgz?cache=0&sync_timestamp=1585596110704&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-reconciler%2Fdownload%2Freact-reconciler-0.25.1.tgz#f9814d59d115e1210762287ce987801529363aaa" + integrity sha1-+YFNWdEV4SEHYih86YeAFSk2Oqo= + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.19.1" + react-test-renderer@^16.8.0: version "16.10.2" resolved "https://registry.npm.taobao.org/react-test-renderer/download/react-test-renderer-16.10.2.tgz#4d8492f8678c9b43b721a7d79ed0840fdae7c518" @@ -4603,6 +4627,14 @@ scheduler@^0.16.2: loose-envify "^1.1.0" object-assign "^4.1.1" +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.npm.taobao.org/scheduler/download/scheduler-0.19.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fscheduler%2Fdownload%2Fscheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" + integrity sha1-Tz4u0sGn1laB9MhU+oxaHMtA8ZY= + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.npm.taobao.org/semver-compare/download/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"