0

I have created a function and, depending on the case, I wish to recall the same function

 buildRoute(listRoutes){
    return(
      <Switch>
        {listRoutes.map((prop, key) => {
          if(prop.subMenus != null){
            if(prop.path !== undefined){
              return
                this.routes(prop, key);
                this.buildRoute(prop.subMenus);
            }else{
              return this.buildRoute(prop.subMenus);
            }
          }else{
            return this.routes(prop, key);
          }
        })}
      </Switch>
    )
  }

  routes(prop, key){
    if (prop.redirect){  
      return <Redirect from={prop.path} to={prop.to} key={key} />;
    }else if(prop.private){        
      return <PrivateRoute authenticated={JSON.parse(localStorage.getItem(IS_AUTHENTICATED))} path={prop.path} component={prop.component} key={key} />;
    }else{
      return <Route path={prop.path} component={prop.component} key={key} />;
    }
  }

But I have this error : VM3056 53.chunk.js:89036 Warning: Each child in an array or iterator should have a unique "key" prop.

Check the render method of APP. in Switch (at Dashboard.jsx:84) in APP (created by WithStyles(APP)) in WithStyles(APP) (created by Route) in Route (at src/index.js:46) in Switch (at src/index.js:42) in Router (at src/index.js:41) in I18nextProvider (at src/index.js:40)

My listRoute :

        const dashboardRoutes = [
      {
        private: true,
        path: "/private/dashboard",
        sidebarName: "menu.sidebarName.dashboard",
        navbarName: "header.navbarName.dashboard",
        icon: Dashboard,
        component: DashboardPage
      },
      {
        private: true,
        path: "/private/MENU1",
        navbarName: "header.navbarName.MENU1",
        component: MENU1,
        sidebarName: "menu.sidebarName.MENU1",
        code: "MENU1",
        icon: "content_paste",
        subMenus:[
          {
        subMenu: true,
        private: true,
        path: "/private/MENU1_SOUS_MENU1",
        sidebarName: "menu.sidebarName.MENU1_SOUS_MENU1",
        navbarName: "header.navbarName.MENU1_SOUS_MENU1",
        code: "MENU1_SOUS_MENU1",
        icon: "content_paste",
        component: MENU1_SOUS_MENU1
      },
      {
        subMenu: true,
        private: true,
        path: "/private/MENU1_SOUS_MENU2",
        sidebarName: "menu.sidebarName.MENU1_SOUS_MENU2",
        navbarName: "header.navbarName.MENU1_SOUS_MENU2",
        code: "MENU1_SOUS_MENU2",
        icon: "content_paste",
        component: MENU1_SOUS_MENU2
      }
    ]
   },
   {
        sidebarName: "menu.sidebarName.MENU12",
        code: "MENU12,
        icon: "content_paste",
        subMenus:[
          {
        subMenu: true,
        private: true,
        path: "/private/MENU2_SOUS_MENU1",
        sidebarName: "menu.sidebarName.MENU2_SOUS_MENU1",
        navbarName: "header.navbarName.MENU2_SOUS_MENU1",
        code: "MENU2_SOUS_MENU1",
        icon: "content_paste",
        component: MENU2_SOUS_MENU1
      },
      {
        subMenu: true,
        private: true,
        path: "/private/MENU2_SOUS_MENU2",
        sidebarName: "menu.sidebarName.MENU2_SOUS_MENU2",
        navbarName: "header.navbarName.MENU2_SOUS_MENU2",
        code: "MENU2_SOUS_MENU2",
        icon: "content_paste",
        component: MENU2_SOUS_MENU2
      }
    ]
  },
   .....
  { 
    redirect: true, 
    path: "/private", 
    to: "/private/dashboard"
  }
  ]
5
  • the jsx of those functions you are calling need a unique key prop reactjs.org/docs/lists-and-keys.html#keys Commented Dec 11, 2018 at 16:42
  • I saw this link but I didn’t find the solution to my problem Commented Dec 11, 2018 at 16:45
  • can you provide a sample listRoutes contents passed to buildRoute ? Commented Dec 11, 2018 at 16:48
  • also return this.routes(prop, key); this.buildRoute(prop.subMenus); this will only return the this.routes(prop, key); Commented Dec 11, 2018 at 16:50
  • I updated my post Commented Dec 11, 2018 at 16:55

