react生命周期函数_如何优雅的消灭掉react生命周期函数
開源不易,感謝你的支持,? star concent^_^
序言
在react應(yīng)用里,存在一個頂層組件,該組件的生命周期很長,除了人為的調(diào)用unmountComponentAtNode接口來卸載掉它和用戶關(guān)閉掉瀏覽器tab頁窗口,該頂層組件是不會有被銷毀的時機(jī)的,它一直伴隨著整個應(yīng)用,所以我們都會在該組件的componentDidMount函數(shù)里發(fā)起一些請求來獲取服務(wù)器端的配置型數(shù)據(jù)并緩存起來,方便整個應(yīng)用全局使用。
對于由路由系統(tǒng)掛載的頁面組件,我們通常也會在它的componentDidMount函數(shù)里發(fā)起請求來獲取該頁面,如果狀態(tài)是由store管理的(如redux、或者mobx),若需要在頁面組件的卸載的時候清理相應(yīng)的store狀態(tài),則還會選擇在componentWillUnmount里調(diào)用相應(yīng)的方法做清理。
當(dāng)然了,對于函數(shù)組件來說使用useEffect鉤子函數(shù)做起來就一步到位,比起類組件顯得更簡單
function PageComp(){useEffect(()=>{/** 等效于 componentDidMount 發(fā)起請求調(diào)用 */return ()=>{/** 等效于 componentWillUnmount 做相應(yīng)的清理 */}}, []) }當(dāng)前生命周期函數(shù)的使用體驗
那本文題目提到的消滅生命周期又作何解釋呢?看起來沒有了它們我們是無法完成類似需求的,在對此作出解釋之前,我們先列舉一下現(xiàn)在的生命周期的使用體驗問題。
無法共用一套邏輯
類組件和函數(shù)組件是無法做到0修改共用一套邏輯的,類組件在未來的很長一段時間內(nèi)都將一直存在,這是我們無法避免的問題,但類組件和函數(shù)組件的設(shè)計理念導(dǎo)致它們的生命周期函數(shù)使用方式是完全不同的,所以共享邏輯需要一定的改造
初始化流程和組件耦合在一起
已提升到store的狀態(tài)的初始化流程卻還是和組件耦合在一起,這一點(diǎn)一定要注意一個前提,就是我們通常在頂層組件的生命周期函數(shù)里完成store的某個節(jié)點(diǎn)的狀態(tài)初始化,不管是根組件還是頁面組件,它們都具有頂層組件的性質(zhì),但是把store某節(jié)點(diǎn)的狀態(tài)初始化流程寫在組件里會帶來一些額外的問題, - 如果另一個頁面組件也需要使用該節(jié)點(diǎn)數(shù)據(jù)時,需要額外的檢查狀態(tài)有沒有初始化好 - 當(dāng)重構(gòu)頂層組件的時候要小心翼翼的維護(hù)好這些聲明周期邏輯
接下里讓我們看看在concent里是如何處理這些問題并消滅掉生命周期函數(shù)的呢。
使用組合api統(tǒng)一邏輯
雖然類組件和函數(shù)的生命周期聲明方式和使用方式完全不一樣,但是我們可以依靠組合api來抹掉這層差異,達(dá)到讓類組件和函數(shù)組件都真正的只充當(dāng)ui載體的目的
假設(shè)有以下兩個自管理狀態(tài)的組件,他們都具有相同的功能,一個是類組件
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 */} }一個是函數(shù)組件
// 函數(shù)組件 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 */ }兩者看起來完完全全不一樣,且函數(shù)組件里為了消除useEffect依賴缺失警告還是用useRef來固定住目標(biāo)值,這些比較燒腦的操作對于新用戶來說是非常大的障礙。
接下來我們看看基于setup的組合api如何來解除這些障礙,setup是一個普通的函數(shù),僅提供一個參數(shù)代表當(dāng)前的渲染上下文,并支持返回一個新的對象(通常都是一堆方法集合),該對象能夠通過settings在渲染塊內(nèi)獲取到,裝配了setup函數(shù)的組件在實(shí)例化時,僅被觸發(fā)執(zhí)行一次,所以我們可以看看上述示例改造后,會變?yōu)?#xff1a;
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);}}; }接著在類組件里和函數(shù)組件里,都可通過渲染上下文ctx拿到數(shù)據(jù)和方法
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消除生命周期
當(dāng)我們的頁面組件狀態(tài)提升到模塊里時,我們可以使用lifecyle.mounted和lifecyle.willUnmount來徹底解耦生命周期和組件的關(guān)系了,concent內(nèi)部會維護(hù)一個模塊對應(yīng)下的實(shí)例計數(shù)器,所以依靠這個功能可以精確控制模塊狀態(tài)的初始化時機(jī)了。
lifecyle.mounted
當(dāng)前模塊的第一個實(shí)例掛載完畢時觸發(fā),且僅觸發(fā)一次,即當(dāng)該模塊的所有實(shí)例都銷毀后,再次有一個實(shí)例掛載完畢,也不會觸發(fā)了
run({product: { lifecycle: {mounted: (dispatch)=> dispatch('initState')} } })如需反復(fù)觸發(fā),即只要滿足模塊的實(shí)例數(shù)從0到1時就觸發(fā),返回false即可
lifecyle.willUnmount
當(dāng)前模塊的最后一個實(shí)例將銷毀時觸發(fā),且僅觸發(fā)一次,即當(dāng)該模塊再次生成了很多實(shí)例,然后又全部銷毀,也不會觸發(fā)了
run({counter: { lifecycle: {willUnmount: dispatch=> dispatch('clearModuleState'),} } })同樣的如需反復(fù)觸發(fā),即只要滿足模塊的實(shí)例數(shù)從有變?yōu)?時就觸發(fā),返回false即可
lifecyle.loaded
如果該模塊的狀態(tài)和有無組件掛載無關(guān)系,則直接配置loaded即可
run({counter: { lifecycle: {loaded: (dispatch)=> dispatch('initState'),} } })改造示例
介紹完lifecyle,我們來看看改造上述函數(shù)組件和類組件后的實(shí)例長為什么樣,首先我們定義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模塊即可,組件實(shí)例就可以調(diào)用product模塊的方法和讀取它的數(shù)據(jù)了。
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,是因為我們不需要額外定義方法和數(shù)據(jù)了,當(dāng)我們需要為組件定義一些非模塊的方法和數(shù)據(jù)時,依然可以定義setup
function setup(ctx) {const { initState, setState, state, effect } = ctx;initState({ xxxx: 'hey i am private' });effect(()=>{// 等效于useEffect里,當(dāng)xxxx改變時執(zhí)行此副作用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 }結(jié)語
綜上所述,我們可以看到其實(shí)并沒有消滅生命周期函數(shù),而是轉(zhuǎn)移并統(tǒng)一了生命周期函數(shù)的定義入口,讓其和組件的定義徹底分離,這樣無論我們怎樣重構(gòu)組件代碼,都不怕動到整個模塊狀態(tài)的初始化流程。
附錄
和本期主題相近的其他文章
- 初識組合api
- recoil vs concent
CloudBase CMS
歡迎小哥哥們來撩CloudBase CMS ,打造一站式云端內(nèi)容管理系統(tǒng),它是云開發(fā)推出的,基于 Node.js 的 Headless 內(nèi)容管理平臺,提供了豐富的內(nèi)容管理功能,安裝簡單,易于二次開發(fā),并與云開發(fā)的生態(tài)體系緊密結(jié)合,助力開發(fā)者提升開發(fā)效率。
concent已為其管理后臺提供強(qiáng)力支持,新版的管理界面更加美觀和體貼了。FFCreator
也歡迎小哥哥們來撩FFCreator,它是一個基于node.js的輕量、靈活的短視頻加工庫。您只需要添加幾張圖片或視頻片段再加一段背景音樂,就可以快速生成一個很酷的視頻短片。
FFCreator是一種輕量又簡單的解決方案,只需要很少的依賴和較低的機(jī)器配置就可以快速開始工作。并且它模擬實(shí)現(xiàn)了animate.css90%的動畫效果,您可以輕松地把 web 頁面端的動畫效果轉(zhuǎn)為視頻,真的很給力。總結(jié)
以上是生活随笔為你收集整理的react生命周期函数_如何优雅的消灭掉react生命周期函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 好听又简单的女生网名121个
- 下一篇: redis desktop manage