Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Saving callback refs into a context to then use within another component

I have a long list component that consists of some big elements. These elements can trigger a notification in a sidebar. I have a sidebar in which I want to be able to scroll to a particular notification: one that triggered this notification. Hence the question from the title:

Can I store some long list of refs within a context? To then use that list to access a ref of a particular element from my list and simply call .scrollIntoView(). I’ve tried:

I created a context like this:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import { createContext, createRef, useContext } from "react";

const ElementRefsContext = createContext();

const elementRefs = createRef({});

export const ElementRefsProvider = ({ children }) => {
  return (
    <ElementRefsContext.Provider value={elementRefs}>
      {children}
    </ElementRefsContext.Provider>
  );
};

export const useElementRefsContext = () => {
  return useContext(ElementRefsContext);
};

function LongListOfBigElements() {
    const { elementRefs } = useElementRefsContext();

    return (
        <>
            {messages?.map((message, index) => (
                <BigElement
                      ref={(el) => {
                          const messageId = message.message_id;
                          const elementId = index;
                              if (elementRefs) {
                                  console.log(workDropdownRefs);
                                  if (!elementRefs.current[messageId]) {
                                   elementRefs.current[messageId] = {};
                              }
                              elementRefs.current[messageId][
                                elementId
                              ] = el;
                            }
                          }}/>)
        </>

>Solution :

Technically, yes you can, but it is something that has to be implemented carefully. It is a minefield in that you can easily create memory leaks since the context can now hold a reference to an element even after it has been potentially removed from the DOM, which would prevent it from being garbage collected.

When the ref callback is called where el is null, it should unset the ref from the context. Your code does this, but holding mutable references is a bit error prone.

However, it’s probably quite a lot easier to lean on simple markup to achieve this. If BigElement assigns messageId (or something derived from it) to some HTML attribute like id. Then, when scrolling, you can simply look up that element and scroll to it using querySelector or otherwise.

This may sound like I’m suggesting hacky code that breaks component encapsulation, but this is possibly the right thing to do here. After all # fragment URLs allow referencing any DOM element ID by default to scroll to it.

If you really don’t want to do that, then you could instead store in the context the activeMessageId. Then, each BigElement would be passed its own messageId via props. Inside of BigElement a useEffect with activeMessageId from the context in the deps array could be used to check if the activeMessageId is equal to the passed props.messageId. If it is, then a local ref could be used with scrollIntoView().

When activeMessageId is updated, the appropriate BigElement will respond.

No storing of DOM elements or refs would be needed outside of the component that owns that DOM element. Which both avoids leaks and reduces complexity.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading