React Router v6 and ownParams doesnt work like v5 - node.js

Hello in react router dom v5 i can get params inside redux. Sample code is below:
1- passing parameter
<Route path="/saveproduct/:productId" component={AddOrUpdateProduct} />
2- get params inside redux. I can get the productId inside ownProps
function mapStateToProps(state, ownProps) {...
But when i call route in v6 i cant get the productId inside ownProps

First, in react-router-dom v6 you should pass component to Route like an element. See docs.
<Route path="/saveproduct/:productId" element={ <AddOrUpdateProduct /> } />
Second,
react-router-dom v6 Route components rendered via the element prop don't receive route props
See question. Redux is not needed here. Just use params react hook
const { productId } = useParams();

Im new at react and it take my one day. But finally i found the solution. I am not sure this is the best practice but it make sense for me now. Check link for solution.
https://youtu.be/qdCHEUaFhBk
Also thanks #kupp

Related

Difference between MemoryRouter and Router concerning testing with react-testing-library

I work on a small App to get familiar with testing and such in React, using jest and React-Testing-Library.
In my <App /> Component, I have a Routes with two Route. One of those looks like this:
<Route path='/' element={<RequireAuth><Dashboard /></RequireAuth>} />
If the user is not logged in, <RequireAuth /> redirects the user to a Login /> Component via <Navigate to="/login" />.
This is just for context. All of this works. But for quite some time, I couldnt make the test pass to check that the Navigation happens. I figured, that my problem was the Route method I used in React-Testing-Librariesrender() method. The test passes if I use <MemoryRouter /> but doesnt if I wrap <App /> in <Router location={history.location} navigator={history} />..
In the following stackblitz, I have implemented both versions. The one that s not working, is currently commented out. Could someone tell me, why it only works with MemoryRouter? You find the test in src/routing.test.tsx. You can run the tests with npm run test.
https://stackblitz.com/edit/github-nfj4lw?file=src/routes.test.tsx
The Router is a low level function that is not environment specific. As the docs state, you probably never want to render your components with it.
Replacing it with higher level environment aware functions like BrowserRouter or (MemoryRouter) makes your test pass:
// routes.test.tsx
import { BrowserRouter } from 'react-router-dom';
it('Testing if Route Login gets rendered by default', () => {
render(
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
);
expect(
screen.getByText('Welcome to nutri. Please Login.')
).toBeInTheDocument();
});
If you want something more, you can add further assertions by querying the location/history stack.
Note: using MemoryRouter in tests is preferred to BrowserRouter since it allows you to keep your routing history independent of any external source. React-router uses it in many of its tests.

How does serving different pages in React works?

Let's say I have a react projects, and an Express server for serving my project, as follows(After building the project):
]
This way, only the index.html is served, isn't it? If the user routes to a different page, how is that page sent to him?
Routing in javascript is managed by using HTML5 push state. So every time you click a link and go to another route, the browser history and push state is being used. That's the basis for routing in almost of all the single page applications.
Until and unless you refresh the page, your request doesn't go to the server. Hence, index.html is served only once and after that the router (here the react-router) takes over and manages the routing in url using the history API of the browser.
Hope this helps !
That is done using react-router which manages the routing using the browser's History API.
This style of a website is called a single page application as opposed to a multi page application where the server sends different pages depending on the url you route to.
you can use react-router-dom like this
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/someurl" component={ComponentForSomeUrl}
</Switch>
and render it with BrowserRouter
but you can use something like history.push, in my opinion react-router-dom is really simple and better than react-router
you don't need to send html file to specific route, in case of react express is used for building API (in most cases)
In you React folder you want to do npm install --save react-router-dom.
So inside the React Router family of libraries, there is a couple of different dependencies you can possibly install.
Ensure you never install React Router by itself.
The react-router library as it is published on npm is the core library of everything inside the React Router general project.
So react-router has some core navigational logic inside of it. It decides how to work with React, how to change content out depending on different rules and some other low-level logic.
To gain some actual implementation as it works specifically in the browser, install react-router-dom.
So anytime you want to use React Router on a project to handle navigation, always install react-router-dom, not react-router.
There are other similarly named projects that you might think you need as well, react-router-native for use inside of React Native projects.
In web applications we make use of react-router-dom, we are not making native mobile apps.
React-router-native is for native mobile applications only.
For the browser you always want react-router-dom as opposed to react-router-native
So perhaps in your App.js component you want to set something up that looks like this:
import React from "react";
import { BrowserRouter, Route } from “react-router-dom”;
const App = () => {
return <div>App</div>;
};
export default App;
I also recommend if you are new to React Router to get familiar with it by setting up something temporary like so:
import React from "react";
import { BrowserRouter, Route } from “react-router-dom”;
const PageOne = () => {
return <div>PageOne</div>;
};
const PageTwo = () => {
return <div>PageTwo<button>Click Me</button></div>;
};
const App = () => {
return (
<div>
<BrowserRouter>
<div>
<Route path=“/” exact component={PageOne} />
<Route path=“/pagetwo” component={PageTwo} />
</div>
</BrowserRouter>
</div>
);
};
Visit your localhost:3000 and then your localhost:3000/pagetwo, check out how all that is working.
When we visit a page called localhost:3000 and we type that address into the url it loads up the application.
React Router itself does not care about that entire url, instead React Router only cares about all the characters that are listed after the domain name or port definition.
Localhost:3000 is interpreted as being localhost:3000/
If I go to localhost:3000/ it still loads up my application.
Now I have other examples here if I go to localhost:3000/pageone, React Router only cares about everything after the port and domain
Same thing if I went to airbnb.com/listings/spain react router would only consider /listings/spain when deciding what content to render to the screen.
Notice in the example above I created an instance of BrowserRouter, well BrowserRouter creates an object of its own known as the history object.
This history object is going to look at the URL inside the address bar and extract just that portion of the URL that react router cares about.
The history object is then going to communicate that path over to BrowserRouter who communicates that path to both Route components and those Route components decide whether to show themselves or hide themselves depending on the path that the user is visiting and the path property that it was passed when it was created.

