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>
</>
);
}
Related
In the react hooks web, I have a component called NominatePerson, in that component if the props.role is not admin it should display text Nomination View and if its admin then it should display Dashboard. This is not happening, it always displays Dashboard. Could someone help me to resolve the issue ?
App.js
function App() {
const [role, setRole] = useState();
useEffect(() => {
const fetchData = async () => {
try {
const userEmail = localStorage.getItem("loginEmail");
const res = await Axios.get(
"http://localhost:8000/service/managenomineeaccess",
{ params: { userEmail } }
);
console.log(res.data[0][0].access, "rest.data");
const data = res.data[0][0].access;
setRole(data);
} catch (e) {
console.log(e);
}
};
fetchData();
}, []);
const switchAdmin = (
<Switch>
<Route exact path='/' component={() => <Login role={role} />} />
<ProtectedRoute exact path='/dashboard' component={DashboardLayout} />
<ProtectedRoute exact path='/manageNominees' component={ManageNominees} />
<Route path='/nominatePerson' exact component={NominatePerson} />
<Route path='/nominationView' exact component={NominationView} />
</Switch>
);
const switchUser = (
<Switch>
<Route exact path='/' component={Login} />
<Route
path='/nominatePerson'
exact
component={() => <NominatePerson role={role} />}
/>
<Route
path='/nominationView'
exact
component={() => <NominationView role={role} />}
/>
<Route component={NominationView} />
</Switch>
);
return (
<Router>
<div>
<ThemeProvider theme={theme}>
<GlobalStyles />
{role === "admin" ? switchAdmin : switchUser}
</ThemeProvider>
</div>
</Router>
);
}
export default App;
NominatePerson
const NominatePerson = (props) => {
return (
<div className='leftNavItem'>
<a>
<Link
to={props.role ? "/nominationView" : "/dashboard"}
className='nav-link'
>
<b>{props.role ? "Nomination View" : "Dashboard"}</b>
</Link>
</a>
</div>
)
}
server.js // get service
app.get("/service/managenomineeaccess", async (req, res) => {
try {
let userEmail = req.query.userEmail;
let data = await sequelize.query(
`SELECT access FROM devchoice.managenominees where email="${userEmail}";`
);
res.status(200).send(data);
} catch (e) {
res.status(500).json({ fail: e.message });
}
});
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;
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>
);
};
Need help with pagination. Right now my app can change page, but if I want send request like /character?page=4 it always throw me /character?page=1 this is not help, coz I use router. I have no idea how to resolve my problem
My app.js
function App() {
return (
<>
<Router>
<Header />
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/character' component={AllCharacters} />
<Route component={NotFound} />
</Switch>
<Footer />
</Router>
</>
);
}
CharacterList.jsx
// API Data
const url = "https://rickandmortyapi.com/api/character";
// Fetching Page
const fetchPage = (page) => {
// Init loading while page load
setLoading(true);
const query = `${url}?page=${page}`;
fetchData(query);
setLoading(false);
};
// Change pages
const { push } = useHistory();
const handleChanger = (event, page) => {
fetchPage(page);
push({
pathname: "/character",
search: `?page=${page}`,
});
};
<Pagination
count={info.pages}
showLastButton
showFirstButton
onChange={handleChanger}
/>
Dynamic Pagination : App.js
function App() {
return (
<>
<Router>
<Header />
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/character/page=:page' component={DynamicPagination} />
<Route component={NotFound} />
</Switch>
<Footer />
</Router>
</>
);
}
Dynamic pagination Demo : DynamicPaginaton.js
export default function DynamicPagination() {
const history = useHistory();
const [page, setPage] = React.useState(0);
const [pageCount, setPagcount] = useState(10);
const handlePageChange = (event, value) => {
history.push(`/character/page=${value}`)
setPage(value);
};
return (
<div >
<Typography>page:{page}</Typography>
<Pagination
count={pageCount}
page={page}
onChange={handlePageChange}
style={{ marginTop: 20 }}
/>
</div>
);
}
I am using aws-amplify, react-hook in my project. The app have some private Routes has been define below:
const ProtectedRoute = ({render: C, props: childProps, ...rest}) => {
return (
<Route
{...rest}
render={rProps =>
(childProps) ? (
<C {...rProps} {...childProps} />
) : (
<Redirect
to={`/login?redirect=${rProps.location.pathname}${
rProps.location.search
}`}
/>
)
}
/>
);
}
In App.js, we change childProps to define whether user is login or not. But when childProps change, Switch not re rendering. What is the way to force React re rendering its Route because isAuthenticated is change but ProtectedRoute is not rerender.
const [isAuthenticated, userHasAuthenticated] = useState(null);
useEffect(() => {
onLoad();
}, []);
async function onLoad() {
try {
let user = await Auth.currentSession();
if (user.accessToken.payload) {
userHasAuthenticated(user.accessToken.payload);
}
} catch (e) {
if (e !== 'No current user') {
alert(e);
}
}
}
.....
const childProps = isAuthenticated;
return (
<ApolloProvider client={client} >
<div className="App">
<BrowserRouter>
<Route path='/'>
<div>
<Switch>
<Route path='/login' render={props => <Login {...props}/>} exact/>
<ProtectedRoute
exact
path='/admin/:name'
render={()=> <Admin />}
props={childProps}
/>
<Route path='/' render={props => <User {...props} />}/>
</Switch>
</div>
</Route>
</BrowserRouter>
</div>
</ApolloProvider>)
The route only renders again when you enter that URL again. You are doing a Redirect, meaning it will never have a chance to enter the same URL after authentication is complete. You should delay rendering the protected route until you have confirmed authentication:
useEffect(() => {
async function onLoad() {
try {
let user = await Auth.currentSession();
userHasAuthenticated(!!user.accessToken.payload);
} catch (e) {
if (e !== 'No current user') {
alert(e);
}
}
}
onLoad();
}, []);
...
const ProtectedRoute = ({render: C, props: childProps, ...rest}) => {
if (childProps === null) {
// app still waiting authentication
return 'Loading...';
}
return (
<Route
{...rest}
render={rProps =>
(childProps) ? (
<C {...rProps} {...childProps} />
) : (
<Redirect
to={`/login?redirect=${rProps.location.pathname}${
rProps.location.search
}`}
/>
)
}
/>
);
}