Skip to content

Commit

Permalink
Merge pull request #26 from jimengio/use-atom
Browse files Browse the repository at this point in the history
provide an useAtom hooks API
  • Loading branch information
chenyong authored May 13, 2020
2 parents 48e78b7 + 7a0f19c commit 8ea3c9d
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 0 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
39 changes: 39 additions & 0 deletions example/demo-atom.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className={props.className}>
<pre>{JSON.stringify(dataAtom.deref(), null, 2)}</pre>
<div>
<button
onClick={() => {
dataAtom.resetWith({ a: 0 });
}}
>
Reset
</button>
</div>
<div>
<button
onClick={() => {
dataAtom.swapWith((data) => {
data.a += 1;
});
}}
>
Add
</button>
</div>
</div>
);
});

export default DemoAtom;
9 changes: 9 additions & 0 deletions example/pages/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -18,6 +19,10 @@ export default (props: IProps) => {
<div className={styleTitle}>Container</div>
<pre>{JSON.stringify(props.store, null, 2)}</pre>
<Home data={props.store.homeData} obj={props.store.obj} />

<DemoAtom />

<div className={styleSpace}></div>
</div>
);
};
Expand All @@ -30,3 +35,7 @@ const styleContainer = css`
const styleTitle = css`
margin-bottom: 16px;
`;

let styleSpace = css`
height: 200px;
`;
25 changes: 25 additions & 0 deletions src/use-atom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useState, useRef } from "react";
import { produce } from "immer";

/** "Clojure Atom"-like data management for React Hooks */
export let useAtom = <T>(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);
},
};
};

0 comments on commit 8ea3c9d

Please sign in to comment.