Search code examples
reactjseslintreact-contextcircular-dependency

React Context dependency cycle eslint error import/no-cycle


I have a two components FirstUIProvider(Parent) and DesktopOverlay(Child) and I want to export a context from Parent to Child but this causes circular dependency which I'm unable to solve.

CustomUIProvider

export default function CustomUIProvider() {

  if (condition1) {
    return <FirstUIProvider />;
  }

  return null;
}

FirstUIProvider

//Dependency cycle detected
import DesktopOverlay from "components/custom-ui/DesktopOverlay";

const FirstUIContext = createContext({} as FirstUIContextType);

  const useFirstUI = () => {
    const context = useContext(FirstUIContext);

    if (!context) {
      throw new Error("useFirstUI must be used within an 
      FirstUIProvider");
    }

  return context;
};

const FirstUIProvider= () => {


  return (
    <FirstUIContext.Provider
      value={{
        value1,
        value2,
        value3,
      }}
    >
      <Grid>
        <DesktopOverlay/>
      </Grid>

    </FirstUIContext.Provider>
  );
};

export { FirstUIProvider, useFirstUI};

DesktopOverlay

//Dependency cycle via 
import { useFirstUI } from "components/custom-ui/providers/FirstUIProvider";

export default function DesktopOverlay() {

  const { value1, value2, value3} = useFirstUI();

  return (
    <Component1 />
    <Component 2/>
  );
}

Solution

  • It's better to not explicitly define children of Context Provider. Usually you define it like this:

    const FirstUIProvider = ({ children }) => {
    
    
      return (
        <FirstUIContext.Provider
          value={{
            value1,
            value2,
            value3,
          }}
        >
          {children}
        </FirstUIContext.Provider>
      );
    };
    
    

    and then have some Desktop component in separate file:

    export const Desktop = () => {
    
      return (
        <FirstUIProvider>
          <Grid>
            <DesktopOverlay />
          </Grid>
        </FirstUIProvider>
      );
    }
    

    In this case you don't need to import any UI component in FirstUIProvider and you won't have circular dependency