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.
Related
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('/')
);
};
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>
In the react router docs here it says:
Consider this code:
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
If the URL is /about, then <About>, <User>, and <NoMatch> will all render because they all match the path.
How do they all match the path /about? I can't see why this would be true, unless a user had the username about. What am I missing?
The Line
<Route path="/:user" component={User}/>
means that everything after / will be passed into this.props.params.user variable of component and User component would be rendered.
The matching rule only cares if the path given matches your path= pattern, it doesn't care if the resource actually exists. If I get path starting with / the and there is a text following the variable, the text will be parsed as Route Parameter user and User component will be rendered and that's it. So yes, this.props.params.user will have value of "about" in this case, but how you handle the variable and what would you display in case user such name is not found is entirely up to you.
I think they are just trying to say that in case that you have more patterns that would normally get matched all at once, you should use <Switch> component so only the first match would actually render.
So e.g. when used <Switch>:
A) and the path is /about, rule
<Route path="/about" component={About}/>
would get matched and About component would get rendered and no more evaluation are done.
B) if the path is /something, rule
<Route path="/about" component={About}/>
won't get matched, but rule:
<Route path="/:user" component={User}/>
would get matched, and User component would be rendered with something as this.props.params.user param and no more evaluation are done.
C) If the path is / the rules
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
won't get matched but
<Route component={NoMatch}/>
will and NoMatch component would get rendered.
On contrary when not using <Switch>, if your path is /about:
<Route path="/about" component={About}/>
Would get matched, because this rule matches all routes which paths are equal to /about.
<Route path="/:user" component={User}/>
Would also get matched because this rule matches all routes which start with / and there is a text following.
<Route component={NoMatch}/>
Would too get matched because this rule doesn't care about path at all, it gets always matched.
As they're not contained within a <switch>...</switch> element, they're all evaluated, and evaluated independently.
The router has no knowledge of the users in the system - it's only looking for a string match within the path.
Something like:
if (path === '/about') { return 'About' }
if (typeof path === 'String') { return 'User' }
if (true) { return 'noMatch' }
I am creating one app using reactJS. I am defining routing by react-router.
sample code is below:
<Router history={browserHistory()}>
<Route path="/" component={App}>
<Route path="taco/:name" component={Taco} />
</Route>
</Router>
but I want to use something like this:
<Route path="taco?yourchoice/:name" component={Taco} />
but I am not able to do that.
Any help would be appreciated.
Thanks
path="taco?yourchoice/:name is not a valid path. Because you include the forward slash between yourchoice and :name, I am not positive if you are trying to place a path segment after the query or capture the yourchoice query parameter value.
In the case of the former, you cannot place a path segment after the search segment of a URL and you will need to reorder the path. For the latter, React Router does not take into account the search string when it is matching the current location to route paths. However, the location will be parsed and the query parameters will be available on the location object (which is injected as a prop into the <Route>'s component.
So, given the route:
<Route path="taco" component={Taco} />
When the user navigates to the URL:
example.com/taco?yourchoice=fish
The Taco component will be rendered and one of its props will be location.
class Taco extends React.Component {
render() {
const { query } = this.props.location
return <div>A {query.yourchoice} taco</div>
}
}
Is it possible to do this with react router?
<Route path="/:reset_password" component={ResetPassword} />
<Route path="/:create_password" component={CreatePassword}/>
I want use different param with different component. I test above code and it doesn't work. the code above work if I change to this:
<Route path="/something1/:reset_password" component={ResetPassword} />
<Route path="/something2/:create_password" component={CreatePassword}/>
thanks for the help
As #chris said, remove the colons and/or assign dedicated routes. React Router can't differentiate between the two routes you've supplied, as they're technically identical (root path + a dynamic parameter.)