redux is not updating states in component - reactjs

From below code ,if i remove routes variable from code1 and go with code2 code than
i did not face any problem .but if i comment code2 routes variable and work with the code1
than i am facing problem that when i click on submit button of Auth.js file or /auth route
(without or with selecting any ingredient from /burgerBuilder route.
when user click on submit button of Auth.js file .it will dispatch auth action in redux store
than that will dispatch authStart than after receiving response from firebase than we dispatch authSuccess which changes token and some other data in redux.
than this changes will rerender all component who has auth object state in their mapStateToProps.but token is not updating in mapStateToProps in Auth.js file
where am i wrong .
complete code you can check on below link
[1]: https://codesandbox.io/s/goofy-kowalevski-mos8f?fontsize=14&hidenavigation=1&theme=dark
but i am getting problem when i conditioned routes in App.js file. if i dont do that than it works fine more i have already described in App.js file with code as well.
class App extends Component {
render(){
//console.log("App.js");
//code1::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
let routes ;
routes = (
<Switch>
<Route path="/auth" component={Auth}/>
<Route path="/" exact component={BurgerBuilder} />
</Switch>);
if(this.props.token)
{
routes = (
<Switch>
<Route path="/checkout" component={Checkout} />
<Route path="/orders" component={Orders} />
<Route path="/logout" component={Logout} />
<Route path="/" exact component={BurgerBuilder} />
</Switch>);
}
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
//code2:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
routes = (
<Switch>
<Route path="/auth" component={Auth}/>
<Route path="/checkout" component={Checkout} />
<Route path="/orders" component={Orders} />
<Route path="/logout" component={Logout} />
<Route path="/" exact component={BurgerBuilder} />
</Switch>);
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
return (
<div>
<Layout>
{routes}
</Layout>
</div>
);
}
componentDidMount() {
this.props.onAuthCheck();
}
}
const mapStateToProps = (state)=>{
return {
token:state.auth.token
}
}
const mapDispatchToProps = (dispatch) => {
return{
onAuthCheck:() =>dispatch(authCheckState()) //when try to auto signin
}
}
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(App));
what i have already tried -> i have followed a question on stackoverflow that was telling that is because of unupdated react and react-dom .i am stuck in it from 12 hours .
thanks in advance.

i already mentioned that when i got the problem in question .when user was submitting the form it causes rerendering because of i received token from a server using an auth action.and i have conditioned my routes in such a way that it does not contain auth.js file (login/signup) page route. so that now it(auth.js) does not render because i omitted route of auth.js file(login/signup page).and even i have logged in and successfully received token but was still on the same url because the redirection code that i have written inside auth.js file does not execute.
some more information and refrence more clarity .-->
i known Link or NavLink component is related to Route .
but how it actually related
but actually what happening is .link component is internally an anchor tag when you click on that it changes your url .if your url changes mean it is changing your url property of match property of prop object.and in react we know if any prop changes it causes re-rendring.when it re-render the corresponding route whose path matches with the url render the component in its component props.
//////////////////////////////////////////////////////////////////////////////////////////
from react-router documentation .
Route Matchers-->
There are two route matching components: Switch and Route. When a is rendered,{*** it searches through its children elements to find one whose path matches the current URL. When it finds one, it renders that and ignores all others***}. This means that you should put s with more specific (typically longer) paths before less-specific ones.
If no matches, the renders nothing (null).
//////////////////////////////////////////////////////////////////////////////////////////

Related

React router doesn't refresh page

I have two different routes that are using the same component.
<BrowserRouter>
<Routes>
<Route path="/produktai" element={<Products />}/>
<Route path="/produktai/:productId" element={<Products />} />
</Routes>
</BrowserRouter>
I'm using Link from react to switch between pages and get id's from
const pathname = useLocation().pathname;
to perform rest api's.
For example, when i change pages using Link from /products to /products/2, url changes but the problem is that page doesn't refresh as it should. Problem solves if i'm using a tag with href as it always reloads page unlike smooth react Link functionality but i don't think that's a good solution.
Even though the route path changes you are still rendering the same Products component. If you need to run some logic when the path changes, or more likely, when the productId route param updates, then you should use an useEffect hook with the productId route param as a dependency.
Example:
const { productId } = useParams();
useEffect(() => {
if (productId) {
// Perform rest api call and response handling
}
}, [productId]);
There is a better approach for this issue. Give unique keys like below.
<Route path="/all-reports">
<ReportsPage key="1" />
</Route>
<Route path="/shared-reports">
<ReportsPage key="2" mode="shared" />
</Route>
<Route path="/owned-reports">
<ReportsPage key="3" mode="owned" />
</Route>

React Router rendering wrong component

