97色伦色在线综合视频,无玛专区,18videosex性欧美黑色,日韩黄色电影免费在线观看,国产精品伦理一区二区三区,在线视频欧美日韩,亚洲欧美在线中文字幕不卡

揚(yáng)州建設(shè)工程信息網(wǎng)站仿騰訊網(wǎng)站源碼

鶴壁市浩天電氣有限公司 2026/01/24 08:44:45
揚(yáng)州建設(shè)工程信息網(wǎng)站,仿騰訊網(wǎng)站源碼,設(shè)計(jì)說(shuō)明ai,網(wǎng)絡(luò)系統(tǒng)集成結(jié)課論文多更新的組件狀態(tài) 在組件狀態(tài)中#xff0c;我們了解到了React中組件的狀態(tài)及其用法。組件狀態(tài)的主要作用就是由狀態(tài)設(shè)置觸發(fā)組件的局部UI渲染#xff0c;狀態(tài)用法也很簡(jiǎn)單。 有時(shí)候有些組件對(duì)于狀態(tài)的更新操作很多#xff0c;這就讓我們很難短時(shí)間理清組件更新邏輯。示例如…多更新的組件狀態(tài)在組件狀態(tài)中我們了解到了React中組件的狀態(tài)及其用法。組件狀態(tài)的主要作用就是由狀態(tài)設(shè)置觸發(fā)組件的局部UI渲染狀態(tài)用法也很簡(jiǎn)單。有時(shí)候有些組件對(duì)于狀態(tài)的更新操作很多這就讓我們很難短時(shí)間理清組件更新邏輯。示例如下獲取初始數(shù)據(jù)后用戶可以對(duì)其進(jìn)行添加、刪除和修改操作。import{useState}fromreact;functionAddTask({onAddTask}){const[text,setText]useState();return(input placeholderAdd taskvalue{text}onChange{esetText(e.target.value)}/button onClick{(){setText();onAddTask(text);}}Add/button/);}functionTaskList({tasks,onChangeTask,onDeleteTask}){return(ul{tasks.map(task(li key{task.id}Task task{task}onChange{onChangeTask}onDelete{onDeleteTask}//li))}/ul);}functionTask({task,onChange,onDelete}){const[isEditing,setIsEditing]useState(false);lettaskContent;if(isEditing){taskContent(input value{task.text}onChange{e{onChange({...task,text:e.target.value})}}/button onClick{()setIsEditing(false)}Save/button/);}else{taskContent({task.text}button onClick{()setIsEditing(true)}Edit/button/);}return(labelinput typecheckboxchecked{task.done}onChange{e{onChange({...task,done:e.target.checked});}}/{taskContent}button onClick{(){onDelete(task.id)}}Delete/button/label);}exportdefaultfunctionTaskApp(){const[tasks,setTasks]useState(initialTasks);functionhandleAddTask(text){setTasks([...tasks,{id:nextId,text:text,done:false,},]);}functionhandleChangeTask(task){setTasks(tasks.map((t){if(t.idtask.id){returntask;}else{returnt;}}));}functionhandleDeleteTask(taskId){setTasks(tasks.filter((t)t.id!taskId));}return(h1布拉格的行程安排/h1AddTask onAddTask{handleAddTask}/TaskList tasks{tasks}onChangeTask{handleChangeTask}onDeleteTask{handleDeleteTask}//);}letnextId3;constinitialTasks[{id:0,text:參觀卡夫卡博物館,done:true},{id:1,text:看木偶戲,done:false},{id:2,text:打卡列儂墻,done:false},];上面的代碼中有三個(gè)不同的事件處理程序來(lái)實(shí)現(xiàn)狀態(tài)數(shù)據(jù)的添加、刪除和修改。這個(gè)組件的每個(gè)事件處理程序都通過(guò)setTasks來(lái)更新?tīng)顟B(tài)。隨著這個(gè)組件的不斷迭代其狀態(tài)邏輯可能也會(huì)越來(lái)越多隨著代碼也會(huì)越變?cè)綇?fù)雜。為了降低這種復(fù)雜度并讓所有邏輯都可以存放在一個(gè)易于理解的地方你可以將這些狀態(tài)邏輯移到組件之外的一個(gè)稱為reducer的函數(shù)中。reducer狀態(tài)管理的另一種方式reducer是React中處理狀態(tài)的另一種方式使用一個(gè)useReducer的Hook來(lái)實(shí)現(xiàn)主要用于管理復(fù)雜的狀態(tài)變化邏輯。功能上與state類似但是代碼形式上有些不同。兩種方式各有優(yōu)劣簡(jiǎn)單狀態(tài)下使用useState管理組件狀態(tài)即可對(duì)于復(fù)雜狀態(tài)下可以嘗試將useState轉(zhuǎn)換為useReducer。至于State的優(yōu)劣和取舍在咱們進(jìn)行一次useSate到useReducer的轉(zhuǎn)換后就能總結(jié)出來(lái)。轉(zhuǎn)換過(guò)程可以分為三步:將設(shè)置狀態(tài)的邏輯修改dispatch的一個(gè)action編寫(xiě)一個(gè)reducer函數(shù)在組件中使用reducer。Step1: 將設(shè)置狀態(tài)的邏輯修改成dispatch的一個(gè)action這一步咱們先移除所有的狀態(tài)設(shè)置邏輯只留下三個(gè)事件處理函數(shù):handleAddTask(text): 在用戶點(diǎn)擊“添加”時(shí)被調(diào)用。handleChangeTask(task): 在用戶切換任務(wù)或點(diǎn)擊“保存”時(shí)被調(diào)用。handleDeleteTask(taskId): 在用戶點(diǎn)擊“刪除”時(shí)被調(diào)用使用reducer管理狀態(tài)與直接設(shè)置狀態(tài)略有不同。它不是通過(guò)設(shè)置狀態(tài)來(lái)告訴React“要做什么”而是通過(guò)事件處理程序dispatch一個(gè)“action” 來(lái)指明 “用戶剛剛做了什么”。而狀態(tài)更新邏輯則保存在其他地方因此我們不再通過(guò)事件處理器直接 “設(shè)置task”而是dispatch一個(gè) “添加/修改/刪除任務(wù)” 的action。這更加符合用戶的思維。functionhandleAddTask(text){dispatch({type:added,id:nextId,text:text,});}functionhandleChangeTask(task){dispatch({type:changed,task:task,});}functionhandleDeleteTask(taskId){dispatch({type:deleted,id:taskId,});}傳遞給dispatch函數(shù)的就叫action這是一個(gè)普通的JavaScript對(duì)象。它的結(jié)構(gòu)是由咱們自主定義的里面可以存儲(chǔ)一些有用的參數(shù)通常情況下它應(yīng)該至少包含可以表明“發(fā)生了什么事情”的信息(上述代碼中的type字段)這個(gè)信息將指導(dǎo)dispatch的函數(shù)去處理狀態(tài)變化。Step2: 編寫(xiě)一個(gè)reducer函數(shù)reducer函數(shù)就是你放置狀態(tài)邏輯的地方。它接受兩個(gè)參數(shù)分別為當(dāng)前state和action對(duì)象并且返回的是更新后的state。functiontasksReducer(tasks,action){switch(action.type){caseadded:{return[...tasks,{id:action.id,text:action.text,done:false,},];}casechanged:{returntasks.map((t){if(t.idaction.task.id){returnaction.task;}else{returnt;}});}casedeleted:{returntasks.filter((t)t.id!action.id);}default:{throwError(未知 action: action.type);}}}由于reducer函數(shù)接受state作為參數(shù)因此你可以 在組件之外聲明它。Step3: 在組件中使用reducer最后咱們需要將上一步實(shí)現(xiàn)的tasksReducer導(dǎo)入到組件中。// 1. 首先從React中導(dǎo)入useReducer// import { useState } from react;import{useReducer}fromreact;// 2. 組件中使用useReducer替換掉useSate// const [tasks, setTasks] useState(initialTasks);const[tasks,dispatch]useReducer(tasksReducer,initialTasks);與useState類似咱們必須給useReducer傳遞一個(gè)初始狀態(tài)它會(huì)返回一個(gè)狀態(tài)值(tasks)和一個(gè)設(shè)置狀態(tài)的函數(shù)(dispatch)。但是useReducer還需要傳入一個(gè)用于處理各種action的函數(shù)(tasksReducer)。最后得到的代碼是這樣的:import{useReducer}fromreact;importAddTaskfrom./AddTask.js;importTaskListfrom./TaskList.js;exportdefaultfunctionTaskApp(){const[tasks,dispatch]useReducer(tasksReducer,initialTasks);functionhandleAddTask(text){dispatch({type:added,id:nextId,text:text,});}functionhandleChangeTask(task){dispatch({type:changed,task:task,});}functionhandleDeleteTask(taskId){dispatch({type:deleted,id:taskId,});}return(h1布拉格的行程安排/h1AddTask onAddTask{handleAddTask}/TaskList tasks{tasks}onChangeTask{handleChangeTask}onDeleteTask{handleDeleteTask}//);}functiontasksReducer(tasks,action){switch(action.type){caseadded:{return[...tasks,{id:action.id,text:action.text,done:false,},];}casechanged:{returntasks.map((t){if(t.idaction.task.id){returnaction.task;}else{returnt;}});}casedeleted:{returntasks.filter((t)t.id!action.id);}default:{throwError(未知 action: action.type);}}}letnextId3;constinitialTasks[{id:0,text:參觀卡夫卡博物館,done:true},{id:1,text:看木偶戲,done:false},{id:2,text:打卡列儂墻,done:false}];現(xiàn)在事件處理函數(shù)只通過(guò)派發(fā)action來(lái)指定發(fā)生了什么而reducer函數(shù)通過(guò)響應(yīng)actions來(lái)決定狀態(tài)如何更新。這樣一來(lái)狀態(tài)修改的全部?jī)?nèi)容就集中到了tasksReducer函數(shù)中了我們也能一眼看出狀態(tài)經(jīng)歷了哪些改變。對(duì)比useState和useReducerReducer并非沒(méi)有缺點(diǎn)以下是比較它們的幾個(gè)方面:代碼體積: 通常在使用useState時(shí)一開(kāi)始只需要編寫(xiě)少量代碼。而useReducer必須提前編寫(xiě)reducer函數(shù)和需要調(diào)度的actioins。但是當(dāng)多個(gè)事件處理程序以相似的方式修改state時(shí)useReducer可以減少代碼量??勺x性: 當(dāng)狀態(tài)更新邏輯足夠簡(jiǎn)單時(shí)useState的可讀性還行。但是一旦邏輯變得復(fù)雜起來(lái)它們會(huì)使組件變得臃腫且難以閱讀。在這種情況下useReducer允許你將狀態(tài)更新邏輯與事件處理程序分離開(kāi)來(lái)??烧{(diào)試性: 當(dāng)使用useState出現(xiàn)問(wèn)題時(shí), 你很難發(fā)現(xiàn)具體原因。而使用useReducer時(shí)你可以在reducer函數(shù)中通過(guò)打印日志的方式來(lái)觀察每個(gè)狀態(tài)的更新以及為什么要更新來(lái)自哪個(gè)action。 如果所有action都沒(méi)問(wèn)題你就知道問(wèn)題出在了reducer本身的邏輯中。 然而與使用useState相比你必須單步執(zhí)行更多的代碼??蓽y(cè)試性:reducer是一個(gè)不依賴于組件的純函數(shù)。這就意味著你可以單獨(dú)對(duì)它進(jìn)行測(cè)試。一般來(lái)說(shuō)我們最好是在真實(shí)環(huán)境中測(cè)試組件但對(duì)于復(fù)雜的狀態(tài)更新邏輯針對(duì)特定的初始狀態(tài)和action斷言reducer返回的特定狀態(tài)會(huì)很有幫助。如果你在修改某些組件狀態(tài)時(shí)經(jīng)常出現(xiàn)問(wèn)題或者想給組件添加更多邏輯時(shí)建議你還是使用reducer。當(dāng)然也不必整個(gè)項(xiàng)目都用reducer這是可以自由搭配的。編寫(xiě)一個(gè)好的reducer編寫(xiě)reducer時(shí)最好牢記以下兩點(diǎn):reducer必須是純粹的。 這一點(diǎn)和狀態(tài)更新函數(shù)是相似的reducer是在渲染時(shí)運(yùn)行的(actions會(huì)排隊(duì)直到下一次渲染)。這就意味著reducer必須純凈即當(dāng)輸入相同時(shí)輸出也是相同的。它們不應(yīng)該包含異步請(qǐng)求、定時(shí)器或者任何副作用(對(duì)組件外部有影響的操作)。它們應(yīng)該以不可變值的方式去更新對(duì)象和數(shù)組。每個(gè)action都描述了一個(gè)單一的用戶交互即使它會(huì)引發(fā)數(shù)據(jù)的多個(gè)變化。舉個(gè)例子如果用戶在一個(gè)由reducer管理的表單(包含五個(gè)表單項(xiàng))中點(diǎn)擊了重置按鈕那么dispatch一個(gè)reset_form的action比dispatch五個(gè)單獨(dú)的set_field的action更加合理。如果你在一個(gè)reducer中打印了所有的action日志那么這個(gè)日志應(yīng)該是很清晰的它能讓你以某種步驟復(fù)現(xiàn)已發(fā)生的交互或響應(yīng)。這對(duì)代碼調(diào)試很有幫助使用Context深層傳遞參數(shù)通常來(lái)說(shuō)咱們會(huì)通過(guò)props將信息從父組件傳遞到子組件。但是如果必須通過(guò)許多中間組件向下傳遞props或是在應(yīng)用中的許多組件需要相同的信息傳遞props會(huì)變得十分冗長(zhǎng)和不便。Context允許父組件向其下層無(wú)論多深的任何組件提供信息而無(wú)需通過(guò)props顯式傳遞。Context翻譯過(guò)來(lái)時(shí)上下文它可以為父組件下面的整個(gè)組件樹(shù)提供數(shù)據(jù)咱們可以將其看成父組件下的一個(gè)全局變量。這是一個(gè)來(lái)自官方手冊(cè)的例子要實(shí)現(xiàn)的是Heading組件接收一個(gè)level參數(shù)來(lái)決定它標(biāo)題尺寸functionHeading({level,children}){switch(level){case1:returnh1{children}/h1;case2:returnh2{children}/h2;case3:returnh3{children}/h3;case4:returnh4{children}/h4;case5:returnh5{children}/h5;case6:returnh6{children}/h6;default:throwError(未知的 levellevel);}}functionSection({children}){return(section classNamesection{children}/section);}exportdefaultfunctionPage(){return(SectionHeading level{1}主標(biāo)題/HeadingHeading level{2}副標(biāo)題/HeadingHeading level{3}子標(biāo)題/HeadingHeading level{4}子子標(biāo)題/HeadingHeading level{5}子子子標(biāo)題/HeadingHeading level{6}子子子子標(biāo)題/Heading/Section);}假設(shè)先要讓相同Section中的多個(gè)Heading具有相同的尺寸對(duì)于這樣一個(gè)復(fù)雜的結(jié)構(gòu)Page組件可能就會(huì)寫(xiě)成這樣:exportdefaultfunctionPage(){return(SectionHeading level{1}主標(biāo)題/HeadingSectionHeading level{2}副標(biāo)題/HeadingHeading level{2}副標(biāo)題/HeadingHeading level{2}副標(biāo)題/HeadingSectionHeading level{3}子標(biāo)題/HeadingHeading level{3}子標(biāo)題/HeadingHeading level{3}子標(biāo)題/HeadingSectionHeading level{4}子子標(biāo)題/HeadingHeading level{4}子子標(biāo)題/HeadingHeading level{4}子子標(biāo)題/Heading/Section/Section/Section/Section);}目前你將level參數(shù)分別傳遞給每個(gè)Heading將level參數(shù)傳遞給Section組件而不是傳給Heading組件看起來(lái)更好一些。這樣的話你可以強(qiáng)制使同一個(gè)section中的所有標(biāo)題都有相同的尺寸Section level{3}Heading關(guān)于/HeadingHeading照片/HeadingHeading視頻/Heading/Section但是Heading組件是如何知道離它最近的Section的level的呢這需要子組件可以通過(guò)某種方式“訪問(wèn)”到組件樹(shù)中某處在其上層的數(shù)據(jù)。這個(gè)功能不能只通過(guò)props來(lái)實(shí)現(xiàn)它。這就是context大顯身手的地方。你可以通過(guò)以下三個(gè)步驟來(lái)實(shí)現(xiàn)它創(chuàng)建一個(gè)context。你可以將其命名為L(zhǎng)evelContext, 因?yàn)樗硎镜氖菢?biāo)題級(jí)別。在需要數(shù)據(jù)的組件內(nèi)使用剛剛創(chuàng)建的context。Heading將會(huì)使用LevelContext。在指定數(shù)據(jù)的組件中提供這個(gè)context。Section將會(huì)提供LevelContext。Context可以讓父節(jié)點(diǎn)甚至是很遠(yuǎn)的父節(jié)點(diǎn)都可以為其內(nèi)部的整個(gè)組件樹(shù)提供數(shù)據(jù)。Step 1: 創(chuàng)建contextContext在調(diào)用前需要在組件外創(chuàng)建甚至可以在單獨(dú)的文件中創(chuàng)建它如果你需要在單獨(dú)文件中創(chuàng)建并將其從一個(gè)文件中導(dǎo)出可以采用如下的代碼:import{createContext}fromreact;exportconstLevelContextcreateContext(1);createContext只需默認(rèn)值這么一個(gè)參數(shù)。在這里,1表示最大的標(biāo)題級(jí)別但是也可以傳遞任何類型的值(甚至可以傳入一個(gè)對(duì)象)。Step 2: 使用Context從React中引入useContext Hook以及你剛剛創(chuàng)建的context:import{useContext}fromreact;import{LevelContext}from./LevelContext.js;刪掉level參數(shù)并從你剛剛引入的LevelContext中讀取值functionHeading({children}){constleveluseContext(LevelContext);switch(level){case1:returnh1{children}/h1;case2:returnh2{children}/h2;case3:returnh3{children}/h3;case4:returnh4{children}/h4;case5:returnh5{children}/h5;case6:returnh6{children}/h6;default:throwError(未知的 levellevel);}}useContext是一個(gè)Hook。和useState以及useReducer一樣你只能在React組件中(不是循環(huán)或者條件里)立即調(diào)用Hook。useContext告訴React Heading組件想要讀取LevelContext?,F(xiàn)在Heading組件沒(méi)有l(wèi)evel參數(shù)你不需要再像這樣在你的JSX中將level參數(shù)傳遞給Heading修改一下JSX讓Section組件代替Heading組件接收l(shuí)evel參數(shù):import{createContext}fromreact;import{useContext}fromreact;constLevelContextcreateContext(1);functionHeading({children}){constleveluseContext(LevelContext);switch(level){case1:returnh1{children}/h1;case2:returnh2{children}/h2;case3:returnh3{children}/h3;case4:returnh4{children}/h4;case5:returnh5{children}/h5;case6:returnh6{children}/h6;default:throwError(未知的 levellevel);}}functionSection({children}){return(section classNamesection{children}/section);}exportdefaultfunctionPage(){return(Section level{1}Heading主標(biāo)題/HeadingSection level{2}Heading副標(biāo)題/HeadingHeading副標(biāo)題/HeadingHeading副標(biāo)題/HeadingSection level{3}Heading子標(biāo)題/HeadingHeading子標(biāo)題/HeadingHeading子標(biāo)題/HeadingSection level{4}Heading子子標(biāo)題/HeadingHeading子子標(biāo)題/HeadingHeading子子標(biāo)題/Heading/Section/Section/Section/Section);}注意這個(gè)示例運(yùn)行起來(lái)還達(dá)不到咱們的預(yù)期。所有Headings的尺寸都一樣因?yàn)?即使你正在使用context但是你還沒(méi)有提供它。如果不提供contextReact會(huì)使用在上一步指定的默認(rèn)值。在這個(gè)例子中為createContext傳入了1這個(gè)參數(shù)所以u(píng)seContext(LevelContext)會(huì)返回1把所有的標(biāo)題都設(shè)置為h1。我們通過(guò)讓每個(gè)Section提供它自己的context來(lái)修復(fù)這個(gè)問(wèn)題。Step 3:提供 contextsection組件目前渲染傳入它的子組件把它們用context provider包裹起來(lái) 以提供LevelContext給它們functionSection({level,children}){return(section classNamesectionLevelContext value{level}{children}/LevelContext/section);}這告訴React“如果在Section組件中的任何子組件請(qǐng)求LevelContext給他們這個(gè)level?!苯M件會(huì)使用UI樹(shù)中在它上層最近的那個(gè)LevelContext傳遞過(guò)來(lái)的值。這與原始代碼的運(yùn)行結(jié)果相同但是你不需要向每個(gè)Heading組件傳遞level參數(shù)了取而代之的是它通過(guò)訪問(wèn)上層最近的Section來(lái)“斷定”它的標(biāo)題級(jí)別你將一個(gè)level參數(shù)傳遞給Section。Section把它的子元素包在LevelContext value{level}里面。Heading使用useContext(LevelContext)訪問(wèn)上層最近的LevelContext提供的值。在相同的組件中使用并提供context:目前你仍需要手動(dòng)指定每個(gè)section的level。由于context讓你可以從上層的組件讀取信息每個(gè)Section都會(huì)從上層的Section讀取level并自動(dòng)向下層傳遞level 1。你可以像下面這樣做:import{useContext}fromreact;functionSection({children}){constleveluseContext(LevelContext);return(section classNamesectionLevelContext value{level1}{children}/LevelContext/section);}這樣修改之后你不用將level參數(shù)傳給Section或者是Heading了import{createContext}fromreact;import{useContext}fromreact;constLevelContextcreateContext(1);functionHeading({children}){constleveluseContext(LevelContext);switch(level){case1:returnh1{children}/h1;case2:returnh2{children}/h2;case3:returnh3{children}/h3;case4:returnh4{children}/h4;case5:returnh5{children}/h5;case6:returnh6{children}/h6;default:throwError(未知的 levellevel);}}functionSection({children}){constleveluseContext(LevelContext);return(section classNamesectionLevelContext value{level1}{children}/LevelContext/section);}exportdefaultfunctionPage(){return(SectionHeading主標(biāo)題/HeadingSectionHeading副標(biāo)題/HeadingHeading副標(biāo)題/HeadingHeading副標(biāo)題/HeadingSectionHeading子標(biāo)題/HeadingHeading子標(biāo)題/HeadingHeading子標(biāo)題/HeadingSectionHeading子子標(biāo)題/HeadingHeading子子標(biāo)題/HeadingHeading子子標(biāo)題/Heading/Section/Section/Section/Section);}現(xiàn)在Heading和Section都通過(guò)讀取LevelContext來(lái)判斷它們的深度。而且Section把它的子組件都包在LevelContext中來(lái)指定其中的任何內(nèi)容都處于一個(gè)“更深”的級(jí)別。Context 會(huì)穿過(guò)中間層級(jí)的組件可以在提供context的組件和使用它的組件之間的層級(jí)插入任意數(shù)量的組件。這包括像div這樣的內(nèi)置組件和自己創(chuàng)建的組件。Context讓你可以編寫(xiě)“適應(yīng)周?chē)h(huán)境”的組件并且根據(jù)在哪或者說(shuō)在哪個(gè)context中來(lái)渲染它們不同的樣子。Context的工作方式可能會(huì)讓人想起CSS屬性繼承。在CSS中你可以為一個(gè)div手動(dòng)指定color: blue并且其中的任何DOM節(jié)點(diǎn)無(wú)論多深都會(huì)繼承那個(gè)顏色除非中間的其他DOM節(jié)點(diǎn)用color: green來(lái)覆蓋它。類似地在React中覆蓋來(lái)自上層的某些context的唯一方法是將子組件包裹到一個(gè)提供不同值的context provider中。在CSS中諸如color和background-color之類的不同屬性不會(huì)覆蓋彼此。你可以設(shè)置所有div的color為紅色而不會(huì)影響background-color。類似地不同的React context不會(huì)覆蓋彼此。你通過(guò)createContext()創(chuàng)建的每個(gè)context都和其他context完全分離只有使用和提供 那個(gè)特定的context的組件才會(huì)聯(lián)系在一起。一個(gè)組件可以輕松地使用或者提供許多不同的context。但是context對(duì)于許多其他的場(chǎng)景也很有用。你可以用它來(lái)傳遞整個(gè)子樹(shù)需要的任何信息當(dāng)前的顏色主題、當(dāng)前登錄的用戶等。使用Context之前使用Context看起來(lái)非常方便誘人這也意味著它也太容易被過(guò)度使用了。如果咱們只想把一些props傳遞到多個(gè)層級(jí)中這并不意味著你需要把這些信息放到context里。在使用context之前可以考慮以下幾種替代方案從傳遞 props開(kāi)始。 如果組件看起來(lái)不起眼那么通過(guò)十幾個(gè)組件向下傳遞一堆props并不罕見(jiàn)。這有點(diǎn)像是在埋頭苦干但是這樣做可以讓哪些組件用了哪些數(shù)據(jù)變得十分清晰維護(hù)你代碼的人會(huì)很高興你用props讓數(shù)據(jù)流變得更加清晰。抽象組件并將 JSX 作為 children 傳遞給它們。 如果通過(guò)很多層不使用該數(shù)據(jù)的中間組件并且只會(huì)向下傳遞來(lái)傳遞數(shù)據(jù)這通常意味著在此過(guò)程中忘記了抽象組件。舉個(gè)例子可能在想傳遞一些像posts的數(shù)據(jù)props到不會(huì)直接使用這個(gè)參數(shù)的組件類似Layout posts{posts} /。取而代之的是讓Layout把children當(dāng)做一個(gè)參數(shù)然后渲染LayoutPosts posts{posts} //Layout。這樣就減少了定義數(shù)據(jù)的組件和使用數(shù)據(jù)的組件之間的層級(jí)。如果這兩種方法都不適合你再考慮使用context。Context的使用場(chǎng)景主題如果你的應(yīng)用允許用戶更改其外觀例如暗夜模式可以在應(yīng)用頂層放一個(gè)context provider并在需要調(diào)整其外觀的組件中使用該context。當(dāng)前賬戶許多組件可能需要知道當(dāng)前登錄的用戶信息。將它放到context中可以方便地在樹(shù)中的任何位置讀取它。某些應(yīng)用還允許你同時(shí)操作多個(gè)賬戶例如以不同用戶的身份發(fā)表評(píng)論。在這些情況下將UI的一部分包裹到具有不同賬戶數(shù)據(jù)的provider中會(huì)很方便。路由大多數(shù)路由解決方案在其內(nèi)部使用context來(lái)保存當(dāng)前路由。這就是每個(gè)鏈接“知道”它是否處于活動(dòng)狀態(tài)的方式。如果你創(chuàng)建自己的路由庫(kù)你可能也會(huì)這么做。狀態(tài)管理 隨著你的應(yīng)用的增長(zhǎng)最終在靠近應(yīng)用頂部的位置可能會(huì)有很多state。許多遙遠(yuǎn)的下層組件可能想要修改它們。通常 將reducer與context搭配使用來(lái)管理復(fù)雜的狀態(tài)并將其傳遞給深層的組件來(lái)避免過(guò)多的麻煩。Context不局限于靜態(tài)值。如果你在下一次渲染時(shí)傳遞不同的值React將會(huì)更新讀取它的所有下層組件這就是context經(jīng)常和state結(jié)合使用的原因。使用Reducer和Context擴(kuò)展你的應(yīng)用Reducer可以整合組件的狀態(tài)更新邏輯。Context可以將信息深入傳遞給其他組件。你可以組合使用它們來(lái)共同管理一個(gè)復(fù)雜頁(yè)面的狀態(tài)。結(jié)合使用reducer和context在reducer介紹的例子里面狀態(tài)被reducer所管理。reducer函數(shù)包含了所有的狀態(tài)更新邏輯并在此文件的底部聲明Reducer有助于保持事件處理程序的簡(jiǎn)短明了。但隨著應(yīng)用規(guī)模越來(lái)越龐大你就可能會(huì)遇到別的困難。目前tasks狀態(tài)和dispatch函數(shù)僅在頂級(jí)TaskApp組件中可用。要讓其他組件讀取任務(wù)列表或更改它你必須顯式傳遞當(dāng)前狀態(tài)和事件處理程序?qū)⑵渥鳛閜rops。例如TaskApp將一系列task和事件處理程序傳遞給TaskListTaskList task{tasks}onChangeTask{handleChangeTask}onDeleteTask{handleDeleteTask}/TaskList將事件處理程序傳遞給TaskTask task{task}onChange{onChangeTask}onDelete{onDeleteTask}/在像這樣的小示例里這樣做沒(méi)什么問(wèn)題但是如果你有成百上千個(gè)中間組件傳遞所有狀態(tài)和函數(shù)可能會(huì)非常麻煩剛剛學(xué)過(guò)Context之后咱們有了解決方案可以直接把tasks狀態(tài)和dispatch函數(shù)都 放入context。這樣所有的在TaskApp組件樹(shù)之下的組件都不必一直往下傳props而可以直接讀取tasks和dispatch函數(shù)。下面將介紹如何結(jié)合使用reducer和context創(chuàng)建context將state和dispatch放入context。在組件樹(shù)的任何地方使用context。Step 1: 創(chuàng)建contextuseReducer返回當(dāng)前的tasks和dispatch函數(shù)來(lái)讓你更新它們:const[tasks,dispatch]useReducer(tasksReducer,initialTasks);為了將它們從組件樹(shù)往下傳你將創(chuàng)建兩個(gè)不同的context:TasksContext提供當(dāng)前的tasks列表。TasksDispatchContext提供了一個(gè)函數(shù)可以讓組件分發(fā)動(dòng)作。import{createContext}fromreact;constTasksContextcreateContext(null);constTasksDispatchContextcreateContext(null);在這里先把null作為默認(rèn)值傳遞給兩個(gè)context。實(shí)際值是由TaskApp組件提供的。Step 2: 將state和dispatch函數(shù)放入context現(xiàn)在你可以將所有的context導(dǎo)入TaskApp組件。獲取useReducer()返回的tasks和dispatch并將它們提供給整個(gè)組件樹(shù)import{createContext}fromreact;constTasksContextcreateContext(null);constTasksDispatchContextcreateContext(null);exportdefaultfunctionTaskApp(){const[tasks,dispatch]useReducer(tasksReducer,initialTasks);// ...return(TasksContext value{tasks}TasksDispatchContext value{dispatch}// .../TasksDispatchContext/TasksContext);}現(xiàn)在你可以同時(shí)通過(guò)props和context傳遞信息Step 3: 在組件樹(shù)中的任何地方使用context現(xiàn)在你不需要將tasks和事件處理程序在組件樹(shù)中傳遞相反任何需要tasks的組件都可以從TasksContext中讀取它任何組件都可以從context中讀取dispatch函數(shù)并調(diào)用它從而更新任務(wù)列表。TaskApp組件不會(huì)向下傳遞任何事件處理程序TaskList也不會(huì)。每個(gè)組件都會(huì)讀取它需要的context:import{createContext}fromreact;import{useState,useContext}fromreact;import{useReducer}fromreact;constTasksContextcreateContext(null);constTasksDispatchContextcreateContext(null);functionTaskList(){consttasksuseContext(TasksContext);return(ul{tasks.map(task(li key{task.id}Task task{task}//li))}/ul);}functionTask({task}){const[isEditing,setIsEditing]useState(false);constdispatchuseContext(TasksDispatchContext);lettaskContent;if(isEditing){taskContent(input value{task.text}onChange{e{dispatch({type:changed,task:{...task,text:e.target.value}});}}/button onClick{()setIsEditing(false)}Save/button/);}else{taskContent({task.text}button onClick{()setIsEditing(true)}Edit/button/);}return(labelinput typecheckboxchecked{task.done}onChange{e{dispatch({type:changed,task:{...task,done:e.target.checked}});}}/{taskContent}button onClick{(){dispatch({type:deleted,id:task.id});}}Delete/button/label);}functionAddTask(){const[text,setText]useState();constdispatchuseContext(TasksDispatchContext);return(input placeholderAdd taskvalue{text}onChange{esetText(e.target.value)}/button onClick{(){setText();dispatch({type:added,id:nextId,text:text,});}}Add/button/);}letnextId3;exportdefaultfunctionTaskApp(){const[tasks,dispatch]useReducer(tasksReducer,initialTasks);return(TasksContext value{tasks}TasksDispatchContext value{dispatch}h1Day offinKyoto/h1AddTask/TaskList//TasksDispatchContext/TasksContext);}functiontasksReducer(tasks,action){switch(action.type){caseadded:{return[...tasks,{id:action.id,text:action.text,done:false}];}casechanged:{returntasks.map(t{if(t.idaction.task.id){returnaction.task;}else{returnt;}});}casedeleted:{returntasks.filter(tt.id!action.id);}default:{throwError(Unknown action: action.type);}}}constinitialTasks[{id:0,text:Philosopher’s Path,done:true},{id:1,text:Visit the temple,done:false},{id:2,text:Drink matcha,done:false}];state仍然 “存在于” 頂層Task組件中由useReducer進(jìn)行管理。不過(guò)組件樹(shù)里的組件只要導(dǎo)入這些context之后就可以獲取tasks和dispatch。將相關(guān)邏輯遷移到一個(gè)文檔當(dāng)中這不是必須的但你可以通過(guò)將reducer和context移動(dòng)到單個(gè)文件中來(lái)進(jìn)一步整理組件。新建一個(gè)“TasksContext.js” 文件包含兩個(gè)context聲明來(lái)給這個(gè)文件添加更多代碼將reducer移動(dòng)到此文件中然后聲明一個(gè)新的TaskProvider組件。此組件將所有部分連接在一起:它將管理reducer的狀態(tài)它將提供現(xiàn)有的context給組件樹(shù)它將把children作為prop所以你可以傳遞JSX。import{createContext,useReducer}fromreact;exportconstTasksContextcreateContext(null);exportconstTasksDispatchContextcreateContext(null);exportfunctionTasksProvider({children}){const[tasks,dispatch]useReducer(tasksReducer,initialTasks);return(TasksContext value{tasks}TasksDispatchContext value{dispatch}{children}/TasksDispatchContext/TasksContext);}functiontasksReducer(tasks,action){switch(action.type){caseadded:{return[...tasks,{id:action.id,text:action.text,done:false}];}casechanged:{returntasks.map(t{if(t.idaction.task.id){returnaction.task;}else{returnt;}});}casedeleted:{returntasks.filter(tt.id!action.id);}default:{throwError(Unknown action: action.type);}}}constinitialTasks[{id:0,text:Philosopher’s Path,done:true},{id:1,text:Visit the temple,done:false},{id:2,text:Drink matcha,done:false}];你也可以從TasksContext.js中導(dǎo)出使用context的函數(shù)exportfunctionuseTasks(){returnuseContext(TasksContext);}exportfunctionuseTasksDispatch(){returnuseContext(TasksDispatchContext);}組件可以通過(guò)以下函數(shù)讀取contextconsttasksuseTasks();constdispatchuseTasksDispatch();這不會(huì)改變?nèi)魏涡袨榈鼤?huì)允許你之后進(jìn)一步分割這些context或向這些函數(shù)添加一些邏輯。現(xiàn)在所有的context和reducer連接部分都在TasksContext.js中。這保持了組件的干凈和整潔讓我們專注于它們顯示的內(nèi)容而不是它們從哪里獲得數(shù)據(jù)你可以將TasksProvider視為頁(yè)面的一部分它知道如何處理tasks。useTasks用來(lái)讀取它們useTasksDispatch用來(lái)從組件樹(shù)下的任何組件更新它們。像useTasks和useTasksDispatch這樣的函數(shù)被稱為自定義 Hook。 如果你的函數(shù)名以u(píng)se開(kāi)頭它就被認(rèn)為是一個(gè)自定義Hook。這讓你可以使用其他Hook比如useContext。隨著應(yīng)用的增長(zhǎng)你可能會(huì)有許多這樣的context和reducer的組合。這是一種強(qiáng)大的拓展應(yīng)用并提升狀態(tài)的方式讓你在組件樹(shù)深處訪問(wèn)數(shù)據(jù)時(shí)無(wú)需進(jìn)行太多工作。
版權(quán)聲明: 本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)聯(lián)系我們進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

