Managing React State with Proxily

import {observable} from 'proxily';class Counter {
count = 0;
increment () {
this.count++;
}
}
export const state = observable(new Counter()); // Make it observable
import {observer} from 'proxily';
import {state} from 'counter';
function App() {
const {count, increment} = state; // Use your state
return (
<div>
<span>Count: {count}</span>
<button onClick={increment}>Increment</button>
</div>
);
};
export default observer(App); // Make your component an observer

Actions

const {count, increment} = state;  // Destructure increment works!
<button onClick={increment}>Increment</button>

Selectors

import {observable, observer} from 'proxily';class NameList {
names = [];
get sortedNames() { // selector
this.names.slice(0).sort();
}

}
const nameList = observable(new NameList());
import {cache} from 'proxily';memoize(NameList, p => p.sortedNames);
function List () {
const {sortedNames} = nameList;
return (<> {sortedNames.map(n => <Name name={n} />} </>)
}
export default observer(List);

Everything in the Box

  • Automatic persistence of complex state
  • Integration with Redux-devtools and Redux-sagas
  • State branching with undo, redo, commit and rollback
  • Immutable snapshots
  • Support for suspense, transitions and deferred values in React 18+

Persistence & Serialization

serializable({Counter});
const state = observable(new Counter());
const state = persist(new Counter());

When You Need Immutable Data

const news = observable({
topics: ["politics", "tech", "cooking"],
stories: {}
});
import {useAsImmutable} from 'proxily';function Stories {
useEffect( () => { // Fire query when topics change
axios.get('/getStories?topics=' + news.topics.join(','))
.then((r) => news.stories = r.toJSON());
}, [useAsImmutable(news.topics)]); // Immutable snapshot
// Render news.stories
}
export default observable(MyComponent);

Debugging

Testing

const counter = new Counter();
counter.increment();
expect(counter.value).toBe(1);
function MyCounter({counter} : {counter : Counter}) {
const {value, increment} = counter;
return (
<div>
<span>Count: {value}</span>
<button onClick={increment}>Increment</button>
</div>
);
});
export default observer(MyCounter);
const mockState = jestMockFromClass(Counter, {value: 5});
render(<MyCounter counter={mockState} />);
screen.getByText('Increment').click();
expect(mockState.increment).toBeCalled();

How Proxily Works

  1. Make use of common Javascript language features without the need to learn a proprietary usage pattern.
  2. Provide the depth of features that users of mature immutable libraries like Redux have come to expect.

Next Up

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sam Elsamman

Sam Elsamman

Retired technology entrepreneur who loves to hike, travel, cook and write music.