当前位置: 首页 > news >正文

建个企业网站多少钱上海市工程咨询行业协会

建个企业网站多少钱,上海市工程咨询行业协会,网站关键词效果追踪怎么做,高速访问免费全自动网页制作系统跨组件通信和数据共享不是一件容易的事#xff0c;如果通过 prop 一层层传递#xff0c;太繁琐#xff0c;而且仅适用于从上到下的数据传递#xff1b;建立一个全局的状态 Store#xff0c;每个数据可能两三个组件间需要使用#xff0c;其他地方用不着#xff0c;挂那么…跨组件通信和数据共享不是一件容易的事如果通过 prop 一层层传递太繁琐而且仅适用于从上到下的数据传递建立一个全局的状态 Store每个数据可能两三个组件间需要使用其他地方用不着挂那么大个状态树也浪费了。当然了有一些支持局部 store 的状态管理库比如 zustand我们可以直接使用它来跨组件共享数据。不过本文将基于事件机制的原理带来一个新的协同方案。 目标 vue3 中有 provide 和 inject 这两个 api可以将一个组件内的状态透传到另外的组件中。那我们最终要实现的 hook 就叫 useProvide 和 useInject 吧。要通过事件机制来实现这两个 hook那少不了具备事件机制的 hook所以我们要先来实现一个事件发射器useEmitter和一个事件接收器useReceiver 事件 Hook 思路 需要一个事件总线需要一对多的事件和侦听器映射关系需要具备订阅和取消功能支持命名空间来提供一定的隔离性 useEmitter 很简单我们创建一个全局的 Map 对象来充当事件总线在里面根据事件名和侦听器名存储映射关系即可。 代码不做太多解释逻辑很简单根据既定的命名规则来编排事件注意重名的处理即可。 (Ukey 是一个生成唯一id的工具函数你可以自己写一个或者用nanoid等更专业的库替代) import { useEffect, useContext, createContext } from react; import Ukey from ./utils/Ukey;interface EventListener {namespace?: string;eventName: string;listenerName: string;listener: (...args: any[]) void; }// 创建一个全局的事件监听器列表 const globalListeners new Mapstring, EventListener();// 创建一个 Context 来共享 globalListeners const GlobalListenersContext createContext(globalListeners);export const useGlobalListeners () useContext(GlobalListenersContext);interface EventEmitterConfig {name?: string;initialEventName?: string;initialListener?: (...args: any[]) void;namespace?: string; }interface EventEmitter {name: string;emit: (eventName: string, ...args: any[]) void;subscribe: (eventName: string, listener: (...args: any[]) void) void;unsubscribe: (eventName: string) void;unsubscribeAll: () void; }function useEmitter(name: string,config?: PartialEventEmitterConfig ): EventEmitter; function useEmitter(config: PartialEventEmitterConfig): EventEmitter; function useEmitterM {}(name?: string,initialEventName?: string,// ts-ignoreinitialListener?: (...args: M[typeof initialEventName][]) void,config?: PartialEventEmitterConfig ): EventEmitter;// ts-ignore function useEmitterM {}(nameOrConfig?: string | PartialEventEmitterConfig,initialEventNameOrConfig?: string | PartialEventEmitterConfig,// ts-ignoreinitialListener?: (...args: M[typeof initialEventNameOrConfig][]) void,config?: PartialEventEmitterConfig ) {const globalListeners useContext(GlobalListenersContext);// 根据参数类型确定实际的参数值let configActual: PartialEventEmitterConfig {};if (typeof nameOrConfig string) {configActual.name nameOrConfig;if (typeof initialEventNameOrConfig string) {configActual.initialEventName initialEventNameOrConfig;configActual.initialListener initialListener;} else if (typeof initialEventNameOrConfig object) {Object.entries(initialEventNameOrConfig).map(([key, value]) {if (value ! void 0) {// ts-ignoreconfigActual[key] value;}});}} else {configActual nameOrConfig || {};}if (!configActual.name) {configActual.name _emitter_${Ukey()};}if (!configActual.namespace) {configActual.namespace default;}// 如果没有传入 name使用 Ukey 方法生成一个唯一的名称const listenerName configActual.name;const emit (eventName: string, ...args: any[]) {globalListeners.forEach((value, key) {if (key.startsWith(${configActual.namespace}_${eventName}_)) {value.listener(...args);}});};const subscribe (eventName: string, listener: (...args: any[]) void) {const key ${configActual.namespace}_${eventName}_${listenerName};if (globalListeners.has(key)) {throw new Error(useEmitter: Listener ${listenerName} has already registered for event ${eventName});}globalListeners.set(key, { eventName, listenerName, listener });};const unsubscribe (eventName: string) {const key ${configActual.namespace}_${eventName}_${listenerName};globalListeners.delete(key);};const unsubscribeAll () {const keysToDelete: string[] [];globalListeners.forEach((value, key) {if (key.endsWith(_${listenerName})) {keysToDelete.push(key);}});keysToDelete.forEach((key) {globalListeners.delete(key);});};useEffect(() {if (configActual.initialEventName configActual.initialListener) {subscribe(configActual.initialEventName, configActual.initialListener);}return () {globalListeners.forEach((value, key) {if (key.endsWith(_${listenerName})) {globalListeners.delete(key);}});};}, [configActual.initialEventName, configActual.initialListener]);return { name: listenerName, emit, subscribe, unsubscribe, unsubscribeAll }; }export default useEmitter; export { GlobalListenersContext };useReceiver 我们在 useEmitter 的基础上封装一个 hook 来实时存储事件的值 import { useState, useEffect, useCallback } from react; import useEmitter from ./useEmitter; import Ukey from ./utils/Ukey; import { Prettify } from ./typings;type EventReceiver {stop: () void;start: () void;reset: (args: any[]) void;isListening: boolean;// emit: (event: string, ...args: any[]) void; };type EventReceiverOptions {name?: string;namespace?: default | (string {});eventName: string;callback?: EventCallback; };type EventCallback (...args: any[]) void;function useReceiver(eventName: string,callback?: EventCallback ): [any[] | null, EventReceiver]; function useReceiver(options: PrettifyEventReceiverOptions ): [any[] | null, EventReceiver];function useReceiver(eventNameOrOptions: string | PrettifyEventReceiverOptions,callback?: EventCallback ): [any[] | null, EventReceiver] {let eventName: string;let name: string;let namespace: string;let cb: EventCallback | undefined;if (typeof eventNameOrOptions string) {eventName eventNameOrOptions;name _receiver_${Ukey()};namespace default;cb callback;} else {eventName eventNameOrOptions.eventName;name eventNameOrOptions.name || _receiver_${Ukey()};namespace eventNameOrOptions.namespace || default;cb eventNameOrOptions.callback;if (cb) {if (callback) {console.warn(useReceiver: Callback is ignored when options.callback is set);} else {cb callback;}}}const { subscribe, unsubscribe, emit } useEmitter({name: name,namespace: namespace,});const [isListening, setIsListening] useState(true);const [eventResult, setEventResult] useStateany[] | null(null);const eventListener useCallback((...args: any[]) {setEventResult(args);cb?.(...args);}, []);useEffect(() {subscribe(eventName, eventListener);return () {unsubscribe(eventName);};}, [eventName, eventListener]);const stopListening useCallback(() {unsubscribe(eventName);setIsListening(false);}, [eventName]);const startListening useCallback(() {subscribe(eventName, eventListener);setIsListening(true);}, [eventName, eventListener]);const reveiver {stop: stopListening,start: startListening,reset: setEventResult,isListening,get emit() {return emit;},} as EventReceiver;return [eventResult, reveiver]; }export default useReceiver; 这里我们开放了 emit但在类型声明上隐藏它因为使用者不需要它留着 emit 是因为我们在接来下实现 useInject 还需要它。 共享 Hook 思路 有了 useEmitter 和 useReceiver 这两大基石后一切都豁然开朗。我们只需要在 useEmitter 的基础上封装 useProvide传入唯一键名state 值和 setState将其和事件绑定即可注意这里额外订阅了一个 query 事件来允许其监听者主动请求提供者广播一次数据用处后面提。 useProvide import { Dispatch, SetStateAction, useEffect } from react; import useEmitter from ./useEmitter;export function useProvideT any(name: string,state: T,setState?: DispatchSetStateActionT ) {const emitter useEmitter(__Provider::${name}, {namespace: __provide_inject__,initialEventName: __Inject::${name}::query,initialListener() {emitter.emit(__Provider::${name}, state, setState);},});useEffect(() {emitter.emit(__Provider::${name}, state, setState);}, [name, state, setState]); }export default useProvide;useInject useInject 只需要封装 useReceiver 并返回 state即可注意在 useInject 挂载之初我们需要主动向提供者请求一次同步因为提供者通常情况下比注入者挂载的更早提供者初始主动同步的那一次绝大多数注入者并不能接收到。 import { Dispatch, SetStateAction, useEffect } from react; import useReceiver from ./useReceiver; import UKey from ./utils/Ukey;/*** useInject is a hook that can be used to inject a value from a provider.* * ---* ### Parameters* - name - The name of the provider to inject from.* * ---* ### Returns* - [0]value - The value of the provider.* - [1]setValue - A function to set the value of the provider.*/ function useInjectT extends Object { [x: string]: any },// ts-ignoreK extends string keyof T,// ts-ignoreV K extends string ? T[K] | undefined : any// ts-ignore (name: K): [V, DispatchSetStateActionV] {// ts-ignoreconst [result, { emit }] useReceiver({name: __Inject::${name}_${UKey()},eventName: __Provider::${name},namespace: __provide_inject__,});const query () emit(__Inject::${name}::query, true);useEffect(() {query();}, []);return [result?.[0], result?.[1]]; }export default useInject;然后你就可以像这样快乐的共享数据了 import useInject from /hooks/useInject; import useProvide from /hooks/useProvide; import { Button } from mui/material; import { useState } from react;type Person {name: string;age: number; };const UseProvideExample () {const [state, setState] useStatePerson({name: Evan,age: 20,});useProvide(someone, state);return (ButtononClick{() setState({ ...state, name: state.name Evan ? Nave : Evan })}{state.name}/ButtonButton onClick{() setState({ ...state, age: state.age 1 })}{state.age}/Button/); };const UseInjectExample () {const [state] useInject{ someone: Person }(someone);const [state2] useInject{ someone: Person }(someone);return (div style{{ display: flex }}span{state?.name}/spandiv style{{ width: 2rem }}/divspan{state?.age}/span/divdiv style{{ display: flex }}span{state2?.name}/spandiv style{{ width: 2rem }}/divspan{state2?.age}/span/div/); };const View () {return (h4UseProvide/h4UseProvideExample /h4Inject/h4UseInjectExample //); };Demo 效果图 Bingo! 用于跨组件协同的 useProvide 和 useInject 就这样实现了 (PS : 我这里的 useProvide 和 useInject 并没有开发命名空间你们可以拓展参数来提供更细粒度的数据隔离)
http://www.pierceye.com/news/377874/