網(wǎng)站上線多少錢(qián)黃金網(wǎng)站app下載免費(fèi)

網(wǎng)站上線多少錢(qián),黃金網(wǎng)站app下載免費(fèi),全球旅游網(wǎng)站排名,微信商城網(wǎng)站案例展示timeline-vuejs是一款專為Vue.js設(shè)計(jì)的極簡(jiǎn)時(shí)間軸組件#xff0c;能夠幫助開(kāi)發(fā)者快速構(gòu)建美觀的時(shí)間線展示

2026/01/23 06:40:01

大連網(wǎng)站推廣公司濰坊網(wǎng)站建設(shè)wfzhy

大連網(wǎng)站推廣公司,濰坊網(wǎng)站建設(shè)wfzhy,wordpress在預(yù)覽圖上加符號(hào),wordpress免費(fèi)簡(jiǎn)約主題下載2025企業(yè)AI網(wǎng)關(guān)終極指南#xff1a;3大架構(gòu)策略實(shí)現(xiàn)多模型統(tǒng)一治理 【免費(fèi)下載鏈接

2026/01/21 18:19:01

網(wǎng)站可以做的線下活動(dòng)個(gè)人怎么申請(qǐng)注冊(cè)商標(biāo)

網(wǎng)站可以做的線下活動(dòng),個(gè)人怎么申請(qǐng)注冊(cè)商標(biāo),手機(jī)官方,建設(shè)局合同備案是哪個(gè)網(wǎng)站在現(xiàn)代數(shù)字化浪潮中#xff0c;三維重建與攝影測(cè)量技術(shù)正以前所未有的速度改變著我們認(rèn)知世界的方式。通過(guò)簡(jiǎn)單的二維照片序列#

2026/01/23 10:38:01