From 7a0f19ced167f843650f344d3f60ef79f9274335 Mon Sep 17 00:00:00 2001 From: ChenYong Date: Wed, 13 May 2020 16:44:46 +0800 Subject: [PATCH] provide an useAtom hooks API --- README.md | 18 +++++++++++++++++ example/demo-atom.tsx | 39 +++++++++++++++++++++++++++++++++++++ example/pages/container.tsx | 9 +++++++++ src/use-atom.ts | 25 ++++++++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 example/demo-atom.tsx create mode 100644 src/use-atom.ts diff --git a/README.md b/README.md index 35b9748..2487b97 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,24 @@ Rex added a log even in release mode for debugging, add run this to turn on: window.REX_DEV_LOG = true; ``` +### `useAtom` + +```tsx +// "Clojure Atom"-like state management +let dataAtom = useAtom({ a: 1 }); + +let onClick = () => { + // get latest state + dataAtom.deref(); + // replace data + dataAtom.resetWith({ a: 0 }); + // update data by function, frozen by immer + dataAtom.swapWith((data) => { + data.a += 1; + }); +}; +``` + ### Workflow https://github.com/jimengio/ts-workflow diff --git a/example/demo-atom.tsx b/example/demo-atom.tsx new file mode 100644 index 0000000..60a374b --- /dev/null +++ b/example/demo-atom.tsx @@ -0,0 +1,39 @@ +import React, { FC } from "react"; +import { css } from "emotion"; +import { useAtom } from "../src/use-atom"; + +let DemoAtom: FC<{ className?: string }> = React.memo((props) => { + let dataAtom = useAtom({ a: 1 }); + + /** Plugins */ + /** Methods */ + /** Effects */ + /** Renderers */ + return ( +
+
{JSON.stringify(dataAtom.deref(), null, 2)}
+
+ +
+
+ +
+
+ ); +}); + +export default DemoAtom; diff --git a/example/pages/container.tsx b/example/pages/container.tsx index 0263706..0fa4ce6 100644 --- a/example/pages/container.tsx +++ b/example/pages/container.tsx @@ -5,6 +5,7 @@ import randomcolor from "randomcolor"; import Home from "./home"; import { IGlobalStore } from "models/global"; import { randomBg } from "util/color"; +import DemoAtom from "demo-atom"; interface IProps { store: IGlobalStore; @@ -18,6 +19,10 @@ export default (props: IProps) => {
Container
{JSON.stringify(props.store, null, 2)}
+ + + +
); }; @@ -30,3 +35,7 @@ const styleContainer = css` const styleTitle = css` margin-bottom: 16px; `; + +let styleSpace = css` + height: 200px; +`; diff --git a/src/use-atom.ts b/src/use-atom.ts new file mode 100644 index 0000000..81c2c86 --- /dev/null +++ b/src/use-atom.ts @@ -0,0 +1,25 @@ +import { useState, useRef } from "react"; +import { produce } from "immer"; + +/** "Clojure Atom"-like data management for React Hooks */ +export let useAtom = (data: T) => { + // state only for triggering changes, data actually hold in dataRef + let [state, setState] = useState(data); + let dataRef = useRef(data); + + console.log("Atom demo updating"); + + return { + deref: () => dataRef.current, + resetWith: (newData: T) => { + dataRef.current = newData; + setState(newData); + }, + /** updates with Immer, returns a frozen result */ + swapWith: (f: (d: T) => T | void) => { + let newData = produce(dataRef.current, f) as T; + dataRef.current = newData; + setState(newData); + }, + }; +};