How to pass params from Route (react-router-dom) to render function

Is possible to do something like this:
<Route exact path="/activate/:token" render={this.activateAccount} />
then in same component
activateAccount(token) {
console.log(token);
return null;
}
How to pass token?
Is my logic correct? Learning MERN a bit, what I find confusing right now is how to move between backend and frontend, for example here when I generate activate account URL I have something like
http://localhost:5006/api/activate/8d7f5b25befb70045b5cb36893fa0f7688b85504
Now my NodeJS/Express is running on 5006 port and my ReactJS is on 3006, not sure what is logic here, I can finish everything on my NodeJS side in this case but not sure how to redirect later on to /login/ on frontend.
Thanks!
The parameter of activateAccount won't be token:
<Route exact path="/activate/:token" render={this.activateAccount} />
As the reference states, Route render function receives route props:
All three render methods will be passed the same three route props
match
location
history
Otherwise it wouldn't be impossible to make use of them in route component.
It is:
activateAccount(props) {
console.log(props.match.token);
return null;
}

Handle Post request to React JS app

I have written a whole application in ReactJS Client Side. I am able to accept /API on my react app URL using <BrowserRouter>
I am looking for a way to make a post request to my React App. Eg. When a user makes a post request to http://myreactapp.com , it should recognize the Post request and get the Post Body received from this call and I want to assign it one of the state before the React App loads.
I tried searching many things on BrowserRouter but I am not able to find 1.
Can someone help me direct towards the way to implement handling POST with body params.
I am open to only suggestions too and and not the whole code since I am kind of stuck thinking what to do next.
render((
<BrowserRouter>
<div>
<Route exact path="/"
render={() => (<App />)} />
<Route path="/find/:find"
render={(props) => (<App {...props} />)} />
</div>
</BrowserRouter>
), document.getElementById('root')
);
I tried with BorwserRouter but it seems it only accepts Get parameters and not Post body.
I have also heard of using NodeJS or express as the backend but can someone help me with modifying my current React code to convert to Express only for Post request and remaining everything remains same,
TIA!

Multiple entry-points in webpack with react-router

I am facing tremendous issues trying to implement multiple entry points along with react router. The aim is to achieve using webpack to do something that is suggested by https://github.com/petehunt/webpack-howto.
So far I have currently set it up like this:
webpack.config.js
entry: {
entry1: __dirname + './entry1.jsx',
entry2: __dirname + './entry2.jsx'
}
routes.jsx
export default (
<Route path='/' name='app' handler={App}>
<DefaultRoute handler={entry1} />
<Route name='entry2' handler={entry2}/>
</Route>
);
Whenever this code is run to instantiate a instance of Router on the client
Router.run(routes, Router.HistoryLocation, (Handler, state) => {
React.render(<Handler />, document.getElementById('app'));
});
Node.js will try to run this code on the server which obviously fails as DOM is not available there. It will produce an error.
Is there any proper way to implement multiple-entry points with react-router?
I have done something similiar to this in a sandbox webpack-react-boilerplate repository I've been playing around with using react-router.
I believe the answer you may be looking for lies here where you need to use React.renderToString and/or React.renderToStaticMarkup in your server entry file as you rightly suggest, there is obviously no DOM on the server. You can see how the client entry point here differs to the server one.

Resources