I am using a HashRouter to render different pages. The problem I am having is that when I visit
/service/app/sort, it renders <MainPage /> when I am expecting it to render <ChildPage />.
Here's similar to what my router looks like
<HashRouter>
<Switch>
<Route path="/service/app">
<MainPage />
</Route>
<Route path="/service/app/sort">
<ChildPage />
</Route>
</Switch>
</HashRouter>
Additional information that may help:
on my <MainPage />, I have a button to redirect onClick
const history = useHistory();
const handleSortClick = () => {
console.log('click me')
let path = "/service/app/sort";
history.push(path);
};
When I click it once, I get the 'click me' console.log and the link changes to /service/app/sort, but it's still the <MainPage />. If I click it one more time, I get the warning
"Warning: Hash history cannot PUSH the same path; a new entry will not be added to the history stack"
You're probably facing this problem because the start of the URL is being interpreted as truthy by react-router-dom, and is letting you access the /service/app anyway.
For example, the /service/app route will not only detect this route, but will also detect /service/app/1 or /service/app1 just because it has /service/app in the path.
To prevent this, you need to pass the exact property to the route, so react-router will understand that you need to access exactly this route to render that component.
<Route path="/service/app" exact={true}>
<MainPage />
</Route>

React router does not render route when URL accessed directly

