3

I have requirement where I need to load component from dynamic folders. For example I have following folders inside components

components  
    -default
        -component-one
        -component-two
        -component-three
    -custom
        -component-three

Suppose if componentFolder state set to custom folder then it should load from custom folder .if any component not found in custom folder then it should be load from default folder. So my question is ,can we possible to import recursively ?

 function App() {
 
const [componentFolder, setComponentFolder] = React.useState("default")

const Home = React.lazy(() => import("./components/" +componentFolder+ "/Home"));
  return (
    <div className="App">
      <Suspense fallback="laoding">
        <Home></Home>
      
      </Suspense>

    </div>
  );
}

the below link has same requirement as i asked How to check if a pariticular fileExists in reactjs

3
  • @ajeet thanks for mentioning...but one point helped regarding rerender Commented Apr 13, 2021 at 14:26
  • Is this a CRA project? Commented Apr 17, 2021 at 17:55
  • Note : bounty question expires in 2 hours so giving bounty to one of the below answers for their effort . Commented Apr 19, 2021 at 11:56

5 Answers 5

4

If you are using Webpack then you can use require.context to load modules dynamically:

import React, { Suspense } from "react";

const load = async (path, file) => {
  const defaultPath = "default";
  const files = require.context("./components", true, /\.js$/);
  try {
    return files(`./${path}/${file}.js`);
  } catch (err) {
    return files(`./${defaultPath}/${file}.js`);
  }
};

export default function App() {
  const [componentFolder, setComponentFolder] = React.useState("default");
  const Home = React.lazy(() => load(componentFolder, "Home"));
  return (
    <div className="App">
      <Suspense fallback="loading">
        <Home />
      </Suspense>
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

4 Comments

@lissettdm.thanks for the answer .i am not using reactjs using create react app.i am not sure its webpack or not.since i am beginner to reactjs .
What module bundler are you using? can you check that?
i sorry my previous comment has wrong typo.I am using reactjs using create react app create-react-app.dev/.Also i am okay with different solution other than lazy loading if my requirement satisfies
CRA use Webpack as module bundle. You can use require.context to load modules dynamically and you can combine it with Lazy load
2

Since lazy returns a promise, you can use its catch block to return another lazy (promise) when the original module was not found.

An example:

import { lazy, Suspense, useState } from "react";

const rotate = {
  custom: "default",
  default: "custom",
};

function App() {
  const [folder, setFolder] = useState("custom");
  const [name, setName] = useState("component1");

  // Here: catch and return another lazy (promise)

  const Component = lazy(() =>
    import("./components/" + folder + "/" + name).catch(
      (err) => import("./components/" + rotate[folder] + "/" + name)
    )
  );

  return (
    <div>
      <Suspense fallback="laoding">
        <Component />
      </Suspense>
      <button onClick={() => setFolder(rotate[folder])}>toggle folder</button>
      <br />
      <button onClick={() => setName("component1")}>load component 1</button>
      <button onClick={() => setName("component2")}>load component 2</button>
      <button onClick={() => setName("component3")}>load component 3</button>
    </div>
  );
}

Here is a demo.


Note that Component, defined/created inside App component, will be recreated at every rerender of App. It will cause Component to reset its state when App rerenders.

3 Comments

thanks but i am looking for recursive since it might be multiple parent child hierarchy so .For example default->custom->client-specific then it will first check in client -specific then it will check in custom then its go to default .is there any solution's will try this anyway
Hm. I thought you wrote "recursive" by mistake as I saw no recursive path in your example.
@ajeeh.yes i have tried many methods but couldn't succeeded so .even other solution other than lazy loading also fine.thanks for your effort
1
+50

Based in the others answers and comments here I came up with this:

https://codesandbox.io/s/so-react-lazy-recursive-import-2dqlp?file=/src/App.js

import React, { lazy, Suspense } from "react";

// test the code by removing the _ in front of file names

/*
components/
  comp 🚫 3? a root file will not trigger -> go to default
  
  /default
    comp 👈 3! nice ^^ (but if it not exists will throw an error)

  /custom
    comp 👈 2?
    /client
      comp 👈 1?
        /omgStop
          heIsAlreadyDead (but works)
    /otherClient ...
*/

const recursiveImport = async (
  componentName,
  targetTree,
  defaultTree = "./components/default"
) => {
  console.count("paths tested");
  if (!targetTree) {
    return import(defaultTree + "/" + componentName);
  }

  return import("./components/" + targetTree + "/" + componentName).catch(
    () => {
      const newTreeArr = targetTree.split("/");
      newTreeArr.pop();
      const newTree = newTreeArr.join("/");
      return recursiveImport(componentName, newTree, defaultTree);
    }
  );
};

export default function App() {
  const targetTree = "custom/client1";
  const Component = lazy(() => recursiveImport("Test", targetTree));

  return (
    <div>
      <Suspense fallback="loading">{<Component />}</Suspense>
    </div>
  );
}

Folder structure:

enter image description here

This solves all of your requirements?

1 Comment

Note : bounty question expires in 2 hours so giving bounty to one of the below answers for their effort .i will try this soon and let you know .
0

Simple and objective

const Recipe = React.lazy(() =>
  import(`docs/app/Recipes/${props.componentName}`)
  .catch(() => ({ default: () => <div>Not found</div> }))
);

Comments

-2

I was trying something, endup with a simple solution that you should reach before:

https://codesandbox.io/s/awesome-violet-fr7np?file=/src/App.js

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.