src\Counter.jsx
import React from 'react';
import {makeAutoObservable} from 'mobx';
import {useObserver} from './mobx-react';
class Store {
number = 1
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
add() {
this.number++;
}
}
let store = new Store();
export default function () {
return useObserver(()=>(
<div>
<p>{store.number}</p>
<button onClick={store.add}>+</button>
</div>
));
};
src\mobx-react\index.jsx
import React,{useEffect,forwardRef} from 'react';
import { Reaction } from 'mobx';
export function useObserver(fn) {
const [, setState] = React.useState();
const forceUpdate = () => setState({});
const reactionTrackingRef = React.useRef(null);
if (!reactionTrackingRef.current) {
const reaction = new Reaction(`observer`, () => {
forceUpdate();
});
reactionTrackingRef.current = { reaction };
}
const { reaction } = reactionTrackingRef.current;
useEffect(() => {
return () => {
reactionTrackingRef.current.reaction.dispose();
reactionTrackingRef.current = null;
}
},[]);
let rendering;
reaction.track(() => {
rendering = fn();
});
return rendering;
}
src\Counter.jsx
import React from 'react';
import {makeAutoObservable} from 'mobx';
+import {useObserver,Observer,observer} from './mobx-react';
class Store {
number = 1
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
add() {
this.number++;
}
}
let store = new Store();
export default function () {
return (
+ <Observer>
{
()=>(
<>
<p>{store.number}</p>
<button onClick={store.add}>+</button>
</>
)
}
+ </Observer>
)
}
src\mobx-react\index.jsx
import React,{useEffect,forwardRef} from 'react';
import { Reaction } from 'mobx';
export function useObserver(fn) {
const [, setState] = React.useState();
const forceUpdate = () => setState({});
const reactionTrackingRef = React.useRef(null);
if (!reactionTrackingRef.current) {
const reaction = new Reaction(`observer`, () => {
forceUpdate();
});
reactionTrackingRef.current = { reaction };
}
const { reaction } = reactionTrackingRef.current;
useEffect(() => {
return () => {
reactionTrackingRef.current.reaction.dispose();
reactionTrackingRef.current = null;
}
},[]);
let rendering;
reaction.track(() => {
rendering = fn();
});
return rendering;
}
+export function Observer({ children }) {
+ return useObserver(children);
+}
src\Counter.jsx
import React from 'react';
import {makeAutoObservable} from 'mobx';
import {useObserver,Observer,observer} from './mobx-react';
class Store {
number = 1
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
add() {
this.number++;
}
}
let store = new Store();
+export default observer(function () {
return (
<div>
<p>{store.number}</p>
<button onClick={store.add}>+</button>
</div>
)
});
src\mobx-react\index.jsx
import React,{useEffect,forwardRef} from 'react';
import { Reaction } from 'mobx';
export function useObserver(fn) {
const [, setState] = React.useState();
const forceUpdate = () => setState({});
const reactionTrackingRef = React.useRef(null);
if (!reactionTrackingRef.current) {
const reaction = new Reaction(`observer`, () => {
forceUpdate();
});
reactionTrackingRef.current = { reaction };
}
const { reaction } = reactionTrackingRef.current;
useEffect(() => {
return () => {
reactionTrackingRef.current.reaction.dispose();
reactionTrackingRef.current = null;
}
},[]);
let rendering;
reaction.track(() => {
rendering = fn();
});
return rendering;
}
export function Observer({ children }) {
return useObserver(children);
}
+export function observer(baseComponent) {
+ let observerComponent = (props) => {
+ return useObserver(() => baseComponent(props));
+ };
+ return observerComponent;
+}
src\Counter.jsx
import React from 'react';
import {makeAutoObservable} from 'mobx';
import {useObserver,Observer,observer} from './mobx-react';
class Store {
number = 1
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
add() {
this.number++;
}
}
let store = new Store();
export default observer(function () {
return (
<div>
<p>{store.number}</p>
<button onClick={store.add}>+</button>
</div>
)
},{forwardRef:true});
src\mobx-react\index.jsx
import React,{useEffect,forwardRef,memo} from 'react';
import { Reaction } from 'mobx';
export function useObserver(fn) {
const [, setState] = React.useState();
const forceUpdate = () => setState({});
const reactionTrackingRef = React.useRef(null);
if (!reactionTrackingRef.current) {
const reaction = new Reaction(`observer`, () => {
forceUpdate();
});
reactionTrackingRef.current = { reaction };
}
const { reaction } = reactionTrackingRef.current;
useEffect(() => {
return () => {
reactionTrackingRef.current.reaction.dispose();
reactionTrackingRef.current = null;
}
},[]);
let rendering;
reaction.track(() => {
rendering = fn();
});
return rendering;
}
export function Observer({ children }) {
return useObserver(children);
}
+export function observer(baseComponent, options) {
+ let useForwardRef = options?.forwardRef ?? false;
+ let observerComponent = (props, ref) => {
+ return useObserver(() => baseComponent(props, ref));
+ };
+ if (useForwardRef) {
+ observerComponent = forwardRef(observerComponent);
+ }
+ return memo(observerComponent);
+}
src\main.jsx
import { createRoot } from "react-dom/client";
import Counter from "./Counter";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(<Counter value={5}/>);
src\Counter.jsx
import React from 'react';
+import {useObserver,useLocalObservable} from 'mobx-react';
export default function (props) {
+ const store = useLocalObservable(()=>({
+ number:props.value,
+ add(){
+ this.number++;
+ },
+ get double(){
+ return this.number*2;
+ }
+ }));
return useObserver(()=>(
<div>
<p>{store.number}</p>
<button onClick={store.add}>+</button>
<p>{store.double}</p>
</div>
));
};
src\mobx-react\index.jsx
import React,{useEffect,forwardRef,memo,useState} from 'react';
import { Reaction,observable } from 'mobx';
import { runInAction } from 'mobx';
export function useObserver(fn) {
const [, setState] = React.useState();
const forceUpdate = () => setState({});
const reactionTrackingRef = React.useRef(null);
if (!reactionTrackingRef.current) {
const reaction = new Reaction(`observer`, () => {
forceUpdate();
});
reactionTrackingRef.current = { reaction };
}
const { reaction } = reactionTrackingRef.current;
useEffect(() => {
return () => {
reactionTrackingRef.current.reaction.dispose();
reactionTrackingRef.current = null;
}
},[]);
let rendering;
reaction.track(() => {
rendering = fn();
});
return rendering;
}
export function Observer({ children }) {
return useObserver(children);
}
export function observer(baseComponent, options) {
let useForwardRef = options?.forwardRef ?? false;
let observerComponent = (props, ref) => {
return useObserver(() => baseComponent(props, ref));
};
if (useForwardRef) {
observerComponent = forwardRef(observerComponent);
}
return memo(observerComponent);
}
+export function useLocalObservable(initializer){
+ return useState(() => observable(initializer(), {}, { autoBind: true }))[0];
+}
src\Counter.jsx
import React from 'react';
import {makeAutoObservable} from 'mobx';
import {observer} from './mobx-react';
class Store {
number = 1
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
add() {
this.number++;
}
}
let store = new Store();
@observer
class Counter extends React.Component{
render(){
return (
<div>
<p>{store.number}</p>
<button onClick={store.add}>+</button>
</div>
)
}
}
export default Counter;
src\mobx-react\index.jsx
import React,{useEffect,forwardRef,memo,useState,Component} from 'react';
import { Reaction,observable } from 'mobx';
export function useObserver(fn) {
const [, setState] = React.useState();
const forceUpdate = () => setState({});
const reactionTrackingRef = React.useRef(null);
if (!reactionTrackingRef.current) {
const reaction = new Reaction(`observer`, () => {
forceUpdate();
});
reactionTrackingRef.current = { reaction };
}
const { reaction } = reactionTrackingRef.current;
useEffect(() => {
return () => {
reactionTrackingRef.current.reaction.dispose();
reactionTrackingRef.current = null;
}
},[]);
let rendering;
reaction.track(() => {
rendering = fn();
});
return rendering;
}
export function Observer({ children }) {
return useObserver(children);
}
export function observer(baseComponent, options) {
+ if(baseComponent.prototype.isReactComponent){
+ return makeClassComponentObserver(baseComponent);
+ }
let useForwardRef = options?.forwardRef ?? false;
let observerComponent = (props, ref) => {
return useObserver(() => baseComponent(props, ref));
};
if (useForwardRef) {
observerComponent = forwardRef(observerComponent);
}
return memo(observerComponent);
}
+export function makeClassComponentObserver(componentClass){
+ const target = componentClass.prototype
+ const originalRender = target.render
+ target.render = function () {
+ const boundOriginalRender = originalRender.bind(this)
+ const reaction = new Reaction(`render`, () => Component.prototype.forceUpdate.call+(this))
+ let rendering;
+ reaction.track(() => {
+ rendering = boundOriginalRender();
+ })
+ return rendering
+ }
+ return componentClass
+}
export function useLocalObservable(initializer){
return useState(() => observable(initializer(), {}, { autoBind: true }))[0];
}