I am using react-router-dom in a redux app.
This is my initial setup in index.js:
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
, document.getElementById('root'));
Then in my App.js I have:
render() {
return (
<div className="App">
<Route exact path="/" render={ () => {
return (
<div>
{
this.props.categories.map((category)=>{
console.log('category', category)
return (
<Link key={category.name} to="/category" >{category.name}</Link>
)
})
}
</div>
)
}}
/>
<Route path="/category" render={ () => {
console.log('category path this.props', this.props)
return (<p>Category is whatever</p>)
}}
/>
</div>
);
}
I would think that whenever I click any of the Links displayed the browser would automatically know how to render the new Route path /category but for some reason it does not.
What am I doing wrong?
The above post by Dane has the solution.
But in the spirit of presenting the solution with more clarity, I will copy and paste the relevant codes that made react router work well with redux and other middleware.
import { withRouter } from 'react-router-dom'
export default withRouter(connect(
mapStateToProps,
)(App))
From React Router docs,
Generally, React Router and Redux work just fine together.
Occasionally though, an app can have a component that doesn’t update
when the location changes (child routes or active nav links don’t
update). This happens if:
The component is connected to redux via
connect()(Comp).
The component is not a “route component”, meaning it
is not rendered like so: <Route component={SomeConnectedThing}/>
The
problem is that Redux implements shouldComponentUpdate and there’s no
indication that anything has changed if it isn’t receiving props from
the router. This is straightforward to fix. Find where you connect
your component and wrap it in withRouter.
So maybe it's a problem with using render props. So:
either replace render with component, or
try their solution, with withRouter ( even there you have to make them into components )
https://reacttraining.com/react-router/core/guides/redux-integration/blocked-updates
Both Link and Router is compulsory.
Not Work!
import { BrowserRouter as Link } from "react-router-dom";
Work in my case.
import { BrowserRouter as Router, Link } from "react-router-dom";
In my case, this is working properly. If you will import router and link both together.
import { BrowserRouter as Router, Link } from "react-router-dom";
Related
import { useState } from 'react';
import About from './Container/About';
import Profile from './Container/Profile';
import {BrowserRouter as Router,Route} from 'react-router-dom'
function App() {
const [state,setState] = useState('Data')
return (
<div >
<button onClick={()=>setState('About')} >About</button>
<button onClick={()=>setState('Profile')}>Profile</button>
{state}
<Router>
<Route element={<About/>} path='/about' />
</Router>
</div>
);
}
export default App;
Why is the browser router is not working as it is showing nothing in the output?
Why is the browser router is not working as it is showing nothing in the output?Why is the browser router is not working as it is showing nothing in the output?Why is the browser router is not working as it is showing nothing in the output?
You need to update the navigation path in order to make this work. Currently you are only updating your state, which is completely decoupled from React Router.
You can either add a link component or naviagate programmatically.
The following should work in your case
import { useNavigate } from "react-router-dom";
[...]
let navigate = useNavigate();
[...]
<button onClick={()=>{ setState('About'); navigate('/about'); } } >About</button>
Or if you don't need the state for anything other than the navigation, you can remove it and replace your buttons with React Router Link components.
The router component maintains it's own state and routing context. You need to either use a Link component or the navigate function to issue an imperative navigation action. Don't forget that all the Route components need to be wrapped by the Routes component so route path matching and rendering functions.
Example:
import About from './Container/About';
import Profile from './Container/Profile';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<div >
<Router>
<Link to='/'>Home</Link>
<Link to='/about'>About</Link>
<Link to='/profile>Profile</Link>
<Routes>
<Route element={<h1>Home</h1>} path='/' />
<Route element={<About />} path='/about' />
<Route element={<Profile />} path='/profile' />
</Routes>
</Router>
</div>
);
}
export default App;
If you decide to use the useNavigate hook to access the navigate function in this App component then the Router will need to be higher in the ReactTree in order for the useNavigate hook and routing components in App to be able to access the routing context.
I am trying to make a multi page app with react routing.
I am have some questions as to how I should structure the routing in the react project.
I want to load my component in my app.js file. In my Home component I would like to have the ability to press a button which will take me to the Poems component, I want the code to be clean and structured into components, therefore I dont want to do all this in the app.js file.
If someone would explain to me how to best do this I can from there be able to route around to multiple pages afterwards depending on the page you are on. I dont want to have a global menu currently (I will want that in the Poems component later though).
Here is my current App.js file & Home.jsx component code just for a more easily adjustable experience for you guys!
Currently it is not optimized to work so if anyone knows a good routing solution for my issue, please give me an example of the routing fix.
Thanks alot
/Jacob
import React from 'react'
import { Route, BrowserRouter as Router, Routes } from 'react-router-dom'
import './App.scss'
import { Home, Poems, Favourites } from './Pages'
const App = () => {
return (
<Router>
<div className="app">
<Home />
<Routes> {/* I read that the Switch was replaces with Routes */}
<Route path="/" exact component={ Home } />
<Route path="/Poems" component={ Poems } />
<Route path="/Favourites" component={ Favourites } />
</Routes>
</div>
</Router>
)
}
export default App
import React from 'react'
import { Route, BrowserRouter as Router, Routes, Link } from 'react-router-dom'
import { Poems } from './Pages'
import './Home.scss'
const Home = () => {
return (
<Router>
<div>
<h1>Petry For All</h1>
<Routes>
<Route path="/Poems" component={ Poems } />
<Link to="/Poems">Poems</Link>
</Routes>
</div>
</Router>
)
}
export default Home
You don't need to (and actually shouldn't) duplicate the <Router> component in all of the route pages. It is only the root component that is acting as a router. So you can keep the App component the same, and then replace the Home component with the following:
import React from 'react'
import { Poems } from './Pages'
import './Home.scss'
const Home = () => {
return (
<div>
<h1>Petry For All</h1>
<Link to="/Poems">Poems</Link>
</div>
)
}
export default Home
The <Link> component resolves into an anchor element which, when clicked, navigates the user to the route passed into the to property.
When I go to one functional component using react-router, it renders twice.
However, when I refresh the page of that component, it only renders once.
For the test, created empty functional component like that:
import React from 'react'
const TestFunctional: React.FC<any> = () => {
console.log('Test===>>>') // console log twice when navigate to this component
return <></>
}
export default TestFunctional
Here is Router in App.tsx
import React from 'react'
import { Route, Switch, useLocation, withRouter } from 'react-router-dom'
import TestFunctional from 'views/Test'
const AnimatedSwitch = withRouter(({ location }) => (
<Switch>
<Route exact path="/" component={StartPage} />
<Route exact path="/test" component={TestFunctional} />
</Switch>
))
const App = () => {
return (
<div className="app">
<Web3ReactManager>
<AnimatedSwitch />
</Web3ReactManager>
</div>
)
}
export default App
I did not use React.StrictMode in index.tsx.
ReactDOM.render(
<ApolloProvider client={client}>
<Provider store={store}>
<ConnectedRouter history={history}>
<Web3ReactProvider getLibrary={getLibrary}>
<Web3ProviderNetwork getLibrary={getLibrary}>
<App />
</Web3ProviderNetwork>
</Web3ReactProvider>
</ConnectedRouter>
</Provider>
</ApolloProvider>,
document.getElementById('root')
)
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers
serviceWorker.unregister()
So it is some weird.
When I refresh this page, console.log('Test===>>>') show only once.
What is a mistake and how to fix the double render problem?
Why is that a problem? You should design/write your components assuming that it could re-render at anytime. React is even working on a new rendering mode where your component might be rendered multiple times before it actually gets "rendered in DOM".
As for why it actually renders twice? Not sure, might just be a quick of ReactDOM. As a side note, the documentation for component does have this warning for Route though:
When you use component (instead of render or children, below) the
router uses React.createElement to create a new React element from the
given component. That means if you provide an inline function to the
component prop, you would create a new component every render. This
results in the existing component unmounting and the new component
mounting instead of just updating the existing component. When using
an inline function for inline rendering, use the render or the
children prop (below).
While that shouldn't apply in this case, still handy to know.
I have changed the routes in my app, and in case any users have bookmarked urls to the old routes I have added some redirects to the new routes. Most of them are working fine, however this one is not -
App.tsx
import { Router } from 'react-router-dom';
import Routes from './Routes';
import history from './history';
const App: FunctionComponent = () => (
<Router history={history}>
<Routes />
</Router>
);
export default App;
RouteSwitch.txs
import React, { FunctionComponent } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
const RouteSwitch: FunctionComponent = () => {
return (
<Switch>
<Redirect exact from="/documents" to="/documents/list" />
<Route exact path="/documents/list">
<DocumentsContainer />
</Route>
</Switch>
);
};
export default RouteSwitch;
The redirect from /documents to /documents/list works, however the DocumentsContainer does not get rendered. If I directly request /documents/list then it renders fine. It's as if <Switch> finds its first match (the Redirect) and then decides its job is done. I tried adding the push prop to the Redirect but it didn't make a difference.
My example is very similar to the one given on the React Training site - https://reacttraining.com/react-router/web/api/Redirect/from-string
Thoughts?
Problem solved - the DocumentsContainer component was actually rendering, but just not showing anything due to a quirk with how the use of the redirect was causing a loader count to be incremented by one (but not decremented) resulting in the loader count not returning to 0 to allow document data to be loaded from Redux and the content to be rendered.
This is my first crack at trying to integrate React-Router4 into a React/Redux app. I've been stuck on the first hurdle for a couple hours as I'm reading the docs and a (very good) CSS-Tricks article.
The issue is that the won't render the 'Whatever' value I input at the component prop, which should be a component.
I've actually read almost entirely thru the (excellent) docs, beginning here: https://reacttraining.com/react-router/web/guides/quick-start
And I've consulted this article: https://css-tricks.com/react-router-4/
Which also includes this Codepen (to see if I did something obvious/stupid): https://codepen.io/bradwestfall/project/editor/XWNWge?preview_height=50&open_file=src/app.js
I'm just hoping someone on SO might be able to nudge me over this hump. I was expecting to at least be able to render this very simply without any additional libraries or adjustment to my stores based on: https://reacttraining.com/react-router/web/guides/redux-integration
entry point, index.js:
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import store from './stores'
import { Provider } from 'react-redux'
import Home from './components/Home'
import TopStories from './components/TopStories'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
// app entry point
const app = (
<Provider store={store.configure(null)}>
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/topstories" component={TopStories} />
</Switch>
</Router>
</Provider>
)
// virtual DOM render
ReactDOM.render(app, document.getElementById('root'))
TopStories.js component (renders ok in the '/' path if I switch it w/ Home)
import React, { Component } from 'react'
export default (props) => {
return(
<div>Top Stories component </div>
)
}
I was attempting to test by typing the path into the browswer.... Duh. I just needed to set up a quick link component and everything worked fine.