Javascript 将引用存储到第三方库的最佳实践

Javascript 将引用存储到第三方库的最佳实践,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我正在pusher js周围创建一个包装钩子库,以便发布到野外。对于每个钩子(即useChannel,usePresenceChannel,useTrigger),我需要保留对Pusher实例的引用,即存储在上下文提供程序中的new Pusher()。我允许传递第三方身份验证,所以我需要动态创建Pusher实例。我不确定是否应该将其存储在useState或useRef中 eslint插件使用useState和useRef的各种组合来存储此信息。我也看到了不良副作用时,试图清理正确的每一个。我不确

我正在
pusher js
周围创建一个包装钩子库,以便发布到野外。对于每个钩子(即
useChannel
usePresenceChannel
useTrigger
),我需要保留对Pusher实例的引用,即存储在上下文提供程序中的new Pusher()。我允许传递第三方身份验证,所以我需要动态创建Pusher实例。我不确定是否应该将其存储在useState或useRef中

eslint插件使用useState和useRef的各种组合来存储此信息。我也看到了不良副作用时,试图清理正确的每一个。我不确定什么是最佳实践

下面是一个简化的实现,其中包含一些重要的细节。见评论1。2.三,。下面是我的问题

//PusherContext.jsx
export const PusherContext=React.createContext();
导出函数PusherProvider({key,config,…props}){
//1.我应该像这样存储第三方库吗?
const clientRef=useRef();
//vs const[client,setClient]=useState();
//当配置更改时,即config.auth,重新创建实例
useffect(()=>{
clientRef.current&&clientRef.current.disconnect();
clientRef.current=新推送器(键,{…配置});
},[clientRef,config]);
返回
}
//useChannel.js
导出函数useChannel(
频道名称,
事件名称,
回拨,
回拨深度
){
const{client}=useContext(PusherContext);
const callbackRef=useCallback(callback,callbackDeps);
//2.还是应该改用状态?
const[channel,setChannel]=useState();
//vs.const channelRef=useRef();
useffect(()=>{
if(客户端当前){
const pusherChannel=client.current.subscribe(channelName);
绑定(eventName,callbackRef.current);
设置通道(推送通道);
}
//无法在此清理,因为callbackRef经常更改。
//3.eslint:client.current之类的可变值不是有效的依赖项,因为对它们进行变异不会重新呈现组件
},[client.current,callbackRef])
//用于解除绑定事件的清理
//使用更新的回调引用重新绑定是有意义的
useffect(()=>{
channel.unbind(eventName)
},[client,channel,callbackRef,eventName]);
//从频道取消订阅的清理
useffect(()=>{
clientRef.unsubscribe(channelName);
},[client,channelName])
}

任何建议,过去的例子或模式是非常感谢,因为我想钉这一个

我将使用ref来保存
Pusher的新实例

您不需要在内部效果中执行空检查和断开(
clientRef.current&&clientRef.current.disconnect()
)来进行初始清理,因为无论何时运行
useffect
,当您在return语句中处理它时,React都将断开连接

export function PusherProvider({ key, config, ...props }) {
  // 1. Should I store third party libraries like this?
  const clientRef = useRef();
  // vs const [client, setClient] = useState();

  // when config changes, i.e. config.auth, re-create instance
  // useEffect(() => {
  //   clientRef.current && clientRef.current.disconnect();
  //   clientRef.current = new Pusher(key, { ...config });
  // }, [clientRef, config]);

  // Create an instance, and disconnect on the next render
  // whenever clientRef or config changes.
  useEffect(() => {
    clientRef.current = new Pusher(key, { ...config });

    // React will take care of disconnect on next effect run.
    return () => clientRef.current.disconnect();
  }, [clientRef, config]);

  return <PusherContext.Provider value={{ client }} {...props} />;
}
导出函数PusherProvider({key,config,…props}){
//1.我应该像这样存储第三方库吗?
const clientRef=useRef();
//vs const[client,setClient]=useState();
//当配置更改时,即config.auth,重新创建实例
//useffect(()=>{
//clientRef.current&&clientRef.current.disconnect();
//clientRef.current=新推送器(键,{…配置});
//}[clientRef,config]);
//创建一个实例,并在下一次渲染时断开连接
//每当clientRef或config更改时。
useffect(()=>{
clientRef.current=新推送器(键,{…配置});
//React将在下一次效果运行时处理断开连接。
return()=>clientRef.current.disconnect();
},[clientRef,config]);
返回;
}
对于第二个案例,我尽量在下面的行中写下建议

要点是,
un/subscription
是相关事件,因此应以相同的效果进行处理(就像
PusherProvider
的情况一样)

//useChannel.js
导出函数useChannel(channelName、eventName、callback、callbackDeps){
const{client}=useContext(PusherContext);
const callbackRef=useCallback(callback,callbackDeps);
//2.还是应该改用状态?
//我认为状态是有意义的,因为un/订阅取决于频道名称。
//使用下面的deps数组更容易触发效果。
const[channel,setChannel]=useState();
useffect(()=>{
//如果没有可用的推进器,请不要运行效果。
如果(!client.current)返回;
const pusherChannel=client.current.subscribe(channelName);
绑定(eventName,callbackRef.current);
设置通道(推送通道);
//通过让客户做出反应来共同定位问题
//处理每个频道名称更改的取消/订阅
return()=>client.current.unsubscribe(channelName);
//在频道名称更改时取消订阅时,在列表中添加了“channelName”。
},[client.current,callbackRef,channelName]);

//这..我不确定..谢谢Sung-一切看起来都不错,但是,每当client.current发生变化时,pusher就会取消订阅(
return()=>client.current.unsubscribe(channelName);
)-即,添加或删除成员。我想我必须在可以用于绑定的上下文中拥有一个isReady状态。是的。我不知道Pusher是如何实现的,所以只要你不伪造deps列表,你可能是对的。不能使用
eslint
!让你保持警惕。我选择了分离频道和ev对于任何遇到这个问题的人来说:另外,还有另一个解决这个问题的方法。