use 'run' to load model configuration, use 'register' to decorate class component, or use 'useConcent' to decorate function component.
no [Provider] any more, the decorated component can be interactive with store by [setState] directly.
except state, you can also define reducer、computed、watch and init optionally to cover all your scene.
your can consume multi model data with state key level dependency.
except setState, you can also use dispatch or invoke to change state, separate your business logic and ui completely.
support ref level computed 、watch、emit&on、setup etc.
no matter class component or function component, they can enjoy the same api call.
working based on dependency mark、ref collection and state broadcast,built-in renderKey、lazyDispatch、delayBroadcast feature.
use reverse inheritance strategy for class component by default, to let your react dom tree keep clean.
allow user customize middleware to intercept data changing behavior to do something else, allow user customize plugin to enhance concent ability.
allow user call configure api to configure you model definition, that means you can publish your component to npm with model.
allow user clone new model by existed model, to meet the abstract factory need.
npm install concent --save
//or
yarn add concent
import { run, useConcent } from "concent";
run();// startup concent
const setup = ctx => {
const { initState, computed, watch, setState } = ctx;
// init ref state
initState({ count: 0 });
// defined a computed fn, here dep is count,
// only count value changed will trigger this computed fn execute again
computed("doubleCount", n => n.count * 2);
// defined a watch fn, here dep is count,
// only count value changed will trigger this watch fn execute again
watch("count", (n, o) => alert(`from ${o.count} to ${n.count}`));
// return packed methods, they will been collected to ctx.settings
return {
inc: () => setState({ count: ctx.state.count + 1 }),
dec: () => setState({ count: ctx.state.count - 1 })
};
};
function Counter(){
// deconstruct from ref ctx
const { state, refComputed, settings } = useConcent({ setup });
return (
<>
<h1>{state.count}</h1>
<h1>{refComputed.doubleCount}</h1>
<button onClick={settings.inc}>inc</button>
<button onClick={settings.dec}>dec</button>
</>
);
}
import { run, useConcent } from "concent";
const delay = (ms = 1000) => new Promise(r => setTimeout(r, ms));
run({// startup concent with module configuration counter: {
state: { count: 0 },// 【neccessary】,define module state
reducer: {
async complexUpdate(p, m, ac) {
await delay();
await ac.setState({ count: m.count + 10 });
await delay();
return { count: m.count + 10 };
},
simpleUpdate(p, m) {
return { count: m.count - 100 };
}
},
computed: {// 【optional】,define module computed
doubleCount: n => n.count * 2,
quadrupleCount: (n, o, f) => f.cuVal.doubleCount * 2,
},
watch: {// 【optional】,define module watch
count: (n, o) => alert(`from ${o.count} to ${n.count}`)
}
}
});
const setup = ctx => {
return {
inc: () => ctx.setState({ count: ctx.state.count + 1 }),
dec: () => ctx.setState({ count: ctx.state.count - 1 })
};
};
function Counter() {
const { state, moduleComputed, moduleReducer, settings } =
useConcent({ setup, module: "counter" });
return <div> ui ... </div>
}
@register({ setup, module: "counter" })
class ClassCounter extends React.Component{
render(){
const { state, moduleComputed, moduleReducer, settings } = this.ctx;
return <div> ui ... </div>
}
}