相关文章:

  • wordpress怎么设置跳站外链接番禺网站建设培训学校
  • 怎样建立网站平台新网站应该怎么做
  • 根据颜色找网站济南做网站公司排名
  • 面对面视频 网站开发网络科技加我qq是干嘛
  • 如何登录网站制作平台百度旧版本
  • 广东营销型网站建设报价定制商品的app
  • 网站导航常用关键字电子商务网站设计内容
  • 建设vip网站相关视频wordpress 修改用户头像
  • 考百度指数 某个关键词在某个行业网站上的wordpress与Wix对比
  • 机器人网站建设规划书福州网站制作怎样
  • 自己创建一个网站需要多少钱2023最建议买10款手机
  • 寻找富阳网站建设国内个人网站欣赏
  • 企业自建站城市建设模拟游戏官方网站
  • 网站建设数据库类型建立网站信息发布登记制度
  • it培训机构都有哪些seo推广教程seo推广技巧
  • 龙岩网站开发较好的公司wordpress屏蔽首页
  • 有没有做美食的网站深圳网站建站公司
  • 学校网站建设需求分析调研表网站右侧信息跟随左侧菜单栏变化
  • 家乡网站建设策划案邢台哪里建网站
  • 网站建设实习收获青岛网上房地产网站
  • 简述电子政务网站设计的技术企业邮箱是什么类型的账户
  • 深圳网站建设公司元嘉定网站开发
  • 佛山外贸网站建设平台上传网站安装教程
  • c2c网站建设实例德国网站建设
  • 建网站支持设备是什么意思佛山中小企业网站建设
  • 网站建设与管理读后感宁德住房和城乡建设部网站
  • 贸易网站建站建设部网站社保联网
  • 住房城乡建设厅网站准考证如何建小企业网站
  • 葫芦岛市城乡建设局网站做什么样的网站
  • 铜山区规划建设局网站大学生心理咨询网站建设论文