mobx-react-lite
Advanced tools
Comparing version 0.1.2 to 0.2.0
@@ -14,18 +14,2 @@ (function (global, factory) { | ||
try { | ||
configureDOM(); | ||
configureNative(); | ||
} | ||
catch (err) { | ||
// safe to ignore here? | ||
} | ||
function configureDOM() { | ||
const { unstable_batchedUpdates } = require("react-dom"); | ||
mobx.configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function configureNative() { | ||
const { unstable_batchedUpdates } = require("react-native"); | ||
mobx.configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function useObservable(initialValue) { | ||
@@ -35,11 +19,5 @@ return react.useRef(mobx.observable(initialValue)).current; | ||
function useComputed(initialValue) { | ||
const value = mobx.computed(initialValue); | ||
const [state, setState] = react.useState(value.get()); | ||
react.useEffect(() => { | ||
return value.observe(change => { | ||
setState(change.newValue); | ||
}); | ||
}, []); | ||
return state; | ||
function useComputed(initialValue, inputs = []) { | ||
const computed = react.useMemo(() => mobx.computed(initialValue), inputs); | ||
return computed.get(); | ||
} | ||
@@ -46,0 +24,0 @@ |
@@ -1,3 +0,3 @@ | ||
import { spy, configure, observable, computed, Reaction } from 'mobx'; | ||
import { useState, useRef, useEffect, memo, useMemo } from 'react'; | ||
import { spy, observable, Reaction, computed } from 'mobx'; | ||
import { useState, useRef, useMemo, memo, useEffect } from 'react'; | ||
@@ -11,18 +11,2 @@ if (!useState) { | ||
try { | ||
configureDOM(); | ||
configureNative(); | ||
} | ||
catch (err) { | ||
// safe to ignore here? | ||
} | ||
function configureDOM() { | ||
const { unstable_batchedUpdates } = require("react-dom"); | ||
configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function configureNative() { | ||
const { unstable_batchedUpdates } = require("react-native"); | ||
configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function useObservable(initialValue) { | ||
@@ -32,11 +16,5 @@ return useRef(observable(initialValue)).current; | ||
function useComputed(initialValue) { | ||
const value = computed(initialValue); | ||
const [state, setState] = useState(value.get()); | ||
useEffect(() => { | ||
return value.observe(change => { | ||
setState(change.newValue); | ||
}); | ||
}, []); | ||
return state; | ||
function useComputed(initialValue, inputs = []) { | ||
const computed$$1 = useMemo(() => computed(initialValue), inputs); | ||
return computed$$1.get(); | ||
} | ||
@@ -43,0 +21,0 @@ |
import "./assertEnvironment"; | ||
import "./configureScheduler"; | ||
export { useObservable } from "./useObservable"; | ||
@@ -4,0 +3,0 @@ export { useComputed } from "./useComputed"; |
@@ -14,18 +14,2 @@ (function (global, factory) { | ||
try { | ||
configureDOM(); | ||
configureNative(); | ||
} | ||
catch (err) { | ||
// safe to ignore here? | ||
} | ||
function configureDOM() { | ||
const { unstable_batchedUpdates } = require("react-dom"); | ||
mobx.configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function configureNative() { | ||
const { unstable_batchedUpdates } = require("react-native"); | ||
mobx.configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function useObservable(initialValue) { | ||
@@ -35,11 +19,5 @@ return react.useRef(mobx.observable(initialValue)).current; | ||
function useComputed(initialValue) { | ||
const value = mobx.computed(initialValue); | ||
const [state, setState] = react.useState(value.get()); | ||
react.useEffect(() => { | ||
return value.observe(change => { | ||
setState(change.newValue); | ||
}); | ||
}, []); | ||
return state; | ||
function useComputed(initialValue, inputs = []) { | ||
const computed = react.useMemo(() => mobx.computed(initialValue), inputs); | ||
return computed.get(); | ||
} | ||
@@ -46,0 +24,0 @@ |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("mobx"),require("react")):"function"==typeof define&&define.amd?define(["exports","mobx","react"],t):t(e.mobxReact={},e.mobx,e.React)}(this,function(e,t,r){"use strict";if(!r.useState)throw new Error("mobx-react requires React 16.7 to be available");if(!t.spy)throw new Error("mobx-react requires mobx to be available");try{!function(){const{unstable_batchedUpdates:e}=require("react-dom");t.configure({reactionScheduler:e})}(),function(){const{unstable_batchedUpdates:e}=require("react-native");t.configure({reactionScheduler:e})}()}catch(e){}let n=!1;function o(e){return n?e:r.memo(n=>{const o=function(){const[e,t]=r.useState(1);return()=>{t(e+1)}}(),c=r.useMemo(()=>new t.Reaction(`observer(${e.displayName||e.name})`,o),[]);let u;return function(e){r.useEffect(()=>e,[])}(()=>c.dispose()),c.track(()=>{u=e(n)}),u})}const c=o(({children:e,render:t})=>{const r=e||t;return void 0===r?null:r()});function u(e,t,r,n,o){const c="children"===t?"render":"children",u="function"==typeof e[t],i="function"==typeof e[c];return u&&i?new Error("MobX Observer: Do not use children and render in the same time in`"+r):u||i?null:new Error("Invalid prop `"+o+"` of type `"+typeof e[t]+"` supplied to `"+r+"`, expected `function`.")}c.displayName="Observer",c.propTypes={children:u,render:u},e.useObservable=function(e){return r.useRef(t.observable(e)).current},e.useComputed=function(e){const n=t.computed(e),[o,c]=r.useState(n.get());return r.useEffect(()=>n.observe(e=>{c(e.newValue)}),[]),o},e.observer=o,e.useStaticRendering=function(e){n=e},e.Observer=c,Object.defineProperty(e,"__esModule",{value:!0})}); | ||
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("mobx"),require("react")):"function"==typeof define&&define.amd?define(["exports","mobx","react"],r):r(e.mobxReact={},e.mobx,e.React)}(this,function(e,r,t){"use strict";if(!t.useState)throw new Error("mobx-react requires React 16.7 to be available");if(!r.spy)throw new Error("mobx-react requires mobx to be available");let n=!1;function o(e){return n?e:t.memo(n=>{const o=function(){const[e,r]=t.useState(1);return()=>{r(e+1)}}(),i=t.useMemo(()=>new r.Reaction(`observer(${e.displayName||e.name})`,o),[]);let u;return function(e){t.useEffect(()=>e,[])}(()=>i.dispose()),i.track(()=>{u=e(n)}),u})}const i=o(({children:e,render:r})=>{const t=e||r;return void 0===t?null:t()});function u(e,r,t,n,o){const i="children"===r?"render":"children",u="function"==typeof e[r],c="function"==typeof e[i];return u&&c?new Error("MobX Observer: Do not use children and render in the same time in`"+t):u||c?null:new Error("Invalid prop `"+o+"` of type `"+typeof e[r]+"` supplied to `"+t+"`, expected `function`.")}i.displayName="Observer",i.propTypes={children:u,render:u},e.useObservable=function(e){return t.useRef(r.observable(e)).current},e.useComputed=function(e,n=[]){return t.useMemo(()=>r.computed(e),n).get()},e.observer=o,e.useStaticRendering=function(e){n=e},e.Observer=i,Object.defineProperty(e,"__esModule",{value:!0})}); |
@@ -1,3 +0,3 @@ | ||
import { spy, configure, observable, computed, Reaction } from 'mobx'; | ||
import { useState, useRef, useEffect, memo, useMemo } from 'react'; | ||
import { spy, observable, Reaction, computed } from 'mobx'; | ||
import { useState, useRef, useMemo, memo, useEffect } from 'react'; | ||
@@ -11,18 +11,2 @@ if (!useState) { | ||
try { | ||
configureDOM(); | ||
configureNative(); | ||
} | ||
catch (err) { | ||
// safe to ignore here? | ||
} | ||
function configureDOM() { | ||
const { unstable_batchedUpdates } = require("react-dom"); | ||
configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function configureNative() { | ||
const { unstable_batchedUpdates } = require("react-native"); | ||
configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function useObservable(initialValue) { | ||
@@ -32,11 +16,5 @@ return useRef(observable(initialValue)).current; | ||
function useComputed(initialValue) { | ||
const value = computed(initialValue); | ||
const [state, setState] = useState(value.get()); | ||
useEffect(() => { | ||
return value.observe(change => { | ||
setState(change.newValue); | ||
}); | ||
}, []); | ||
return state; | ||
function useComputed(initialValue, inputs = []) { | ||
const computed$$1 = useMemo(() => computed(initialValue), inputs); | ||
return computed$$1.get(); | ||
} | ||
@@ -43,0 +21,0 @@ |
@@ -15,18 +15,2 @@ 'use strict'; | ||
try { | ||
configureDOM(); | ||
configureNative(); | ||
} | ||
catch (err) { | ||
// safe to ignore here? | ||
} | ||
function configureDOM() { | ||
const { unstable_batchedUpdates } = require("react-dom"); | ||
mobx.configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function configureNative() { | ||
const { unstable_batchedUpdates } = require("react-native"); | ||
mobx.configure({ reactionScheduler: unstable_batchedUpdates }); | ||
} | ||
function useObservable(initialValue) { | ||
@@ -36,11 +20,5 @@ return react.useRef(mobx.observable(initialValue)).current; | ||
function useComputed(initialValue) { | ||
const value = mobx.computed(initialValue); | ||
const [state, setState] = react.useState(value.get()); | ||
react.useEffect(() => { | ||
return value.observe(change => { | ||
setState(change.newValue); | ||
}); | ||
}, []); | ||
return state; | ||
function useComputed(initialValue, inputs = []) { | ||
const computed = react.useMemo(() => mobx.computed(initialValue), inputs); | ||
return computed.get(); | ||
} | ||
@@ -47,0 +25,0 @@ |
@@ -1,1 +0,1 @@ | ||
export declare function useComputed<T>(initialValue: () => T): T; | ||
export declare function useComputed<T>(initialValue: () => T, inputs?: ReadonlyArray<unknown>): T; |
@@ -1,1 +0,3 @@ | ||
export declare function useObservable<T extends object>(initialValue: T): T; | ||
declare type SupportedValues = object | Map<unknown, unknown> | Array<unknown>; | ||
export declare function useObservable<T extends SupportedValues>(initialValue: T): T; | ||
export {}; |
{ | ||
"name": "mobx-react-lite", | ||
"version": "0.1.2", | ||
"version": "0.2.0", | ||
"description": "Lightweight React bindings for MobX based on experimental React hooks", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -100,2 +100,70 @@ # mobx-react-lite | ||
### useObservable | ||
React hook that allows creating observable object within a component body and keeps track of it over renders. Gets all the benefits from [observable objects](https://mobx.js.org/refguide/object.html) including computed properties and methods. You can also use arrays and Map which are useful to track dynamic list/table of information. The Set is not supported (see https://github.com/mobxjs/mobx/issues/69). | ||
Warning: With current implementation you also need to wrap your component to `observer` otherwise the rerender on update won't happen. | ||
```tsx | ||
import { observer, useObservable } from "mobx-react-lite" | ||
const TodoList = observer(() => { | ||
const todos = useObservable(new Map<string, boolean>()) | ||
const todoRef = React.useRef() | ||
const addTodo = React.useCallback(() => { | ||
todos.set(todoRef.current.value, false) | ||
todoRef.current.value = "" | ||
}, []) | ||
const toggleTodo = React.useCallback((todo: string) => { | ||
todos.set(todo, !todos.get(todo)) | ||
}, []) | ||
return ( | ||
<div> | ||
{Array.from(todos).map(([todo, done]) => ( | ||
<div onClick={() => toggleTodo(todo)} key={todo}> | ||
{todo} | ||
{done ? " ✔" : " ⏲"} | ||
</div> | ||
))} | ||
<input ref={todoRef} /> | ||
<button onClick={addTodo}>Add todo</button> | ||
</div> | ||
) | ||
}) | ||
``` | ||
[![Edit TodoList](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/jzj48v2xry?module=%2Fsrc%2FTodoList.tsx) | ||
Note that if you want to track a single scalar value (string, number, boolean), you would need [a boxed value](https://mobx.js.org/refguide/boxed.html) which is not recognized by `useObservable`. However, we recommend to just `useState` instead which gives you almost same result (with slightly different API). | ||
### useComputed | ||
Another React hook that simplifies computational logic. It's just a tiny wrapper around [MobX computed](https://mobx.js.org/refguide/computed-decorator.html#-computed-expression-as-function) function that runs computation whenever observable values change. In conjuction with `observer` the component will rerender based on such a change. | ||
```tsx | ||
const Calculator = observer(({ hasExploded }: { hasExploded: boolean }) => { | ||
const inputRef = React.useRef() | ||
const inputs = useObservable([1, 3, 5]) | ||
const result = useComputed( | ||
() => (hasExploded ? "💣" : inputs.reduce(multiply, 1) * Number(!hasExploded)), | ||
[hasExploded] | ||
) | ||
return ( | ||
<div> | ||
<input ref={inputRef} /> | ||
<button onClick={() => inputs.push(parseInt(inputRef.current.value) | 1)}> | ||
Multiply | ||
</button> | ||
<div> | ||
{inputs.join(" * ")} = {result} | ||
</div> | ||
</div> | ||
) | ||
}) | ||
``` | ||
Notice that since the computation depends on non-observable value, it has to be passed as a second argument to `useComputed`. There is [React `useMemo`](https://reactjs.org/docs/hooks-reference.html#usememo) behind the scenes and all rules applies here as well except you don't need to specify dependency on observable values. | ||
### Server Side Rendering with `useStaticRendering` | ||
@@ -102,0 +170,0 @@ |
251775
20
211
488