This is a list of support questions that frequently show up in GitHub issues. This list is intended to minimize the frequency of this happening. The issues section is intended for bug reports, not developer support. Support questions should be asked at StackOverflow or in the Reactiflux chat.
If there is a support question that you frequently see being asked, please open a PR to add it to this list.
- Why aren't my components updating when the location changes?
- Why doesn't my application render after refreshing?
- Why doesn't my application work when loading nested routes?
- How do I access the
history
object outside of components? - How do I pass props to the component rendered by a
<Route>
?
React Router relies on updates propagating from your router component to every child component. If you (or a component you use) implements shouldComponentUpdate
or is a React.PureComponent
, you may run into issues where your components do not update when the location changes. For a detailed review of the problem, please see the blocked updates guide.
If your application is hosted on a static file server, you need to use a <HashRouter>
instead of a <BrowserRouter>
.
import { HashRouter } from "react-router-dom";
ReactDOM.render(
<HashRouter>
<App />
</HashRouter>,
holder
);
When you load the root page of a website hosted on a static file server (e.g., http://www.example.com
), a <BrowserHistory>
might appear to work. However, this is only because when the browser makes the request for the root page, the server responds with the root index.html
file.
If you load the application through the root page, in-app navigation will work because requests are not actually made to the server. This means that if you load http://www.example.com
and click a link to http://www.example.com/other-page/
, your application will match and render the /other-page/
route.
However, you will end up with a blank screen if you were to refresh a non-root page (or just attempt to navigate directly to it). Opening up your browser's developer tools, you will see an error message in the console informing you that the page could not be loaded. This is because static file servers rely on the requested file actually existing.
# a request for http://www.example.com/other-page/ expects this to exist
.
|-- index.html
+-- other-page
+-- index.html
This is not an issue when your server can respond to dynamic requests. In that situation, you can instruct the server to catch all requests and serve up the same index.html
file.
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "index.html"));
});
When you use a static server, your application should have just one index.html
file.
.
|-- index.html # this is the only html file
+-- static
|-- js
| +-- bundle.js
+-- css
+-- index.css
Then, you can use a hash history (created by a <HashRouter>
) to encode the location in the URL's hash
fragment. The pathname of the real url will always point to the same file on the server (e.g., both http://www.example.com/#/
and http://www.example.com/#/other-page
will load the root index.html
file). This results in URLs that are not as pretty as the ones created when you use a <BrowserRouter>
, but it is a necessary limitation of working with a static file server.
If the src
of the <script>
tag that is used to load your application has a relative path, you will run into issues when loading your application from nested locations (e.g., /parent
works, but /parent/child
does not). All that you have to do to fix this is to ensure that the src
path is absolute.
<!-- good -->
<script src='/static/js/bundle.js'></script>
<!-- bad -->
<script src='static/js/bundle.js'></script>
<script src='./static/js/bundle.js'></script>
When you use the <BrowserRouter>
, <HashRouter>
, <MemoryRouter>
, and <NativeRouter>
, a history
object will be created for you. This is convenient, and the history
object is readily accessible from within your React components, but it can be a pain to use it outside of them. If you need to access a history
object outside of your components, you will need to create your own history
object (in its own module) and import it throughout your project.
If you do this, make sure that you use the generic <Router>
component and not one of the specialty routers.
// history.js
import { createBrowserHistory } from "history";
export default createBrowserHistory();
// index.js
import { Router } from "react-router-dom";
import history from "./history";
ReactDOM.render(
<Router history={history}>
<App />
</Router>,
document.getElementById("root")
);
// nav.js
import history from "./history";
export default function nav(loc) {
history.push(loc);
}
You can see a demonstration of how this works in this CodeSandbox demo.
If you need to pass props to the component rendered by a <Route>
, you should use the <Route>
's render
prop. The render
prop can take an inline function as its value, which means that you can pass variables from the local scope to the component that the <Route>
renders.
Note: The render
function receives a props
argument, which you should pass on to the element that your render
function returned. If you do not do this, the component that you are rendering will not have acccess to the router variables (match
, location
, and history
).
const App = () => {
const color = "red";
return (
<Route
path="/somewhere"
render={props => <MyComponent {...props} color={color} />}
/>
);
};