React: Fix missing dependency warning useEffect with Refs

Viewed 159

I have a functional component where if I have some error calling an API I want to open a Modal showing that error. The property who decides if this modal is open is stored using context API. So I had this code in the component:

  const modalContext = useContext(ModalContext);

  useEffect(() => {
    if (error !== "") {
      modalContext.showModal();
    }
  }, [error]);

But I have this warning:

React Hook useEffect has a missing dependency: 'modalContext'. Either include it or remove the dependency array react-hooks/exhaustive-deps

I read that to fix this issue I can use refs, so I changed the code and now I have:

  const modalContextRef = React.useRef(false);
  modalContextRef.current = useContext(ModalContext);

  useEffect(() => {
    if (error !== "") {
      modalContextRef.current.showModal();
    }
  }, [error]);

I wonder if this is the correct way to proceed or if it's a bad practice.

Thanks!

2 Answers

You can try to add modalContext to its dependencies.

useEffect(() => {
  if (error !== "") {
    modalContext.showModal();
  }
}, [error, modalContext]);

Maybe the following will work for you:

const ModalContext = React.createContext();
const ModalProvider = ({ children }) => {
  const [isModalOpen, setIsModalOpen] = React.useState(
    false
  );
  //show modal never changes because using useCallback
  const showModal = React.useCallback(
    () => setIsModalOpen(true),
    []
  );
  return (
    <ModalContext.Provider
      value={{
        isModalOpen,
        showModal,
      }}
    >
      {children}
    </ModalContext.Provider>
  );
};
const Modal = () => {
  const { isModalOpen } = React.useContext(ModalContext);
  return isModalOpen ? 'modal shows' : null;
};
const App = () => {
  const [error, setError] = React.useState('');
  const { showModal } = React.useContext(ModalContext);

  React.useEffect(() => {
    if (error !== '') {
      showModal();
    }
  }, [error, showModal]);
  return (
    <div>
      <button onClick={() => setError('error')}>
        set error
      </button>
      <Modal />
    </div>
  );
};

ReactDOM.render(
  <ModalProvider>
    <App />
  </ModalProvider>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Related