当前位置: 首页 > 科技观察

Sentry开发者贡献指南-前端ReactHooks和虫洞状态管理模式

时间:2023-03-12 10:44:34 科技观察

什么是虫洞状态管理模式?您可以逃脱的最小状态共享量是多少?保持你的状态。尽可能靠近使用它的地方。如果有一个组件关心这个,就使用它。如果有多个组件关心它,则与props共享。如果许多组件关心,请将其放在上下文中。上下文就像一个虫洞。它会弯曲您的组件树,以便相距很远的部分可以接触。利用自定义挂钩使这变得容易。一个示例构建了一个点击计数器。虫洞状态管理模式最好用例子来解释??CodeSandbox(示例代码)https://codesandbox.io/s/wormhole-state-pattern-5-j4w5e?file=/src/App.js第1步我们从useState开始,因为它是最简单的。constClickCounter=()=>{const[count,setCount]=useState(0);functiononClick(){setCount(count=>count+1);}返回{count}+1;};count保存当前的点击次数,而setCount让我们更新每次点击的值。很简单。但是,外观不是很漂亮。让我们用自定义按钮组件和一些嵌套来改进它。第2步我们创建一个可重复使用的PrettyButton,确保您应用中的每个按钮看起来都很棒。状态保存在ClickCounter组件中。constClickCounter=()=>{const[count,setCount]=useState(0);functiononClick(){setCount(count=>count+1);}return(<

你点击了按钮{count}次

+1
/>);};这是必要的最小状态共享。我们也让事情变得简单。计数器组件关心点击和计数,因此它将回调作为道具传递给按钮。函数被调用,状态被更新,组件重新渲染。不需要复杂的操作。第3步如果我们的状态更复杂怎么办?我们有2件物品。你可以在你的状态中持久化复杂的值。好的结果。constClickCounter=()=>{const[count,setCount]=useState(0);functiononClick(){setCount(count=>count+1);}return(<

你点击了按钮{count}次

+1
/>);};我们已将计数拆分为一个对象–{A,B}。一个状态现在可以保存多个值。个别按钮点击的个别计数。React使用JavaScript相等性来检测重新渲染的变化,因此您必须在每次更新时制作完整状态的副本。这在大约10,000个元素时变慢。您也可以在此处使用useReducer。特别是当您的状态变得更加复杂并且项目经常单独更新时。使用useReducer的类似状态看起来像这样:const[state,dispatch]=useReducer((action,state)=>{switch(action.type){case'A':return{...state,A:state.A+1}case'B':return{...state,A:state.A+1}}},{A:0,B:0})functiononClickA(){dispatch({type:'A'})}你的状态越复杂,这就越有意义。但我认为那些switch语句很快就会变得混乱,而且你的回调函数已经是动作了。Step4如果我们想让2个按钮更新同一个状态怎么办?你可以将count和setCount作为props传递给你的组件。但是越来越迷茫了。constAlternativeClick=({count,setCount})=>{functiononClick(){setCount(count=>{return{...count,B:count.B+1};});}return(YoucanalsoupdateBhere
B+1

这是{count.B}btw

);};我们创建创建了一个难以移动并且需要了解太多父逻辑的组件。关注点是分裂的,抽象是奇怪的,我们制造了混乱。您可以通过仅传递它需要的状态部分和更自定义的setCount来修复它。但这是很多工作。第5步相反,您可以使用虫洞与自定义挂钩共享状态。您现在有2个共享状态的独立组件。将它们放在您的代码库中的任何位置,它就可以正常工作吗?需要在别处访问共享状态?添加useSharedCount挂钩,瞧。这是这部分的工作原理。我们有一个带有一些操作的上下文提供者:exportconstSharedCountProvider=({children})=>{//replacewithuseReducerformoreflexiblityconst[state,setState]=useState(defaultState);const[contextValue,setContextValue]=useState({state,//dispatch//fromyourreducer//thisiswherearereducercomeshandywhenthisgrowssetSharedCount:(key,val)=>{setState(state=>{return{...state,[key]:val};});}//otherstuffyouneedincontext});//avoidsdeeppre-renders//wheninstancesofstuffincontextchangeuseEffect(()=>{setContextValue(currentValue=>({...currentValue,state}));},[state]);return({children});};ContextProvider使用丰富的状态变量来保持你的状态。这是我们的{A,B}。contextValue是一个更丰富的状态,它还包含操作该状态所需的一切。通常这将是来自你的reducer的dispatch方法,或者像我们这里的自定义状态设置器。我们的setSharedCount方法接受一个键和一个val并更新那部分状态。setSharedCount("B",10);然后我们有一个副作用,观察状态变化并在需要时触发重新渲染。这避免了每次我们重新定义我们的调度方法或其他任何东西时深度重新渲染。让React树更稳定??此提供程序中呈现的每个组件都可以使用相同的自定义挂钩来访问它需要的一切。exportfunctionuseSharedCount(){const{state,setSharedCount}=useContext(SharedCountContext);functionincA(){setSharedCount("A",state.A+1);}functionincB(){setSharedCount("B",state.B+1);}return{count:state,incA,incB};}Customhook利用ReactContext共享状态,定义更简单的incA和incB辅助方法,并返回它们的状态。这意味着我们的AlternativeClick组件可以看起来像这样:"}}>你也可以在这里更新
B+1

这是{count.B}btw

);};从custom钩子得到count和incB。使用它们。表现如何?好的。尽可能少地共享状态。为应用程序的不同部分使用不同的上下文提供程序。除非它需要是全球性的,否则不要让它成为全球性的。包裹你可以逃脱的树的最小部分。有多复杂?什么复杂性?保持小。不要塞进你不需要的东西。讨厌管理自己的状态看到我们的SharedCountProvider中处理状态变化的部分了吗?这部分:const[contextValue,setContextValue]=useState({state,//dispatch//fromyourreducer//thisiswhereareducercomeshandywhenthisgrowssetSharedCount:(key,val)=>{setState(state=>{return{...state,[key]:val};});}//otherstuffyouneedincontext});为此,您可以使用XState。或减速机。即使是Redux,如果你真的想要它。但是,如果你使用Redux,你还不如一路走下去??顶级开源项目如何使用?(哨兵)organizationContext.tsx(详细代码)https://github.com/getsentry/sentry/blob/master/static/app/views/organizationContext.tsxRefs虫洞状态管理https://swizec.com/blog/wormhole-state-管理/