将事件处理程序绑定到文档并通过 useEffect 访问 firebase api 数据

Posted

技术标签:

【中文标题】将事件处理程序绑定到文档并通过 useEffect 访问 firebase api 数据【英文标题】:Bind event handler to document & have access to firebase api data via useEffect 【发布时间】:2020-01-05 23:09:20 【问题描述】:

快速版:

我的最终目标是执行类似于下面链接的操作,但根据 useEffect 对 firebase 进行异步调用,其中列表数据由 firebase 对象内容组成。

https://codesandbox.io/s/usage-pxfy7

问题

在下面的代码中,useEffect 封装了 ping firebase 并获取一些称为“客户端”的数据的代码。数据被完美检索。

然后我使用useState 将该数据存储到useState 的两个不同实例中。数据存储在clientListclientListForRender

到目前为止一切顺利。

现在问题开始了。

我有第三个useState 实例,它需要一个数字。我想为文档设置一个按键事件,以便我可以使用向上/向下箭头来切换计数器并访问 clientListForRender 数组的每个值。

当我设置 eventListener 时,我无权访问数组(可能是由于异步调用的顺序不支持它)。

我不知道如何编写我的钩子以得到我想要的结果。

谢谢。

const clientsRef = firebase.database().ref('clients');
const [clientList,setClientListState] = useState([]);   
const [clientListForRender,setClientListStateForRender] = useState([]);
const [selectedIndex, updateSelectedIndex] = useState(0);



useEffect(() => 



  function handleKeyPress(event,arr)
    console.log(arr)
    if(event.key === "ArrowDown")
      updateSelectedIndex((prev)=>
          return prev += 1
      );
    
  



  clientsRef.on('child_added', snapshot => 
      const client = snapshot.val();
      client.key = snapshot.key;     //     __________________________1. get firebase data


     setClientListState(function(prev)       




           setClientListStateForRender(()=>[client,...prev]); //_______2 store data    



     // document.addEventListener('keydown', handleKeyPress);  <---I am not sure where to put this. I have experimented and 
                                                                   // I decided to omit my cluttered "experiments" to protect your eyes


           return[client,...prev]
      );

   );


,[]);

【问题讨论】:

你在控制台看到什么错误? 【参考方案1】:

好的,您发布的代码几乎没有问题:

1) 绝对不要在 child_ added 监听器中添加键盘监听器(这意味着每次调用 child_added 监听器时,你都要创建一个新的监听器,导致意外结果和内存泄漏)

2) 您在 setState 更新函数(您提供的回调函数,setClientListState)中调用 setState,这是一种反模式,使您的代码难以遵循和理解,并且一旦组件增长会导致意想不到的影响。如果您想根据之前的状态更新状态,请使用 useEffect 回调

3) useEffect 函数接受第二个参数,称为依赖数组。当你为它提供了一个空数组时,这意味着你希望你的效果只运行一次,这是有问题的,因为我们看到该函数依赖于 clientsRef 变量。 (这实际上是你的问题,因为键盘监听器有你的 clientsList 的旧值,它是空数组,所以它总是返回 0,当按下键时,我在代码沙箱中解释了更多)

4) 你应该从 useEffect 函数返回一个回调函数来清理你创建的效果,关闭你附加的监听器(否则你可能有内存泄漏,这取决于组件被挂载/卸载的程度)

好的,代码应该是这样工作的:

const clientsRef = firebase.database().ref('clients');
const [clientList, setClientListState] = useState([]);
// I don't understand why you wanted another list, so for now i only use on list
// const [clientListForRender,setClientListStateForRender] = useState([]);
const [selectedIndex, updateSelectedIndex] = useState(0);

useEffect(() => 
  function handleKeyPress(event, arr) 
    if (event.key === 'ArrowDown') 
      updateSelectedIndex(prev => 
        if (prev >= clientList.length - 1) 
          return (prev = 0);
         else 
          return prev + 1;
        
      );
    
  

  clientsRef.on('child_added', snapshot => 
    const client = snapshot.val();
    client.key = snapshot.key; //     __________________________1. get firebase data

    setClientListState(function(prev) 
      return [client, ...prev];
    );
  );

  document.addEventListener('keydown', handleKeyPress);

  // here you should return a callback to clear/clean your effects

  return () => 
    document.removeEventListener('keydown', handleKeyPress);
    clientsRef.off();
  ;
  // Its important to add these here, or else each time your keyboard listener runs it will have the initial value of
  // clientsList ([]), and so clientsList.length = 0, and so you will always updateSelectedIndex(0)
, [clientList, clientsRef]);

//here render based on selected list as you wish

最后我根据你给https://codesandbox.io/s/usage-4sn92的例子建立了一个模拟数据获取的工作代码框,我在那里添加了一些cmets来帮助解释我上面所说的。

【讨论】:

这使我的应用程序崩溃并创建了某种递归循环。我将很快发布更多我的应用程序代码,以便有更多上下文。 .... 这是一个视频,显示了我在使用您的代码时遇到的崩溃。 youtu.be/yDyYNgcceMs 这是我所有的原始组件代码转储到代码沙箱中,仅供查看,无需 Firebase 依赖等。codesandbox.io/s/usage-5qj4u @William 很难在视频中发布的代码中看到...您共享的代码框根本不工作...我需要一个显示问题的工作代码框,从那里我可以采取...无论如何,您可以向firebase添加一些虚拟数据并将其公开以供阅读,然后在您设置的示例中使用该数据 我用一个虚拟数据库创建了一个精简版的应用程序,并将其推送到 Github 并附上说明。这是我能做的最好的。看看有没有帮助:github.com/wktdev/wm_troubleshooting

以上是关于将事件处理程序绑定到文档并通过 useEffect 访问 firebase api 数据的主要内容,如果未能解决你的问题,请参考以下文章

如何将事件处理程序绑定到 jQuery 中的实例?

EXTJS,无法将事件处理程序绑定到控制器

将命令绑定到事件?

使用 jQuery 访问绑定到事件处理程序的函数

如何将 WPF 中的命令绑定到控件的双击事件处理程序?

将许多控制事件绑定到同一个处理程序,获取发送者