3 Answers 3

1

The problem is that your buildRoute can either return a Route or another Switch. Your Switch components do not have a key, though.

Also you have

if(prop.path !== undefined){
          return
            this.routes(prop, key);
            this.buildRoute(prop.subMenus);
        }

this will actually return nothing. And even if you move this.routes in the same line with return it will only return that and the this.buildRoute(prop.subMenus); will never be called. You should return an array with both elements in it.

All fixes together (notice i am changing the signature of the buildRoute to accept an additional parameter)

buildRoute(listRoutes) {
    return (
        {listRoutes.map((prop, key) => {
          if (prop.subMenus != null) {
            if (prop.path !== undefined) {
              return [
                this.routes(prop, key),
                this.buildRoute(prop.subMenus)
              ];
            } else {
              return this.buildRoute(prop.subMenus);
            }
          } else {
            return this.routes(prop, key);
          }
        })}
    );
  }
  
render(){
  return <Switch>{this.buildRoute(dashboardRoutes)}</Switch>;
}


On further notice, you cannot have nested Switch elements (see https://github.com/ReactTraining/react-router/issues/6199).

So remove the nestingSwitch and wrap the results of buildRoute on a single Switch

Demo at https://codesandbox.io/s/ppwk4qnrox

Sign up to request clarification or add additional context in comments.

8 Comments

I have updated my listRoute with the all possibilities.
@dna i had accidentally removed a , key from one of the this.routes(..). Updated answer
It is the same result
@dna what result is that ? You get the error about Each child in an array or iterator should have a unique "key" prop ?
I have the same error : Warning: Each child in an array or iterator should have a unique "key" prop. The problem is most likely MENU2 with no path
|
0

That error is just because you haven't specified a key when you map through you listRoutes. You're not showing the this.routes method in your code here. But I guess it's there your're returning your JSX element. So you should set a key in there. You're already passing in the key so just use that one if you don't have a better choice.

5 Comments

What is the solution ?
@dna The second part of this answer is the solution: “So you should set a key in there. You're already passing in the key so just use that one if you don't have a better choice.
When I call my function buildRoute(), I don't have a key
Youre not returning any JSX in your buildRoute. But in routes your'e returning JSX elements. So you can use the key your'e passing in to that method and set the key in your components your'e returning.
When I call buildRoute for the first time, what are parameters to pass?
0

You need to clone element so you can actually pass it a key. Passing down the key to child function doesn't works AFAIK.

buildRoute (listRoutes) {
  return (
    <Switch>
      {listRoutes.map((prop, key) => {
        if (prop.subMenus != null) {
          if (prop.path != null) {
            return React.cloneElement([
              this.routes(prop),
              this.buildRoute(prop.subMenus)
            ], { key });
          } else {
            return React.cloneElement(this.buildRoute(prop.subMenus), { key })
          }
        } else {
          return React.cloneElement(this.routes(prop), { key });
        }
      })}
    </Switch>
  )
}

Then you can remove the key argument from routes function. Also remove key={key} in the return's.

Another solution can be to wrap everything into a "wrapper" whose set the key.

buildRouteItem (prop) {
  if (prop.subMenus != null) {
    if (prop.path != null) {
      return [
        this.routes(prop),
        this.buildRoute(prop.subMenus)
      ]
    } else {
      return this.buildRoute(prop.subMenus);
    }
  } else {
    return this.routes(prop);
  }
}

buildRoute (listRoutes) {
  return (
    <Switch>
      {listRoutes.map((prop, key) => (
        <div key={key}>
          {this.buildRouteItem(prop)}
        </div>
      ))}
    </Switch>
  )
}

2 Comments

Route redirect /private to /private/dashboard not working.
I have updated my listRoute with the all possibilities.

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.