I'm trying to use REGEXP to help render a 404 page in a react app using the path. I cannot figure it out.
This is the REGEXP I want; I want to match IF:
The entire path is !== '/' && does not contain the word 'article'.
EDIT: Including code for clarification:
<Switch location={location} key={location.pathname}>
<Route path={["/commentisfree/article/:id", "/commentisfree"]}>
<Opinion />
</Route>
<Route path={["/sport/article/:id", "/sport"]}>
<Sport />
</Route>
<Route path={["/culture/article/:id", "/culture"]}>
<Culture />
</Route>
<Route path={["/lifestyle/article/:id", "/lifestyle"]}>
<Lifestyle />
</Route>
<Route path={["/signup", "/login"]}>
<Account />
</Route>
<Route path={["search/:search", "/search"]}>
<Search />
</Route>
<Route path={/REGEXP[if path !== "/" && path does NOT include the word "article"]/} component={ErrorDefault} />
<Route path={["/article/:id", "/"]}>
<Home />
</Route>
</Switch>
At the bottom you'll see I've had to put the 404 component just above my index route because the 404 is never hit if I use a catch all route, it simply navigates to the index route but maintains the incorrect URL.
For example, entering http://localhost:3000/mistake takes me to the index route. I don't want this as I rely on the urls to render modular components and it doesn't work if the path is incorrect.
So i need to force any non declared paths to a 404 page where i can display a message and a link back to the home page.
Are you using React router?
If so, you could use a catch-all route at the end of the route list, which will render a 404 page, like here: https://reactrouter.com/web/example/no-match
Edited: added link to React router documentation
The following function uses Regular Expression
const checkRegex = (urlString) => {
return (
new RegExp("/").test(urlString) && new RegExp("article").test(urlString)
);
};
You can also use the includes function for this
const checkRegex = (urlString) => {
return (
urlString.includes('article') && urlString.includes('/')
);
};
Related
I would like to understand better how the useNavigate works as I'm not really understanding the pattern.
This is my Routes
<BrowserRouter>
<Routes>
<Route path="/" element={<Homepage />} />
</Routes>
<Routes>
<Route path="/questionaire" element={<Questionaire />} />
<Route path="questionaire/1" element={<Question1 />} />
<Route path="questionaire/2" element={<Question1 />} />
</Routes>
</BrowserRouter>
On the Questionaire page I use navigate("1") and it goes into the path "/questionaire/1" -
Nice!
Now on question1 I want to go into "/questionaire/2":
navigate("2") - leads me into /questionaire/1/2
navigate("/2") - leads me into /2
navigate("questionare/2") - leads me into /questionaire/1/questionaire/2
How do I make an increment so every question just adds ++
How do I go from questionaire/5 into questionaire/2 using navigate?
I'm using navigate in buttons, should I use LINK? with a button nested in it? Why?
EDIT: doesn't necessarily have to increment the value, but just replace the current number with the one I want - ex question/1 to question/2 or from question/5 to question/3
What you are asking about is the fundamental difference between absolute and relative routing. In react-router-dom#6 the only thing that differentiates relative links and routes from absolute links and routes is the leading "/" character.
Absolute links and routes:
Begin with a leading "/" character, i.e. "/root/segment1/segment2"
Replace the entire path
// "/root/segment1"
navigate("/root/otherPath");
// "/root/otherPage"
Relative links and routes:
Do not begin with a leading "/" character, i.e. "segment2"
Append to the current path
// "/root/segment1"
navigate("otherPath");
// "/root/segment1/otherPage"
...
// "/root/segment1"
navigate("../otherPath");
// "/root/otherPage"
I suggest the following route refactor:
All sibling routes can be wrapped and rendered by a single Routes component.
Use layout and index routes to help manage/organize nested routes.
Code
<BrowserRouter>
<Routes>
<Route path="/" element={<Homepage />} />
<Route path="/questionaire">
<Route index element={<Questionaire />} /> // "/questionaire"
<Route path="1" element={<Question1 />} /> // "/questionaire/1"
<Route path="2" element={<Question2 />} /> // "/questionaire/2"
...
<Route path="<N>" element={<QuestionN />} /> // "/questionaire/<N>"
</Route>
</Routes>
</BrowserRouter>
Use absolute paths to navigate from to the parent path or from question to question:
navigate("/questionaire"); // to parent
navigate("/questionaire/1"); // to question #
navigate("/questionaire/2");
navigate("/questionaire/N");
Use relative paths from the parent layout route on path="/questionaire":
navigate(".."); // to parent
navigate("../1"); // to question #
navigate("../2");
navigate("../N");
Notice here that we can use ".." to navigate relatively to the parent route. This is useful to navigate along sibling components.
as i know. (i am noob)
On the Questionaire page I use navigate("1") and it goes into the path "/questionaire/1" - Nice! Now on question1 I want to go into "/questionaire/2": navigate("2") - leads me into /questionaire/1/2
When you use just a number or string, useNav just adding it with / after current path. If you instead of number 2 write 'hi' it navigate you to /hi.
navigate("/2") - leads me into /2.
Its because you wrote absolute path, if before your string in useNav you will add "/", then its meaning "yourhost"+"your string".
example:
Your host is localhost:3000. If you entered '/test' in useNav it will be localhost:3000/test. Or you want add this "/test/2/3" - then it will be localhost:3000/test/2/3.
navigate("questionare/2") - leads me into /questionaire/1/questionaire/2
as i said if you have just string and before it you didnt add /, then its just added after your current path.
Answering you second question:
How do I make an increment so every question just adds ++ How do I go
from questionaire/5 into questionaire/2 using navigate?
navigate("questionare/2") - leads me into
/questionaire/1/questionaire/2
You can do this using absolute path (e.g: '/questionaire/2') or relative path (e.g: '2'), you can either do this using a Link or programmatically using a useNavigate hook.
const navigate = useNavigate()
const handleClick = () => {
navigate('2')
//or
navigate('/questionaire/2')
}
Your current code is using relative path + adding entire path, which leads to duplicated path as you mentioned.
I have a React component named Auction which I wanna render with a uniq URL everytime it's rendered,
so I can share the URL for this specific auction.
I'm using react-router-dom.
I have a function to create a random string:
const generateRandomString = () => Math.random().toString(36).slice(2)
Which I wanna use as the path in the react-router-dom syntax like so:
<Route exact path={`/${generateRandomString()}`} render={() => <Auction />}
/>
But this doesn't work. When I print window.location.href in the component it shows
http://localhost:3000/?
What am I missing?
I think you can miss slash in route path.
<Route exact path={ "/" + generateRandomString()} render={() => <Auction />} />
I'm learning React making a small single page app. Just added react-router-dom today and building it out to do routes and private routes. All is well except for one thing: When the user enters a malformed url in the browser bar, the user should be rerouted to the index (WORKS!), but the browser url bar is not updated on this redirect. Oddly enough, when I hit a private route while not authorized, the redirect DOES update the url bar. What am I missing?
router.js:
const PrivateRoute = ({auth: authenticated, component: Component, ...rest}) => (
<Route {...rest} render={(props) => (
authenticated === true
? <Component {...props} />
: <Redirect to='/login/'/>
)}/>
);
export default function Router() {
const auth = useSelector(isAuthenticated);
return (
<Switch>
<PrivateRoute auth={"auth"} path={"/dashboard/"} component={DashboardContainer}/>
<Route path={"/about/"} component={AboutContainer}/>
<Route path={"/login/"} component={LoginContainer}/>
<Route path={"/terms/"} component={TermsContainer}/>
<Route path={"/"} component={IndexContainer}/>
<Redirect push to={"/"}/>
</Switch>
);
}
I believe your issue is a result of not specifying that the paths should be exact matches, therefore any route will match with your route that is specified as:
<Route path={"/"} component={IndexContainer}/>
Try adding the exact prop to all of your routes (except for your redirect), and you should properly get redirected to the home page with the correct URL.
More details on the exact prop here: React : difference between <Route exact path="/" /> and <Route path="/" />
I am using the same component for three different routes:
<Router>
<Home path="/" />
<Home path="/home" />
</Router>
Is there anyway to combine it, to be like:
<Router>
<Home path=["/home", "/"] />
</Router>
For Reach Router: (https://reach.tech/router/example/)
With the exact sample shown, the only way I can see how to do this(on a single line) is with a wildcard.
To find a way to reproduce this without side effects, we would need to see the entire nav menu.
<Router>
<Home path="/*" />
<Chicken path="chicken">
</Router>
...
const Home = props => {
let urlPath = props["*"]
// URL: "/home"
// urlPath === "home"
// URL/: "/"
// urlPath ===""
}
You could continue with other paths below Home and the router would allow them to process.
Check out the the example using a wildcard and reach router on codesandbox, I wrote!
Note: This is a catch-all, but without parsing a parameter is the only single line solution I saw.
Some DrawBacks include Home rendering instead of '404', etc.
//This could be resolved with an if statement in your render
//It will not produce the intended URL either for /home, and I have not looked into that since it is not part of the question.. but if it matched props[*] I'm sure you could redirect or something.
You can read more about the Route Component for Reach Router.
https://reach.tech/router/api/RouteComponent
I wasn't happy with the wildcard solution from the documentation and #cullen-bond because I had to map many other paths and came up with this solution:
<Router>
{["/home", "/", "/other", "/a-lot-more"].map(page => <Home path={page} />)}
</Router>
Example: https://codesandbox.io/s/reach-router-starter-v1-forked-6f44c?file=/src/index.js
Depending on the situation you're dealing with, <Redirect /> could also make the work.
<Router>
<Redirect from="/" path="/home" noThrow />
<Home path="/home" />
</Router>
You can use a single component for mutiple paths, by using a array of routes.
code example :
import sampleComponent from './sampleComponent'; // single component for mutiple routes
<Router>
<Switch>
{["/pathname_1", "/pathname_2", "/pathname_3", "/pathname_4", "/pathname_5", "/pathname_6"].map(pathname => (<Route exact path={pathname} component={sampleComponent} />) )}
<Switch>
<Router>
I am trying to implement the following nested urls with react-router. My problem is that the Feed component sends both GET and POST requests to the wrong url when nested within the Router component, like this:
ReactDOM.render((
<Router history = { browserHistory }>
<Route component={ NavBar }>
<Route path='/' component={ Feed } url='/api/threads' pollInterval={ 2000 } />
<Route path='signup' component={ Signup } />
</Route>
</Router>
), document.getElementById('root'));
sends requests to http://localhost:3000/?_=1463499798727 which returns the content of index.html, which causes an error since the ajax request is expecting json data, not html, and is wrong anyway.
while
ReactDOM.render((
<Router history = { browserHistory }>
<Route component={ NavBar }>
<Route path='signup' component={ Signup } />
</Route>
</Router>
), document.getElementById('root'));
ReactDOM.render(<Feed url='/api/threads' pollInterval={ 2000 }/>, document.getElementById('feed'))
sends requests to the expected url http:localhost:3001/api/threads and returns data, and everything works normally.
As a side note, I have port 3000 set for the webpack-hot-load frontend and port 3001 set for the Express backend.
On the Express side, I have the following route set:
router.get('/api/threads', function (req, res, next) {
Thread.find(function (err, threads) {
if (err) { return next(err); }
res.json(threads)
})
})
Visiting localhost:3001/api/threads returns the expected data.
localhost:3001 returns Cannot GET '/' which is expected.
First, if a URL is intended to be used as an API endpoint and not directly in the browser then it probably does not belong in your react-router at all. Only put paths in the router that you expect to render a view in the browser. So if you want localhost:3001/api/threads to return JSON via an API call, take it out of your router.
Also, you use should organize your routes using IndexRoute. Try this:
<Router history={browserHistory}>
<Route path="/" component={CoreLayout}>
<IndexRoute component={Feed} />
<Route path="signup" component={Signup} />
<Route path="*" component={NotFoundView} />
</Route>
</Router>
Where CoreLayout simple renders it's children. I'm not sure exactly what you are trying to display for the root URL (localhost:3001) but you would use a component like above.
To use your API endpoint you can just call it in the component directly via it's full path (localhost:3001/api/threads).