Last Updated 2021-02-15 18:18:95
初体验
以下代码片段将展示concent slogan里的特性,方便你快速了解它与其它状态管理的巨大差异。
0入侵
使用concent,可以在你原始react组件一行代码不改动的情况下,直接接入状态管理。
❤️0入侵
启动concent,载入模块配置
import { run } from 'concent';
run({
counter: {//定义counter模块
state: { count: 1 },//state定义,必需
},
})
定义类组件
import { register } from 'concent';
//注册成为Concent Class组件,指定其属于counter模块
@register('counter')
class CounterComp extends Component {
render() {
const { count } = this.state;
return (
<div>
count: {count}
<button onClick={() => this.setState({count: count+1})}>inc</button>
<button onClick={() => this.setState({count: count-1})}>dec</button>
</div>
);
}
}
定义函数组件
import { useConcent } from 'concent';
function CounterFnComp() {
const { state, setState } = useConcent('counter');
return (
<div>
count: {state.count}
<button onClick={() => setState({count: state.count+1})}>inc</button>
<button onClick={() => setState({count: state.count-1})}>dec</button>
</div>
);
}
代码0改动接入concent
渐进式
得益于concent灵活的api设计,允许你逐步的解耦渲染逻辑与业务逻辑,让组件保持只输出视图的最小职责,彻底提高代码的可阅读性与可维护性。
🌟渐进式
新增reducer定义
import { run } from 'concent';
run({
counter: {//定义counter模块
state: { count: 1 },//state定义,必需
reducer: {//reducer函数定义,可选
inc(payload, moduleState) {
return { count: moduleState.count + 1 }
},
dec(payload, moduleState) {
return { count: moduleState.count - 1 }
}
},
},
})
通过dispatch 或 moduleReducer 修改状态
import { register } from 'concent';
//注册成为Concent Class组件,指定其属于counter模块
@register('counter')
class CounterComp extends Component {
// 替代dispatch字符串方式的调用, this.ctx.dispatch('inc')
inc = ()=> this.ctx.mr.inc();
dec = ()=> this.ctx.mr.dec();
render() {
//ctx是concent为所有组件注入的上下文对象,携带为react组件提供的各种新特性api
return (
<div>
count: {this.state.count}
<button onClick={this.inc}>inc</button>
<button onClick={this.dec}>dec</button>
</div>
);
}
}
逐步解耦业务逻辑与ui渲染
高性能
基于运行时的依赖收集机制,同时配合内置的
renderKey
、lazyDispatch
、delayBroadcast
等特性,从状态提交那一刻,concent就精确的知道怎么样缩小渲染范围、减少渲染次数、降低渲染频率,保证大型react工程的极致的渲染效率。
⚡️高性能
renderKey
缩小长列表渲染范围
lazyDispatch
减小渲染次数
delayBroadcast
降低渲染频率
增强react
有了实例上线文
ctx
,配合setup
特性,concent可以非常从容自然的增强react组件功能,离开这些功能你依然能够开发react应用,但用上这些功能能你拥抱更好的开发范式,全面提升大型react工程的编码优化度和架构体验。
setup
是针对组件实例提供的一个非常重要的特性,在类组件和函数组件里都能够被使用,它会在组件首次渲染之前会被触发执行一次,其返回结果收集在ctx.settings
里,之后便不会再被执行,所以可以在其中定义实例computed
、实例watch
、实例effect
等钩子函数,同时也可以自定义其他的业务逻辑函数并返回,方便组件使用。 利用setup只执行一次的特性,可以让函数组件省去重复渲染期间,重复生成临时闭包函数,同时需要手动调用useCallback
等辅助优化函数
🛠增强react
实例computed、watch、effect、emit&on etc...
import { run, useConcent } from 'concent';
run({
counter: {//定义counter模块
state: {//【必需】定义state
count: 1,
msg: '',
},
reducer: {//【可选】定义reducer,解耦业务逻辑与ui渲染
inc(num, moduleState, actionCtx) {
return { count: moduleState.count + num };
},
changeMsg(msg, moduleState, actionCtx) {
return { msg };
},
async complexInc(num, moduleState, actionCtx) {
await api.track('inc');
actionCtx.dispatch('inc', inc);
actionCtx.dispatch('changeMsg', 'call complexInc');
}
},
computed: {//【可选】定义模块计算函数
count: count => count * 2,
// 收集到此函数的依赖为 ['count', 'msg']
autoDep:(newState, oldState, fnCtx) => {
const { count, msg } = newState;
const { changed } = fnCtx;
return `${changed.join(',')} changed, count ${count}, msg ${msg}`
},
manualDep: {
fn: (newState, oldState, fnCtx) => {
const { changed } = fnCtx;
return `${changed.join(',')} changed`
},
// 人工标记依赖为 ['count', 'msg'],不管函数体有没有用到这些值,只要它们改变了就触发此计算函数
depKeys: ['count', 'msg'],
}
},
watch: {//【可选】定义模块观察函数
count: (count, oldVal) => console.log(`old ${oldVal} new ${count}`),
anyOneChange: {
fn: (newState, oldState, fnCtx) => {
console.log(`${changed.join(',')} changed`);
},
depKeys: ['count', 'msg'],
}
},
init: async () => {//【可选】异步的初始化模块状态
const data = await api.fetchData();
return data;
}
},
})
const setup = ctx => {
//count变化时的副作用函数,第二位参数可以传递多个值,表示任意一个发生变化都将触发此副作用
ctx.effect(() => {
console.log('count changed');
}, ['count']);
//每一轮渲染都会执行
ctx.effect(() => {
console.log('trigger every render');
});
//仅首次渲染执行的副作用函数
ctx.effect(() => {
console.log('trigger only first render');
}, []);
//定义实例computed,因每个实例都可能会触发,优先考虑模块computed
ctx.computed('count', ({count}, oldState, fnCtx) => {
return count * 2;
});
//定义实例watch,区别于effect,执行时机是在组件渲染之前
//因每个实例都可能会触发,优先考虑模块watch
ctx.watch('count', ({count}, oldState, fnCtx) => {
//发射事件
ctx.emit('countChanged', newVal);
api.track(`count changed to ${newVal}`);
});
//定义事件监听,concent会在实例销毁后自动将其off掉
ctx.on('changeCount', count => {
ctx.setState({ count });
});
return {
inc: () => ctx.dispatch('inc', ctx.state.count + 1),
complexInc: () => ctx.dispatch('complexInc', ctx.state.count + 1),
};
}
const iState = { privCount: 0 };//此state相当于组件的私有状态
function HookFnComp() {
const {
state: { privCount, count, msg }, settings: { inc, dec, incStoreCount, decStoreCount }
} = useConcent({ module: 'counter', setup, state: iState });
return (
<div>
count: {count}
msg: {msg}
privCount: {privCount}
<button onClick={inc}>+</button>
<button onClick={complexInc}>+</button>
</div>
);
}