Reputation: 151
My main intention is to rewrite the Switch component, and then realize the caching of the component through the display, instead of destroying it every time.
// App
const App = () => {
return (
<MySwitch>
<Route path="path1" component={<Component1>}>
<Route path="path2" component={<Component2>}>
</MySwitch>
)
}
// MySwitch
const cacheRouteMap = {}
const MySwitch = props => {
return (
<Route
path="*"
render={
context => {
const location = props.location || context.location
let element
let match
let currentMatchPath
React.Children.forEach(props.children, child => {
// eslint-disable-next-line no-eq-null
if (match == null && React.isValidElement(child)) {
element = child
const path = child.props.path || child.props.from
currentMatchPath = path
match = path ? matchPath(location.pathname, {...child.props, path}) : context.match
}
})
if (!cacheRouteMap[currentMatchPath]) {
cacheRouteMap[currentMatchPath] = React.cloneElement(element, {
location,
computedMatch: match,
})
}
return Object.values(cacheRouteMap).map(d => {
const {path} = d.props
return <div style={{display: path === currentMatchPath ? 'block' : 'none'}}>{d}</div>
})
}
}
/>
)
}
The above code can run, but id the upper layer is re-render, the Route components render method inside MySwitch will remount.
Below is my test the render method re-mount every time.
react-router: 5.2.0; react-router-dom: 5.2.0;
code:
import React, {useState, useEffect} from 'react'
import {HashRouter as Router, Route, Switch, Redirect} from 'react-router-dom'
const Demo = () => {
useEffect(() => {
console.log('Demo did mount........')
}, [])
return 1111
}
const App = () => {
const [visible, setVisible] = useState(false)
return (
<div>
<div onClick={() => setVisible(!visible)}>button</div>
<div style={{display: visible ? 'block' : 'none'}}>xxxxx</div>
<Router>
<Switch>
<Route path="/" render={() => <Demo />} />
<Redirect to="/" />
</Switch>
</Router>
</div>
)
}
when App rerender, the Demo is re mount not rerender. What should I do the Demo rerender with render function? thanks!😋
Upvotes: 0
Views: 627
Reputation: 6395
Have you tried using this
<Route exact path="/"><Demo /></Route>
When you are using render={() => <Demo />}
, you are basically using an anonymous
function which is creating a new instance
of the Demo
component.
With this approach you can pass your own custom param, as well as use the hooks like useLocation
given by react-router
.
Sample usage
<Route exact path="/">
<App someProp={1} />
</Route>
function App(props) {
let location = useLocation();
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<h2>Value of someProp is {props.someProp} </h2>
<h2>Pathname is {location.pathname}</h2>
</div>
);
}
Check this Code Sandbox for a working sample.
Upvotes: 1
Reputation: 400
You just need to mount the <Demo />
directly.
<Route path="/" exact>
<Demo />
</Route>
Upvotes: 0