i'm first times make routing in my app
help me please
react-dom.development.js:26740 Uncaught Error: You cannot render a inside another . You should never have more than one in your app.
I used a Router inside a component. Then I decided to make routing for the entire application. And I get an error.
How can I rewrite the routing so that the Router works inside the component
app
const App = () => {
return (
<Routes>
<Route path="/" element={<MainPage />} />
<Route path="a" element={<StartSearchingPage />} />
<Route path="UserNotFoundPage" element={<UserNotFoundPage />} />
<Route path="404" element={<Page404 />} />
</Routes>
);
};
export default App;
index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
,
</React.StrictMode>,
);
Pagination
const PaginationButton = (page, handleChange, res) => {
return (
<NavLink
onClick={() => handleChange(res + 1)}
to={`/users/repos/page/${res + 1}`}
className={cn(styles.pagination__item, {
[styles.active]: page === res + 1,
})}
key={res}
>
{res + 1}
</NavLink>
);
};
const Pagination = ({
handleClickPrev,
pageSize,
page,
reposCount,
amount,
handleChange,
handleClickNext,
}) => {
return (
<Router>
<div className={styles.pagination__wrap}>
<ul className={styles.pagination__list}>
<div className={styles.pagination__count}>
{pageSize * page <= reposCount ? pageSize * page - 4 : reposCount}
-
{pageSize * page <= reposCount ? pageSize * page : reposCount}
{' '}
of
{' '}
{' '}
{reposCount}
{' '}
items
</div>
<button
type="button"
className={styles.pagination__arrowleft}
draggable="false"
onClick={() => handleClickPrev()}
>
</button>
{amount?.length > 7 ? (
<>
{page < 3
&& [...amount].splice(0, 3).map((res) => {
return PaginationButton(page, handleChange, res);
})}
{page === 3
&& [...amount].splice(0, 4).map((res) => {
return PaginationButton(page, handleChange, res);
})}
{page > 3
&& [...amount].splice(0, 1).map((res) => {
return PaginationButton(page, handleChange, res);
})}
<span className={styles.pagination__item}>...</span>
{page > 3
// eslint-disable-next-line no-unsafe-optional-chaining
&& page < amount?.length - 2
&& [...amount].splice(page - 2, 3).map((res) => {
return PaginationButton(page, handleChange, res);
})}
{page > 3 && page < amount.length - 2 && (
<span className={styles.pagination__item}>...</span>
)}
{page < amount.length - 2
&& [...amount].splice(amount.length - 1, 1).map((res) => {
return PaginationButton(page, handleChange, res);
})}
{page === amount.length - 2
&& [...amount].splice(amount.length - 4, 4).map((res) => {
return PaginationButton(page, handleChange, res);
})}
{page > amount.length - 2
&& [...amount].splice(amount.length - 3, 3).map((res) => {
return PaginationButton(page, handleChange, res);
})}
</>
) : (
amount?.map((res) => {
return PaginationButton(page, handleChange, res);
})
)}
<button
type="button"
className={styles.pagination__arrowright}
draggable="false"
onClick={() => handleClickNext()}
>
</button>
</ul>
</div>
</Router>
);
};
You need to remove the Router component from Pagination. It looks to me that you do not need that even.
Should you nest Route it should be a child of Route like this, not Router.
const App =() => {
return (
<Routes>
<Route path="invoices" element={<Invoices />}>
<Route path=":invoiceId" element={<Invoice />} />
<Route path="sent" element={<SentInvoices />} />
</Route>
</Routes>
);
}
https://reactrouter.com/docs/en/v6/getting-started/overview#nested-routes
The error is very clear, you have rendered the <Router> component more than once in your App. Just remove the extra one from Navigation.
The <Router> component is just where you define the routes.
You will have to remove BrowserRouter tag from index.js
Your index.js file will be
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={ <App /> }>
</Route>
</Routes>
</BrowserRouter>
</React.StrictMode>
);
And App.js will be
const App = () => {
return (
<div className="app">
<Routes>
<Route exact path="/" element={<MainPage />} />
<Route exact path="/a" element={<StartSearchingPage />} />
<Route exact path="/UserNotFoundPage" element={<UserNotFoundPage />} />
<Route exact path="/404" element={<Page404 />} />
</Routes>
</div>
);
};
export default App;
Related
I use 6.8.1 react-router-dom and react is 18.0.9.
How I can render the page in nested route condition (for example: render the page, MemberExample1 in MemberDetail, once it is clicked)?
Here is how the logic flow. It works until I click and (expected) render the page.
MemberMgt.tsx ->
opened MemberDetail.tsx (from MemberMgt.tsx) ->
Click MemberNavbar's one of button. (Should render the page based on its link and path ON MemberDetail.tsx.)
src > routers.tsx
const Routers = (): JSX.Element => {
const location = useLocation();
return (
<Routes location={location}>
<Route path="/" element={<Main />} />
<Route path="/designsystem" element={<DesignSystem />} />
<Route path="/modal" element={<ModalPage />} />
<Route path="*" element={<NotFound />} />
<Route path="/servermgt" element={<ServerMgt />} />
<Route path="/membermgt">
<Route path="" element={<MemberMgt />} />
<Route path="detail/:id/*">
{/* MemberDetail is the page I should render button when clicked. */}
<Route path="" element={<MemberDetail />} />
</Route>
</Route>
MemberMgt.tsx
src > pages > MemberMgt
return (
// note: viewList is custom hook. This state refers to the custom hook's state.
{_.map(state.viewList, (item, key) => {
<tr
key={key}
onClick={(e) => {
console.log(item.active);
onChoice(item.id);
navigate(`detail/${String(item.data.idx)}`, { state: item.data });
}}
>
MemberDetail.tsx -
This file act as a middle page to display the other page once the button is clicked.
src > pages > MemberMgt> MemberDetail.tsx
import MemberBrief from './MemberDetailMenu/MemberBrief/MemberBrief';
import MemberExample1 from './MemberDetailMenu/MemberMsMed/MemberExample1';
import MemberExample2 from './MemberDetailMenu/MemberPoint/MemberExample2';
import MemberExample3 from './MemberDetailMenu/MemberWarn/MemberExample3';
import MemberNavbar from './MemberDetailMenu/MemberNavbar';
const MemberDetail = () => {
// this state does not refer to the custom hook!
const { state } = useLocation();
return (
<div className="title-box">
<h5>Main - Detail Page</h5>
</div>
<>
<div className="detail-box-detail">
<div className="detail-global-container-gray">
<div className="memberNavbar">
<MemberNavbar />
</div>
{/* nested Route */}
<Routes>
<Route path="*" element={<MemberBrief />} />
{/* <Route path="/brief" element={<MemberBrief />} /> */}
<Route path="/example1" element={<Example1 />} />
<Route path="/example2" element={<Example2 />} />
<Route path="/example3" element={<Example3 />} />
</Routes>
</div>
</div>
</>
)}
Lastly, this is the button, MemberNavbar.tsx.
src > pages > MemberMgt > MemberDetailMenu > MemberNavbar
const MemberNavbar = () => {
const navigate = useNavigate();
const param = useParams();
const handleClickBrief = () => {
navigate(`/membermgt/detail/${param.id as string}`);
};
const handleClickExample1 = () => {
navigate(`/membermgt/detail/${param.id as string}/example1`);
};
const handleClickExample2 = () => {
navigate(`/membermgt/detail/${param.id as string}/example2`);
};
const handleClickExample3 = () => {
navigate(`/membermgt/detail/${param.id as string}/example3`);
};
return (
<div className="detail-button">
{/* <Button style="filled" size="md" onClick={handleInfoClick}> */}
<Button onClick={handleClickBrief} style="transparent" size="md">
Main - detail page
</Button>
<Button onClick={handleClickExample1} style="transparent" size="md">
Example1
</Button>
<Button onClick={handleClickExample2} style="transparent" size="md">
Example2
</Button>
<Button onClick={handleClickExample3} style="transparent" size="md">
Example3
</Button>
</div>
);
};
I'm updating a sourcecode from react-router-5 to version 6. So far I'm getting this error:
Error: [div] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>
The bug is triggered when I activate a link in this component(QuoteItem.js):
const QuoteItem = (props) => {
return (
<li className={classes.item}>
<figure>
<blockquote>
<p>{props.text}</p>
</blockquote>
<figcaption>{props.author}</figcaption>
</figure>
<div className={classes.item}>
<Link className='btn' to={`/quotes/${props.id}`}>View Fullscreen</Link>
</div>
</li>
);
};
in another component (VerQuotes) I defined the routes:
const VerQuotes = () => {
return (
<div>
<main>
<Layout>
<Routes>
<Route path="quotes" element={<AllQuotes />} />
<Route path="new-quote" element={<NewQuote />} />
<Route path="quotes/:quoteId" element={<QuoteDetail />} />
</Routes>
</Layout>
</main>
</div>
);
};
I'm kind of lost how to tackle the error, your comments will be highly appreciated.
Thanks a lot
Update
QuoteDetail
const QuoteDetail = () => {
const match = useNavigate();
const params = useParams();
const { quoteId } = params;
const { sendRequest, status, data: loadedQuote, error } = useHttp(getSingleQuote, true);
//const quote = DUMMY_NOTES.find((quote) => quote.id === params.quoteId);
useEffect(() => {
sendRequest(quoteId);
}, [sendRequest, quoteId]);
if(status === "pending"){
return (
<div className="centered">
<LoadingSpinner />
</div>
);
}
if(error){
return <p className="centered">{error}</p>;
}
if (!loadedQuote.text) {
return <p>No Quote Found!</p>;
}
return (
<Fragment>
<HighlightedQuote text={loadedQuote.text} author={loadedQuote.author} />
<Routes>
<Route path={match}>
<div className="centered">
<Link
className="btn--flat"
to={`${match}/comments`}
>
Load Comments
</Link>
</div>
</Route>
<Route path={`${match}/comments`} element={<Comments />}></Route>
</Routes>
</Fragment>
);
};
Issues
After tracing your code I found you had a couple issues in QuoteDetail component.
You used const match = useNavigate(); (so match is really the navigate function) but then later used match to attempt to form a path string for a Route.
The Route component's children prop is only for rendering nested routes. The error you see is the use of the div element that isn't a Route component.
Code
<Routes>
<Route path={match}>
<div className="centered">
<Link
className="btn--flat"
to={`${match}/comments`}
>
Load Comments
</Link>
</div>
</Route>
<Route path={`${match}/comments`} element={<Comments />}></Route>
</Routes>
Solution
Remove const match = useNavigate(); since it is not used, and place the div into the element prop of the Route. Change the path props to use relative routing from the current route path that's already been built up.
const QuoteDetail = () => {
const params = useParams();
const { quoteId } = params;
const { sendRequest, status, data: loadedQuote, error } = useHttp(
getSingleQuote,
true
);
//const quote = DUMMY_NOTES.find((quote) => quote.id === params.quoteId);
useEffect(() => {
sendRequest(quoteId);
}, [sendRequest, quoteId]);
if (status === "pending") {
return (
<div className="centered">
<LoadingSpinner />
</div>
);
}
if (error) {
return <p className="centered">{error}</p>;
}
if (!loadedQuote.text) {
return <p>No Quote Found!</p>;
}
return (
<Fragment>
<HighlightedQuote text={loadedQuote.text} author={loadedQuote.author} />
<Routes>
<Route
path="/"
element={
<div className="centered">
<Link className="btn--flat" to="comments">
Load Comments
</Link>
</div>
}
/>
<Route path="comments" element={<Comments />} />
</Routes>
</Fragment>
);
};
so I have the private routes set up in App.js. The other components in the private routes render correctly. The About Component isnt rendering. Before I was getting an error saying something along the lines of expected a string but got an object. Now I can goto the about page and the error is gone. I console.log props and slides but it doesnt show up in the console. I am passing props(slides) in the Private route to About.js.
Hi. Ive been stuck on this for two days now. PRivate route doesnt show the About component. It works on all other components. Code is below.Any help is greatly appreciated.
function App() {
return (
<div className="App">
<Nav/>
<main>
<Switch>
<PrivateRoute exact path="/home" component={Home} />
<PrivateRoute path="/resources" component={Resources} />
<PrivateRoute path = "/about" component={ About} slides= {SliderData} />
<PrivateRoute path="/mealplan" component={MealPlan} />
</Switch>
<Route exact path="/" component={SignUp} />
<Route path="/login" component={Login} />
</main>
</div>
);
}
export default App;
function About(slides) {
const [current, setCurrent] = useState(0);
const length = slides.length
if (!Array.isArray(slides) || slides.length <= 0) {
return null;
}
const nextSlide = () => {
setCurrent(current === length - 1 ? 0 : current + 1);
};
const prevSlide = () => {
setCurrent(current === 0 ? length - 1 : current - 1);
};
return (
<>
<section className="slider">
<FaArrowAltCircleLeft onClick={prevSlide} className="left-arrow" />
<FaArrowAltCircleRight onClick={nextSlide} className="right-arrow" />
{SliderData.map((slide, index) => {
return (
<div className={index === current ? "slide-active" : "active"} key={index}
>
{index === current && (
<img src={slide.image} alt="dog" className="dog-img" />
)}
</div>
);
})}
</section>
</>
Private Route
const PrivateRoute = ({component: Component, ...rest}) => {
return(<Route {...rest} render={
(props) => {
if (localStorage.getItem("token")) {
return <Component {...props}/>;
} else {
return(<Redirect to='/login'/>);
}
}
}/>);
};
Like I said it works on the other components but not the About Component. I have tried everything I can think of but cant get it to render
The issue is that you are trying to pass additional props through PrivateRoute to the component but don't pass them all the way through. You only pass the route props through.
PrivateRoute
const PrivateRoute = ({ component: Component, ...rest }) => {
return(
<Route
{...rest}
render={
(props) => {
if (localStorage.getItem("token")) {
return <Component {...props}/>; // <-- only route props from `render`
} else {
return(<Redirect to='/login'/>);
}
}}
/>
);
};
Refactor the PrivateRoute so it renders more like a plain Route component.
const PrivateRoute = (props) => {
return localStorage.getItem("token") ? (
<Route {...props} />
) : (
<Redirect to='/login'/>
);
};
Now use the render prop to render the About component and pass the additional prop(s) through.
function App() {
return (
<div className="App">
<Nav/>
<main>
<Switch>
<PrivateRoute exact path="/home" component={Home} />
<PrivateRoute path="/resources" component={Resources} />
<PrivateRoute
path="/about"
render={props => (
<About {...props} slides= {SliderData} />
)}
/>
<PrivateRoute path="/mealplan" component={MealPlan} />
</Switch>
<Route exact path="/" component={SignUp} />
<Route path="/login" component={Login} />
</main>
</div>
);
}
Ensure you are accessing the slides prop correctly. I.E. props.slides.
function About({ slides }) {
const [current, setCurrent] = useState(0);
const length = slides.length
if (!Array.isArray(slides) || slides.length <= 0) {
return null;
}
const nextSlide = () => {
setCurrent(current === length - 1 ? 0 : current + 1);
};
const prevSlide = () => {
setCurrent(current === 0 ? length - 1 : current - 1);
};
return (
<>
<section className="slider">
<FaArrowAltCircleLeft onClick={prevSlide} className="left-arrow" />
<FaArrowAltCircleRight onClick={nextSlide} className="right-arrow" />
{SliderData.map((slide, index) => {
return (
<div className={index === current ? "slide-active" : "active"} key={index}
>
{index === current && (
<img src={slide.image} alt="dog" className="dog-img" />
)}
</div>
);
})}
</section>
</>
);
}
I have a problem in nested routing in React.js.
The presenter component has this.
<Route
exact
path={`/course/${id}/assignment`}
render={(props) => (
<CourseAssignments
{...props}
courseId={id}
data={assignmentData}
/>
)}
/>
And here is CourseAssignments component at /course/${id}/assignment.
const CourseAssignments: React.FC<RouteComponentProps & IProps> = ({
courseId,
data,
match,
}) => {
return (
<Container>
<Route
exact
path={match.path}
render={(props) => (
<AssignmentList {...props} courseId={courseId} data={data} />
)}
/>
<Route path={`${match.path}/:id`} component={AssignmentSubmit} />
</Container>
);
};
The AssignmentList renders well at course/0/assignment.
const AssignmentList: React.FC<RouteComponentProps & IProps> = ({
match,
courseId,
data,
}) => {
return (
<div>
{data.map((d) => (
<div key={d.id}>
<Link to={`${match.url}/${d.id}`}>{d.title}</Link>
</div>
))}
</div>
);
};
I use <Link />, it links to course/0/assignment/:id.
But course/0/assignment/1 doesn't render AssignmentSubmit component.
I don't know why it doesn't work. Pleaze help.
(env is localhost)
I am trying add a custom styling to the active route inside the navigation component inside the dashboardlayout, but I am not able to get the current route inside the current component.
const Index = props => {
return (
<BrowserRouter>
<DashboardLayout>
<Route exact path='/' component={Dashboard} />
<Route exact path='/earnings' component={Earnings} />
<Route exact path='/comms' component={Comms} />
<Route exact path='/rankings' component={Rankings} />
<Route exact path='/ratings' component={Ratings} />
<Route exact path='/ads' component={Ads} />
<Route exact path='/settings' component={Settings} />
<Route exact path='/ad/details' component={AdDetails} />
<Route exact path='/ad/submit-sample' component={SubmitSample} />
<Route exact path='/feedback' component={Feedback} />
</DashboardLayout>
</BrowserRouter>
);
};
export default Index;
I made a little component that looks like this:
import React from 'react';
import { Route, Link } from 'react-router-dom';
const Nav = ({
children,
to,
exact,
onClick,
className,
...rest
}) => (
<Route
path={to}
exact={exact}
children={({ match }) => (
<Link
// Assign class and active class name
className={match ? `${className} act-link` : className}
to={to}
replace={match && to === match.path}
onClick={(e) => {
// Avoid clicking the current route
if (!match || to !== match.path) {
onClick(e);
}
}}
{...rest}
>
{children}
</Link>
)}
/>
);
You can use it this way:
const NavList = ({
links,
toggleOpened,
}) => (
<ul className="main-menu">
{
links.map((link) => (
<li
key={link.name}
className={link.className}
>
<NavLink
className="icon-w"
to={link.url}
onClick={(e) => {
e.target.focus();
toggleOpened(false);
}}
>
<div className={`os-icon ${link.icon}`} />
</NavLink>
</li>
))
}
</ul>
);
Hope it helps