mobdux
v2.0.5
Published
A collection of utilities for using a redux-like architecture with mobx
Downloads
6
Readme
mobdux
A collection of utilities for using redux-like smart/dumb components with Mobx. You can watch the video explaining the inspiration of the library here and read the medium article explaining the approach in more detail here.
connect(mapStoresToProps: (stores, ownProps, context) => injectedProps)
A higher-order-component used to connect a 'dumb' React component to the Mobx stores
that have been injected onto your React context using the <Provider>
component from mobx-react
. In the mapStoresToProps
function, you can additionally wire up your 'dumb' components callbacks to their corresponding @action
s
It is a thin wrapper around the inject
higher-order-function that additionally unboxes any observables into plain javascript objects and primitives.
normalizeArray<T>(array: T[], key: string) => { [key: string]: T }
A utitlity for normalizing an array of objects by indexing them according to their key
.
Examples
counter-store.ts
import { normalizeArray } from 'mobdux';
import { action, computed, observable } from 'mobx';
type Counter = {
count: number,
id: string,
};
export default class Counters {
@observable counters: Counter[] = [
{ id: 'counter-1', count: 100 },
{ id: 'counter-2', count: 200 },
{ id: 'counter-3', count: 300 },
];
@computed get ids() {
return this.counters.map(counter => counter.id);
}
@computed get byId() {
return normalizeArray(this.counters, 'id');
}
@action addCounter = () => {
this.counters.push({
count: 0,
id: `counter-${this.counters.length + 1}`,
});
}
@action increment = (id: string) => {
this.byId[id].count++;
}
}
app.tsx
import { useStrict } from 'mobx';
import { Provider } from 'mobx-react';
import * as React from 'react';
import { createStores } from './stores';
import CounterList from './view/counter-list';
// enable mobx strict mode. State mutation can only happen in actions
useStrict(true);
const stores = createStores();
const App = () => (
<Provider {...stores}>
<CounterList />
</Provider>
);
export default App;
counter-list.tsx
import { connect } from 'mobdux';
import * as React from 'react';
import Stores from '../stores/';
import Counter from './counter';
type InjectedProps = {
counterIds: string[],
onAddCounter: () => void,
};
const CounterList = ({ counterIds, onAddCounter }: InjectedProps) => (
<div>
{counterIds && counterIds.map(id => (
<Counter id={id} key={id} />
))}
<button onClick={onAddCounter}>Add a counter</button>
</div>
);
export default connect(
(stores: Stores): InjectedProps => ({
counterIds: stores.counters.ids,
onAddCounter: stores.counters.addCounter,
}),
)(CounterList);
counter.tsx
import { connect } from 'mobdux';
import * as React from 'react';
import Stores from '../stores';
type OwnProps = {
id: string,
};
type InjectedProps = {
value: number,
onClick: () => void,
};
type Props = OwnProps & InjectedProps;
const Counter = ({ onClick, value }: Props) => (
<div>
<button onClick={onClick}>+</button>
value: {value}
</div>
);
export default connect(
(stores: Stores, ownProps: OwnProps): InjectedProps => ({
value: stores.counters.byId[ownProps.id].count,
onClick: () => stores.counters.increment(ownProps.id),
}),
)(Counter);