网站建设与制作价格,哪个网站可以做危险化学品供求,网页图片下载不了怎么办,团员团干部如何登录到系统开源不易#xff0c;感谢你的支持#xff0c;❤ star concent^_^序言在react应用里#xff0c;存在一个顶层组件#xff0c;该组件的生命周期很长#xff0c;除了人为的调用unmountComponentAtNode接口来卸载掉它和用户关闭掉浏览器tab页窗口#xff0c;该顶层组件是不会…开源不易感谢你的支持❤ star concent^_^序言在react应用里存在一个顶层组件该组件的生命周期很长除了人为的调用unmountComponentAtNode接口来卸载掉它和用户关闭掉浏览器tab页窗口该顶层组件是不会有被销毁的时机的它一直伴随着整个应用所以我们都会在该组件的componentDidMount函数里发起一些请求来获取服务器端的配置型数据并缓存起来方便整个应用全局使用。对于由路由系统挂载的页面组件我们通常也会在它的componentDidMount函数里发起请求来获取该页面如果状态是由store管理的如redux、或者mobx若需要在页面组件的卸载的时候清理相应的store状态则还会选择在componentWillUnmount里调用相应的方法做清理。当然了对于函数组件来说使用useEffect钩子函数做起来就一步到位比起类组件显得更简单function PageComp(){useEffect((){/** 等效于 componentDidMount 发起请求调用 */return (){/** 等效于 componentWillUnmount 做相应的清理 */}}, [])
}
当前生命周期函数的使用体验那本文题目提到的消灭生命周期又作何解释呢看起来没有了它们我们是无法完成类似需求的在对此作出解释之前我们先列举一下现在的生命周期的使用体验问题。无法共用一套逻辑类组件和函数组件是无法做到0修改共用一套逻辑的类组件在未来的很长一段时间内都将一直存在这是我们无法避免的问题但类组件和函数组件的设计理念导致它们的生命周期函数使用方式是完全不同的所以共享逻辑需要一定的改造初始化流程和组件耦合在一起已提升到store的状态的初始化流程却还是和组件耦合在一起这一点一定要注意一个前提就是我们通常在顶层组件的生命周期函数里完成store的某个节点的状态初始化不管是根组件还是页面组件它们都具有顶层组件的性质但是把store某节点的状态初始化流程写在组件里会带来一些额外的问题 - 如果另一个页面组件也需要使用该节点数据时需要额外的检查状态有没有初始化好 - 当重构顶层组件的时候要小心翼翼的维护好这些声明周期逻辑接下里让我们看看在concent里是如何处理这些问题并消灭掉生命周期函数的呢。使用组合api统一逻辑虽然类组件和函数的生命周期声明方式和使用方式完全不一样但是我们可以依靠组合api来抹掉这层差异达到让类组件和函数组件都真正的只充当ui载体的目的假设有以下两个自管理状态的组件他们都具有相同的功能一个是类组件class ClsPageComp extends React.Component{state {list: [],page: 1,};componentDidMount(){fetchData();}componentWillUnmount(){/** clear up */}fetchData () {const { page } this.state;fetch(xxxx, { page }).then(list this.setState({ list }))}nextPage () {this.setState({ page: this.page 1 }, this.fetchData);}render() {/** ui logic */}
}
一个是函数组件// 函数组件
function PageComp() {const [list, setList] useState([]);const [page, setPage] useState(1);const pageRef useRef(page);pageRef.current page;const fetchData (page) {// fetch(xxxx, { page }).then((list) setList(list));};const nextPage () {const p page 1;setPage(p);fetchData(p);};useEffect(() {fetchData(pageRef.current);return () {/** clear up */};}, []);/** ui logic */
}
两者看起来完完全全不一样且函数组件里为了消除useEffect依赖缺失警告还是用useRef来固定住目标值这些比较烧脑的操作对于新用户来说是非常大的障碍。接下来我们看看基于setup的组合api如何来解除这些障碍setup是一个普通的函数仅提供一个参数代表当前的渲染上下文并支持返回一个新的对象通常都是一堆方法集合该对象能够通过settings在渲染块内获取到装配了setup函数的组件在实例化时仅被触发执行一次所以我们可以看看上述示例改造后会变为function setup(ctx) {const { initState, setState, state, effect } ctx;initState({ list: [], page: 0 });const fetchData (page) {fetch(xxxx, { page }).then(list setState({ list }))};effect((){fetchData(state.page);return (){/** clear up */};}, []);return {nextPage: () {const p page 1;setState({ page: p });fetchData(p);}};
}
接着在类组件里和函数组件里都可通过渲染上下文ctx拿到数据和方法import { register, useConcent } from concent;register({ setup })
class ClsComp extends React.Component {render() {const { state: { page, list }, settings: { nextPage } } this.ctx;// ui logic}
}function PageComp() {const {state: { page, list }, settings: { nextPage },} useConcent({ setup });// ui logic
}
使用lifecyle消除生命周期当我们的页面组件状态提升到模块里时我们可以使用lifecyle.mounted和lifecyle.willUnmount来彻底解耦生命周期和组件的关系了concent内部会维护一个模块对应下的实例计数器所以依靠这个功能可以精确控制模块状态的初始化时机了。lifecyle.mounted当前模块的第一个实例挂载完毕时触发且仅触发一次即当该模块的所有实例都销毁后再次有一个实例挂载完毕也不会触发了run({product: { lifecycle: {mounted: (dispatch) dispatch(initState)} }
})
如需反复触发即只要满足模块的实例数从0到1时就触发返回false即可lifecyle.willUnmount当前模块的最后一个实例将销毁时触发且仅触发一次即当该模块再次生成了很多实例然后又全部销毁也不会触发了run({counter: { lifecycle: {willUnmount: dispatch dispatch(clearModuleState),} }
})
同样的如需反复触发即只要满足模块的实例数从有变为0时就触发返回false即可lifecyle.loaded如果该模块的状态和有无组件挂载无关系则直接配置loaded即可run({counter: { lifecycle: {loaded: (dispatch) dispatch(initState),} }
})
改造示例介绍完lifecyle我们来看看改造上述函数组件和类组件后的实例长为什么样首先我们定义product模块import { run } from concent;run({product: {state: { list: [], page: 1 },reducer: {async initState() {/** init state logic */},clearState() {/** clear state logic */},async nextPage(payload, moduleState, ac) {const p moduleState.page 1;await ac.setState({ paeg: p });const list await fetch(xxxx, { page: p });return { list };}},lifecycle: {mounted: dispatch dispatch(initState),willUnmount: dispatch dispatch(clearState),}}
});
接着我们注册组件属于product模块即可组件实例就可以调用product模块的方法和读取它的数据了。import { register, useConcent } from concent;register({ module: product })
class ClsComp extends React.Component {render() {const { state: { page, list }, mr: { nextPage } } this.ctx;// ui logic}
}function PageComp() {const {state: { page, list }, mr: { nextPage },} useConcent({ module: product });// ui logic
}
我们可以看到此时已没有了setup是因为我们不需要额外定义方法和数据了当我们需要为组件定义一些非模块的方法和数据时依然可以定义setupfunction setup(ctx) {const { initState, setState, state, effect } ctx;initState({ xxxx: hey i am private });effect((){// 等效于useEffect里当xxxx改变时执行此副作用console.log(state.xxxx);}, [xxxx]);return {changeXXX: (e) setState({xxxx: e.target.value}),};
}
然后组件装配setup即可import { register, useConcent } from concent;register({ module: product, setup })
class ClsComp extends React.Component {render() {const { state: { page, list }, mr: { nextPage }, settings } this.ctx;// ui logic}
}function PageComp() {const {state: { page, list }, mr: { nextPage }, settings,} useConcent({ module: product, setup });// ui logic
}
结语综上所述我们可以看到其实并没有消灭生命周期函数而是转移并统一了生命周期函数的定义入口让其和组件的定义彻底分离这样无论我们怎样重构组件代码都不怕动到整个模块状态的初始化流程。附录和本期主题相近的其他文章初识组合apirecoil vs concentCloudBase CMS欢迎小哥哥们来撩CloudBase CMS 打造一站式云端内容管理系统它是云开发推出的基于 Node.js 的 Headless 内容管理平台提供了丰富的内容管理功能安装简单易于二次开发并与云开发的生态体系紧密结合助力开发者提升开发效率。concent已为其管理后台提供强力支持新版的管理界面更加美观和体贴了。FFCreator也欢迎小哥哥们来撩FFCreator它是一个基于node.js的轻量、灵活的短视频加工库。您只需要添加几张图片或视频片段再加一段背景音乐就可以快速生成一个很酷的视频短片。FFCreator是一种轻量又简单的解决方案只需要很少的依赖和较低的机器配置就可以快速开始工作。并且它模拟实现了animate.css90%的动画效果您可以轻松地把 web 页面端的动画效果转为视频真的很给力。