Consider this the main App component (imports left out for brevity):
const App = () => {
const [orderRoutes, setOrderRoutes] = useState([])
const updateOrderRoutes = (newRoute) => {
orderRoutes.push(newRoute)
setOrderRoutes(orderRoutes)
}
const renderedOrderRoutes = orderRoutes.map(route => {
return (
<Route
path={`/${route.class}/${route.order}`}
exact
key={`/${route.class}/${route.order}`}
>
<CatalogPage />
</Route>
)
})
return (
<BrowserRouter>
<Header
updateOrderRoutes={updateOrderRoutes}
/>
<Route path="/" exact component={Home} />
<Route path="/aboutus" exact component={AboutUs} />
<Route path="/faq" exact component={Faq} />
<Route path="/register" exact component={Register} />
{renderedOrderRoutes}
<Footer />
</BrowserRouter>
)
}
export default App
The challenge is that some of the routes are not known when rendering the initial App component. They will be known when an AJAX request in the <Header> component is responded to. The header will then update the new route to the orderRoutes state property, re-rendering the App component every time. The routes that are the result of the AJAX call (that is made in the <Header>) are then rendered to the <BrowserRouter> (in {renderedOrderRoutes}). In the <Header>, there is a <Link> for each route being rendered as a result of the same AJAX call, so that every menu entry (The <Link>s) will have a corresponding route.
This works fine, but when I access one of the URL's that this mechanism generates directly (e.g.: refresh the page), the <CatalogPage> component is not rendered.
So, for instance let's say that the AJAX call results in a bunch of routes and one of those is /t-shirts/tanktops. I will get a menu entry with a link to that path. When I click that menu entry the <CatalogPage> component is rendered. But when I access /t-shirts/tanktops directly, the <CatalogPage> component is not rendered.
How can I alter this code to make the URL's that are a result of the AJAX call directly accessible?
EDIT
OK, I 'solved' this (don't like it) by forcing the <App> component to re-render when one of the <Link>s was clicked by creating an unused piece of state on the App component called activeOrderRoute. I passed the setter down to the Header as a prop and connected it as a callback to the onClick handler for each Link that was created in response to the AJAX request. This essentially forces the App to re-render and render the routes, which solved my problems.
Still, that does not seem like the correct way to do it so any help would be appreciated.
React router does not directly have routing support for all URLs. It catches the default domain only the remaining routing is done on client side and requests are not served.
If your domain is www.mydomain.com, you can not access the URL www.mydomain.com/info directly in the react router.
Solutions:
You can use a hash router but that makes the URLs unfriendly for SEO
You can set up a catch-all routes and route it yourself
This link would help you with the same
https://ui.dev/react-router-cannot-get-url-refresh/
you need to modify your webpack.config.js and add the following lines.
module.exports = {
devServer: {
historyApiFallback: true,
},
...
Instead of trying to explicitly render a route for each asynchronously fetched route, leverage the power of react-router-dom and render a dynamic route path string that can handle any catalog page.
Instead of this:
const renderedOrderRoutes = orderRoutes.map(route => {
return (
<Route
path={`/${route.class}/${route.order}`}
exact
key={`/${route.class}/${route.order}`}
>
<CatalogPage />
</Route>
)
})
return (
<BrowserRouter>
<Header
updateOrderRoutes={updateOrderRoutes}
/>
<Route path="/" exact component={Home} />
<Route path="/aboutus" exact component={AboutUs} />
<Route path="/faq" exact component={Faq} />
<Route path="/register" exact component={Register} />
{renderedOrderRoutes}
<Footer />
</BrowserRouter>
)
Render a single dynamic route in your Router. Use a Switch so only a single route component is matched and rendered. Reorder the routes so the more specific paths can be matched before less specific paths. Now, when a URL has a path that is of the shape "/someClass/someOrder" it can be matched before you try matching any of the more general paths. You will see that the home path ("/") is matched last and the reordering allows us to remove the exact prop on all routes.
return (
<BrowserRouter>
<Header updateOrderRoutes={updateOrderRoutes} />
<Switch>
<Route
path="/:class/:order"
exact
component={CatalogPage}
/>
<Route path="/aboutus" component={AboutUs} />
<Route path="/faq" component={Faq} />
<Route path="/register" component={Register} />
<Route path="/" component={Home} />
</Switch>
<Footer />
</BrowserRouter>
)
You may need to adjust some logic in CatalogPage to handle possible undefined catalog data, whatever it is using from the route props/etc... to render catalog stuff.
In your Header component make the asynchronous call there to fetch the routes that can be navigated to so you can dynamically render render links to them (if that is even why you are passing the routes to Header).

React router: Redirecting with url param?

In my render function I have
<Route path="/classes/:course" render={(match) => (
<Redirect to={`/classes/${match.params.course}/home`} />
)}>
<Route path="/home" component={Home} />
</Route>
For example if the param for "course" was "BIO1001", I want to redirect the page to "/classes/BIO1001/home" when I go to the page "/classes/BIO1001/". Previously I tried simply putting a Redirect tag with "from" and "to" but ran into the problem of the url actually going to "/classes/:course/home" instead of "/classes/BIO1001/home"
Also would the nested route with path="/home" go to "/classes/BIO1001/home"? I was unsure on how I can set a route where the path starts from the previous url (in this case starting from "/classes/:course/"
The first problem is right here:
render={(match) => ( ...
The render function gets a props object which contains a match property. Instead of destructuring the match property, what you are actually doing is assigning the whole props object to a variable match. So when you go to access match.params it won't be found.
You need curly braces around match in order to destructure it.
render={({match}) => ( ...
The second problem is the nesting of the two Route components. I get a warning:
Warning: You should not use <Route render> and <Route children> in the same route; <Route render> will be ignored
So based on that warning you can see that your Redirect is being entirely ignored since it comes from render. The child Route is seen as the render function for the classes Route.
I'm assuming you have various subpages of a course? And we want to force the URL to include "/home" if none is set? (Personally I would do the opposite and redirect "/home" to the course root URL).
Previously I tried simply putting a Redirect tag with "from" and "to" but ran into the problem of the url actually going to "/classes/:course/home" instead of "/classes/BIO1001/home"
Per the docs, you can use params in your Redirect, but only if it is inside a Switch.
Here's a sample code to do that:
const CoursePage = () => {
// you can access arguments from the props or through hooks
const { course, tab } = useParams();
// not sure how you want to handle the different tabs
return <div>Viewing Course {course}</div>;
};
const App = () => (
<BrowserRouter>
<Switch>
<Route path="/classes/:course/:tab"><CoursePage/></Route>
<Redirect from="/classes/:course" to="/classes/:course/home"/>
</Switch>
</BrowserRouter>
);
export default App;
Your nested routing is true i think. But you are rendering your Home component without any dynamic props. Try it like below:
<Route path="/classes/:course" render={(match) => (
<Redirect to={`/classes/${match.params.course}/home`} />
)}>
<Route path="/home" >
<Home someProps={someValue} />
</Route>
</Route>
Note: The Redirect element can be used without a containing Route element by providing a from property. In this case, you can just use the URL parameter tokens in both from and to, and they'll be carried over for you. For example, if you're using a Switch block...
<Switch>
{/* various app routes... */}
{/* redirect action */}
<Redirect from="/classes/:course" to="/classes/:course/home" />
<Switch>

States and Router paths

I edited my questions as I realized it was not clear:
Visit https://codesandbox.io/s/dry-glitter-7lk9i?fontsize=14&hidenavigation=1&theme=dark
I was using states for the purpose of having the following structure:
Header
BODY (CONTENT)
Footer
Onclick actions or other events, I used states to hide components and show components in the body content.
I then wanted to be able to access a certain page by url ex (localhost:3000/privacy) So I'm looking to use Router to do so.
When I do a switch command, it does not hide my main component and show the switch, rather it shows both of them. How do I get the UI to react to the way I was initially coding?
You should wrap LandingPage component inside Route. Please check below for detail.
App.js
export default function App() {
return (
<Router>
<div className="App">
<Switch>
<Route exact path="/">
<Landingpage />
</Route>
<Route exact path="/businessregister">
<BusinessRegister />
</Route>
</Switch>
</div>
</Router>
);
}
Baymax has the correct answer but answering to explain a bit more.
The Switch component renders routes exclusively; it matches and returns the first matched route component. The Landingpage component iss always being rendered by the router no matter what the path is.
By moving Landingpage onto a route you can conditionally render it based upon the current path. Placing it last and not specifying a path means that if any route declared before it is matched and returned then it won't render, but if no routes match, then the Landingpage component route will match all paths and render.
function App() {
return (
<Router>
<div className="App">
<Switch>
<Route exact path="/businessregister">
<BusinessRegister />
</Route>
<Route component={Landingpage} /> // <-- render if nothing matches above
</Switch>
</div>
</Router>
);
}

Resources