I have following routes in the application:
<Switch>
<Route path="/shops/:id">
<StoreDetails/>
</Route>
<Route path="/shops">
<Stores/>
</Route>
<Route path="/">
<Home/>
</Route>
</Switch>
how do I deep link /shops and /shops/:id URLs??
whith hooks :
import React from 'react';
export const test = props => {
const { match } = props;
const id = match.params.id;
return <></>;
};
Related
I have a component that I am using in React Router v6 for managing private routes, that does some checks on an auth token, and will either render the Outlet component or will redirect to a login page.
I have -
import { Outlet } from 'react-router-dom';
export const CheckAuth = (props) => {
const valid = ...;
if (!valid) {
window.location.replace(loginUrl);
return null;
}
return <Outlet />;
};
and using it like -
<Route element={<CheckAuth token={authToken} />}>
// ... private routes ...
</Route>
I can mock out window.location.replace with Jest
delete window.location;
window.location = { replace: jest.fn() };
...
render(<CheckAuth token={token} />)
expect(window.location.replace).toHaveBeenCalledWith(loginUrl);
but how can I test the Outlet component using Testing Library?
If it helps anyone, I ended up just wrapping the components in the test with a react router components, and passed a dummy component as a child to Route and asserted that some fake text in that component was or was not rendered
Outside the test block -
const FakeComponent = () => <div>fake text</div>;
and for a failure scenario, where the outlet should not render -
render(
<MemoryRouter initialEntries={['/']}>
<Routes>
<Route element={<CheckAuth />}>
<Route path="/" element={<FakeComponent />} />
</Route>
</Routes>
</MemoryRouter>
);
expect(screen.queryByText('fake text')).not.toBeInTheDocument();
and for a success scenario, assert that the text is present -
render(
<MemoryRouter initialEntries={['/']}>
<Routes>
<Route element={<CheckAuth token={correctToken}/>}>
<Route path="/" element={<FakeComponent />} />
</Route>
</Routes>
</MemoryRouter>
);
expect(screen.queryByText('fake text')).toBeInTheDocument();
I have a React App which works well, but I want to implement Code Splitting by using Lazy & Suspense from React,
I tried to do it for routes but I get the following error
Error: A React component suspended while rendering, but no fallback UI was specified.
Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.
Here's my code :
import React, { lazy, Suspense } from "react";
import { Route, Switch } from "react-router-dom";
import "./App.css";
const Home = lazy(() => import("./pages/Home"));
const Stream = lazy(() => import("./pages/Stream"));
const Contact = lazy(() => import("./pages/Contact"));
const Faq = lazy(() => import("./pages/Faq"));
const About = lazy(() => import("./pages/About"));
const Twitch = lazy(() => import("./pages/Twitch"));
const Chat = lazy(() => import("./pages/Chat"));
const Error = lazy(() => import("./pages/Error"));
const Backdrop = lazy(() => import("./components/Backdrop"));
function Router() {
return (
<Suspense fallback={<Backdrop />}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/stream" exact component={Stream} />
<Route path="/contact" exact component={Contact} />
<Route path="/faq" exact component={Faq} />
<Route path="/a-propos" exact component={About} />
<Route path="/twitch" exact component={Twitch} />
<Route path="/chat" exact component={Chat} />
<Route component={Error} />
</Switch>
</Suspense>
);
}
export default Router;
I don't know what's the issue with this ?
Edit: Backdrop component is a component from Material UI enter link description here
Basically, I'm working on the DataTurks project but I've stumbled upon some problems linked to the frontend app named bazaar. I'm trying to create a new component and add a new route for it so I can access it. This is my code for my routes:
import React from 'react';
import {IndexRoute, Route} from 'react-router';
// import { isLoaded as isAuthLoaded, load as loadAuth } from 'redux/modules/auth';
import {
App,
Home,
NotFound,
TaggerLogin,
TaggerSpace,
TaggerCreate,
TaggerImport,
TaggerStats,
TaggerExport,
TaggerProjects,
TaggerAdd,
TaggerOveriew,
TaggerVisualize,
TaggerEdit,
TaggerOrg,
TaggerOrgProject,
TaggerError,
TaggerKeyBind,
TaggerContributors,
ConfirmMail
} from 'containers';
export default (store) => {
const requireLogin = (nextState, replace, cb) => {
const { auth: { user }} = store.getState();
if (!user) {
// oops, not logged in, so can't be here!
replace('/projects/login');
}
cb();
};
/**
* Please keep routes in alphabetical order
*/
return (
<Route path="/" component={App}>
<Route path="confirm" component={ConfirmMail}/> //THIS IS THE COMPONENT I'M TRYING TO ACCESS
{ /* Home (main) route */ }
<IndexRoute component={Home}/>
{ /* Routes requiring login */ }
<Route onEnter={requireLogin}>
<Route path="projects/create" component={TaggerCreate}/>
<Route path="projects/edit" component={TaggerEdit}/>
<Route path="projects/:orgName/create" component={TaggerCreate}/>
<Route path="projects/:orgName/import" component={TaggerImport}/>
<Route path="projects/:orgName/:projectName/edit" component={TaggerEdit}/>
<Route path="projects/:orgName/:projectName/keybind" component={TaggerKeyBind}/>
</Route>
{ /* Dataturks tool */}
<Route path="projects/login" component={TaggerLogin}/>
<Route path="projects/import" component={TaggerImport}/>
<Route path="projects/space" component={TaggerSpace}/>
<Route path="projects/stats" component={TaggerStats}/>
<Route path="projects/export" component={TaggerExport}/>
<Route path="projects" component={TaggerProjects}/>
<Route path="projects/add" component={TaggerAdd}/>
<Route path="projects/overview" component={TaggerOveriew}/>
<Route path="projects/visualize" component={TaggerVisualize}/>
<Route path="projects/errors" component={TaggerError}/>
<Route path="projects/:orgName" component={TaggerOrg} />
<Route path="projects/:orgName/:projectName" component={TaggerOrgProject} />
<Route path="projects/:orgName/:projectName/space" component={TaggerSpace}/>
<Route path="projects/:orgName/:projectName/export" component={TaggerExport}/>
<Route path="projects/:orgName/:projectName/overview" component={TaggerOveriew}/>
<Route path="projects/:orgName/:projectName/visualize" component={TaggerVisualize}/>
<Route path="projects/:orgName/:projectName/contributors" component={TaggerContributors}/>
{ /* Catch all route */ }
<Route path="*" component={NotFound} status={404} />
</Route>
);
};
What I'm trying to access is ConfirmMail component and route. The ConfirmMail component:
import React from 'react';
export default function ConfirmMail() {
const styles = require('./ConfirmMail.scss');
return (
<div className="container">
<div className={styles.loading + ' text-center'}>
<span className="glyphicon glyphicon-repeat glyphicon-refresh-animate gi-3x">
CONFIRMED
</span>
</div>
</div>
);
}
Also, the client.js:
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import createStore from './redux/create';
import ApiClient from './helpers/ApiClient';
import {Provider} from 'react-redux';
import { Router, browserHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import { ReduxAsyncConnect } from 'redux-async-connect';
import useScroll from 'scroll-behavior/lib/useStandardScroll';
import {persistStore} from 'redux-persist';
import getRoutes from './routes';
import { Segment } from 'semantic-ui-react';
const client = new ApiClient();
const _browserHistory = useScroll(() => browserHistory)();
console.log('window data is', window._data);
const store = createStore(_browserHistory, client, window.__data);
const history = syncHistoryWithStore(_browserHistory, store);
class AppProvider extends React.Component {
constructor() {
super();
this.state = { rehydrated: false };
}
componentWillMount() {
persistStore(store, { blacklist: ['routing', 'dataturksReducer'] }, () => {
this.setState({ rehydrated: true });
});
}
render() {
const component = (
<Router render={(props) =>
<ReduxAsyncConnect {...props} helpers={{client}} filter={item => !item.deferred} />
} history={history}>
{getRoutes(store)}
</Router>
);
if (!this.state.rehydrated) {
return (<div><Segment basic loading/></div>);
} else if (this.state.rehydrated) {
console.log('rehydrating ', component);
return (
<Provider store={store} key="provider">
{component}
</Provider>);
}
}
}
const dest = document.getElementById('content');
ReactDOM.render(
<AppProvider />,
dest
);
// const persistor = persistStore(store, {}, () => { this.rehydrated = true; });
This is the main App.js component in this project.
So when I access localhost/confirm, I don't get a 404 not found page but I get an empty page. Earlier I've tried to console.log a few things but it didn't work either. I've been working on this my whole day and I didn't manage to make it work. Does someone know what am I doing wrong?
Did you try to add / in Route path?
<Route path="/confirm"
You need to add / before every route. That's why it is not getting the component you want. So modify your code by adding / like the following
<Route path="/confirm" component={ConfirmMail}/>
And another thing that I recommend you to do is enclose your routers inside <Switch></Sitch>. If the URL is /confirm, then all routes below it will be rendered. This is by design, allowing us to compose s into our apps in many ways, like sidebars and breadcrumbs, bootstrap tabs, etc.
Occasionally, however, we want to pick only one to render. If we’re at /confirm we don’t want to also match /:orgName If so you will end up with 404 error.
Here’s how to do it with Switch:
return (
<Switch>
<Route path="/" component={App}/>
<Route path="confirm" component={ConfirmMail}/> //THIS IS THE COMPONENT I'M TRYING TO ACCESS
{ /* Home (main) route */ }
<IndexRoute component={Home}/>
{ /* Routes requiring login */ }
<Route onEnter={requireLogin}>
<Route path="projects/create" component={TaggerCreate}/>
<Route path="projects/edit" component={TaggerEdit}/>
<Route path="projects/:orgName/create" component={TaggerCreate}/>
<Route path="projects/:orgName/import" component={TaggerImport}/>
<Route path="projects/:orgName/:projectName/edit" component={TaggerEdit}/>
<Route path="projects/:orgName/:projectName/keybind" component={TaggerKeyBind}/>
</Route>
{ /* Dataturks tool */}
<Route path="projects/login" component={TaggerLogin}/>
<Route path="projects/import" component={TaggerImport}/>
<Route path="projects/space" component={TaggerSpace}/>
<Route path="projects/stats" component={TaggerStats}/>
<Route path="projects/export" component={TaggerExport}/>
<Route path="projects" component={TaggerProjects}/>
<Route path="projects/add" component={TaggerAdd}/>
<Route path="projects/overview" component={TaggerOveriew}/>
<Route path="projects/visualize" component={TaggerVisualize}/>
<Route path="projects/errors" component={TaggerError}/>
<Route path="projects/:orgName" component={TaggerOrg} />
<Route path="projects/:orgName/:projectName" component={TaggerOrgProject} />
<Route path="projects/:orgName/:projectName/space" component={TaggerSpace}/>
<Route path="projects/:orgName/:projectName/export" component={TaggerExport}/>
<Route path="projects/:orgName/:projectName/overview" component={TaggerOveriew}/>
<Route path="projects/:orgName/:projectName/visualize" component={TaggerVisualize}/>
<Route path="projects/:orgName/:projectName/contributors" component={TaggerContributors}/>
{ /* Catch all route */ }
<Route path="*" component={NotFound} status={404} />
</Switch>
);
I can't seem to get my functional components to pass a variable like I expect. I've tried passing props, didn't work, I'm also not sure if the syntax is the same with purse functional components. Any tips?
app.js:
const [showRecommender, setRecommenderVisible] = React.useState(true);
<Switch>
<Route
path='/'
render={() => <LandingPage showRecommender={showRecommender} />}
//ALSO TRIED: render={(props) => <LandingPage {...props} showRecommender={showRecommender} />}
/>
</Switch>
LandingPage.js:
const LandingPage = ({showRecommender}) => {
console.log("showRecommender val from landingPage:", showRecommender); //getting undefined????
It works fine. Can you please match your code with the code below and let me know if your issue is solved.
App.js
import React from "react";
import { Switch, Route, BrowserRouter as Router } from "react-router-dom";
import LandingPage from "./components/LandingPage";
function App() {
const [showRecommender, setRecommenderVisible] = React.useState(true);
return (
<Router>
<Switch>
<Route
path="/"
render={() => <LandingPage showRecommender={showRecommender} />}
/>
</Switch>
</Router>
);
}
export default App;
LandingPage.js
import React from "react";
const LandingPage = ({ showRecommender }) => {
console.log("showRecommender val from landingPage:", showRecommender);
return <div>landing page</div>;
};
export default LandingPage;
Browser Console
showRecommender val from landingPage: true LandingPage.js:4
I still had my original code 'commented' out, or so I thought...it was still executing the commented out line. Once removed, it worked as expected... bonehead move, sorry all.
<Switch>
// <Route path="/" exact component={LandingPage}/>
<Route
path='/'
render={() => <LandingPage showRecommenderVal={showRecommender} />}
/>
</Switch>
Hello i try to protected route if is no auth but it is not work
Warning: You should not use Route component and Route render in the same route; Route render will be ignored
App.js
import React, { Fragment, useEffect } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import NavBar from './component/Layout/NavBar';
import Landing from './component/Layout/Landing';
import Login from '../src/component/Auth/Login';
import Register from '../src/component/Auth/Register';
import Dashboard from './component/dashboard/Dashboard';
import Alert from './component/Auth/Alert';
import PrivateRoute from './component/routing/PrivateRoute';
import './App.css';
// Redux
import { Provider } from 'react-redux';
import store from './store';
import setAuthToken from './utils/token';
import { loadUser } from './action/auth';
if (localStorage.token) {
setAuthToken(localStorage.token);
}
const App = () => {
useEffect(() => {
store.dispatch(
loadUser());
}, []);
return (
<Provider store={store}>
<Router>
<Fragment>
<NavBar />
<Route exact path="/" component={Landing}></Route>
<section className="container">
<Alert />
<Switch>
<Route exact path="/login" component={Login}></Route>
<Route exact path="/register" component={Register}></Route>
<PrivateRoute exact path="/dashboard" component={Dashboard}></PrivateRoute>
</Switch>
</section>
</Fragment>
</Router>
</Provider>
);
};
export default App;
PrivateRoute.js
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Route, Redirect } from 'react-router-dom';
const PrivateRoute = ({
componet: Component,
auth: { isAuthenticated, loading },
...rest
}) => (
<Route
{...rest}
render={props =>
!isAuthenticated && !loading ? (
<Redirect to="/login" />
) : (
<Component {...props} />
)
}
/>
);
PrivateRoute.propTypes = {
auth: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
auth: state.auth
});
export default connect(mapStateToProps)(PrivateRoute);
Warning: You should not use "Route component" and "Route render" in the same route; "Route render" will be ignored
how can I fix it ?
From route rendering method:
There are 3 ways to render something with a <Route>:
- <Route component>
- <Route render>
- <Route children>
Each is useful in different circumstances. You should use only one of these props on a given
PrivateRoute contains both component and render prop. You can only use one rendering method but not both.
<PrivateRoute exact path="/dashboard" component={Dashboard}></PrivateRoute> // here
const PrivateRoute = ({
...
}) => (
<Route
render={props => ()} // here
/>
);
FIX
: Rename component prop to comp since it's acting as an HOC:
// rename prop to `comp`
<PrivateRoute exact path="/dashboard" comp={Dashboard}></PrivateRoute>
const PrivateRoute = ({
comp: Component, // use comp prop
auth: { isAuthenticated, loading },
...rest
}) => (
<Route
{...rest}
render={props =>
!isAuthenticated && !loading ? (
<Redirect to="/login" />
) : (
<Component {...props} />
)
}
/>
);
Use <Route render={() => <YourComponent />} /> instead of <Route component={YourComponent} />.
Don't combine two of those, react does not like that.