检测查询参数react-router-dom v4.x中的更改并重新呈现组件 [英] Detect change in query param react-router-dom v4.x and re-render component
问题描述
我不确定为什么在我进行查询参数更改后它会显示默认路由。这种问题有更好的方法吗?也许我不应该使用查询参数?开放接受教育!
版本
反应:^ 16.2.0,
react-dom:^ 16.2。 0,
react-router:^ 4.2.0,
react-router-dom:^ 4.2.2,
测试用例
https://codepen.io/adamchenwei/pen/YeJBxY?editors=0011
重现
的步骤点击首页 - >步骤1
预期行为
转到步骤1以及步骤2呈现正确的dom
实际行为
空,页面上没有任何呈现
//对于此演示,我们使用UMD构建的反应 - router-dom
const {
BrowserRouter,
Switch,
Route,
Link
} = ReactRouterDOM
const {
组件,
} =反应;
const Router = BrowserRouter;
const Step1View =()=> (
< div>
< h1>步骤1< / h1>
< / div>
)
const Step2View =() => (
< div>
< h1>步骤2< / h1>
< / div>
)
class Home extends Component {
构造函数(道具){
super(道具);
console.log(' - !!!')
this.state = {
step:1,
}
this.next = this.next.bind (这个);
}
next(stepNumber = 1){
this.props.history.push({
pathname:`/ adamchenwei / pen / YeJBxY?editors = 0011 /?step = $ {stepNumber}`,
});
const query = this.props.history.location.pathname;
console.log('--- aaaaa');
console.log(查询);
if(query ==='/ adamchenwei / pen / YeJBxY?editors = 0011 /?step = 1'){
this.setState({
step:1,
})
} else if(query ==='/ adamchenwei / pen / YeJBxY?editors = 0011 /?step = 2'){
this.setState({
step:2,
})
}
}
render(){
console.log('render !!!');
console.log(this);
const {
step
} = this.state;
console.log('--- step');
console.log(步骤);
返回(
< div>
< h1>欢迎使用龙卷风网站!< / h1>
< button onClick = {()=>这个。 next(1)}>第1步< / button>
< button onClick = {()=> this.next(2)}>第2步< / button>
{
step === 1?< h1>这里的第1步< / h1>:null
}
{
step === 2?< h1>这里的第2步< / h1>:null
}
< / div>
);
}
}
//主要组件呈现三个中的一个提供
//路由(假设一个匹配)。 / roster
//和/ schedule路由都将匹配任何使用/ roster或/ schedule启动
//的路径名。当路径名正好是字符串/时,/ route只匹配
//
const Main =()=> (
< main>
< Route exact path ='/'component = {Home} />
< / main>
)
// Header创建的链接可用于在路由之间导航
//。
const Header =()=> (
< header>
< nav>
< ul>
< li>< Link to ='/'> Home< / Link>< / li>
< li>< Link to ='/ roster'> Roster< / Link>< / li>
< li>< Link to ='/ schedule'> ; Schedule< / Link>< / li>
< / ul>
< / nav>
< / header>
)
const App =()=> (
< div>
< Header />
< Main />
< / div>
)
//这个演示使用HashRouter而不是BrowserRouter
//因为没有匹配URL的服务器
ReactDOM.render((
< Router>
< App / >
< / Router>
),document.getElementById('root'))
从v4开始,React路由器不再在其位置对象中为您提供查询参数。原因是
有许多流行的包可以查询字符串解析/字符串化
略有不同,每个对于某些用户,这些差异可能是正确
方式,对于其他用户,这些差异可能是不正确
。如果 React Router
选择了right
,那么它只适合某些人。然后,它需要为其他用户添加一种替代其首选查询解析包的方法。 React Router没有内部使用搜索字符串来要求它解析键值对,所以它不需要选择其中哪一个应该是正确的。
包含它之后,只需在视图组件中解析期望查询对象的 location.search
就更有意义了。 p>
您可以通过覆盖来自react-router的withRouter来实现这一点,例如
customWithRouter.js
从'recompose'导入{compose,withPropsOnChange};来自'react-router'的
import {withRouter};
从'query-string'导入queryString;
const propsWithQuery = withPropsOnChange(
['location','match'],
({location,match})=> {
return {
位置:{
...位置,
查询:queryString.parse(location.search)
},
匹配
};
}
);
导出默认撰写(withRouter,propsWithQuery)
以及需要查询的地方字符串,您只需使用它就像
从'path / to / customWithRouter.js'导入withRouter;
class Home extends Component {
constructor(props){
super(props);
console.log(' - !!!')
this.state = {
step:1,
}
this.next = this.next.bind (这个);
}
next(stepNumber = 1){
this.props.history.push({
pathname:`/ adamchenwei / pen / YeJBxY?editors = 0011& ; step = $ {stepNumber}`,
});
}
componentDidUpdate(prevProps){//使用componentDidUpdate,因为componentWillReceiveProps将从v16.3.0重命名为UNSAFE_componentWillReceiveProps,后来被删除
const {query:{step}} = this.props.history 。地点;
if(!_。isEqual(this.props.history.location.query,prevProps.history.location.query)){
this.setState({
step
} )
}
}
render(){
console.log('render !!!');
console.log(this);
const {
step
} = this.state;
console.log('--- step');
console.log(步骤);
返回(
< div>
< h1>欢迎使用龙卷风网站!< / h1>
< button onClick = {()=>这个。 next(1)}>第1步< / button>
< button onClick = {()=> this.next(2)}>第2步< / button>
{
step === 1?< h1>这里的第1步< / h1>:null
}
{
step === 2?< h1>这里的第2步< / h1>:null
}
< / div>
);
}
}
const HomeWithQuery = withRouter(Home);
I am not really sure why its showing the default route once I did a query param change. Is there a better approach for this kind of issue? maybe I shouldn't be using query param? Open to get educated!
Version "react": "^16.2.0", "react-dom": "^16.2.0", "react-router": "^4.2.0", "react-router-dom": "^4.2.2",
Test Case https://codepen.io/adamchenwei/pen/YeJBxY?editors=0011
Steps to reproduce Click on Home -> Step 1
Expected Behavior Go to Step 1 as well as Step 2 render correct dom
Actual Behavior Empty, nothing renders on the page
// For this demo, we are using the UMD build of react-router-dom
const {
BrowserRouter,
Switch,
Route,
Link
} = ReactRouterDOM
const {
Component,
} = React;
const Router = BrowserRouter;
const Step1View = () => (
<div>
<h1> Step 1</h1>
</div>
)
const Step2View = () => (
<div>
<h1> Step 2</h1>
</div>
)
class Home extends Component {
constructor(props) {
super(props);
console.log('-!!!')
this.state = {
step: 1,
}
this.next = this.next.bind(this);
}
next(stepNumber=1) {
this.props.history.push({
pathname: `/adamchenwei/pen/YeJBxY?editors=0011/?step=${stepNumber}`,
});
const query = this.props.history.location.pathname;
console.log('---aaaaa');
console.log(query);
if (query === '/adamchenwei/pen/YeJBxY?editors=0011/?step=1') {
this.setState({
step: 1,
})
} else if (query === '/adamchenwei/pen/YeJBxY?editors=0011/?step=2') {
this.setState({
step: 2,
})
}
}
render() {
console.log('render!!!');
console.log(this);
const {
step
} = this.state;
console.log('---step');
console.log(step);
return(
<div>
<h1>Welcome to the Tornadoes Website!</h1>
<button onClick={()=> this.next(1)} > Step 1</button>
<button onClick={()=> this.next(2)} > Step 2</button>
{
step === 1 ? <h1>Step 1 here</h1> : null
}
{
step === 2 ? <h1>Step 2 here</h1> : null
}
</div>
);
}
}
// The Main component renders one of the three provided
// Routes (provided that one matches). Both the /roster
// and /schedule routes will match any pathname that starts
// with /roster or /schedule. The / route will only match
// when the pathname is exactly the string "/"
const Main = () => (
<main>
<Route exact path='/' component={Home}/>
</main>
)
// The Header creates links that can be used to navigate
// between routes.
const Header = () => (
<header>
<nav>
<ul>
<li><Link to='/'>Home</Link></li>
<li><Link to='/roster'>Roster</Link></li>
<li><Link to='/schedule'>Schedule</Link></li>
</ul>
</nav>
</header>
)
const App = () => (
<div>
<Header />
<Main />
</div>
)
// This demo uses a HashRouter instead of BrowserRouter
// because there is no server to match URLs
ReactDOM.render((
<Router>
<App />
</Router>
), document.getElementById('root'))
React router from v4 onwards no longer gives you the query params in its location object. The reason being
There are a number of popular packages that do query string parsing/stringifying
slightly differently, and each of these differences might be the "correct"
way for some users and "incorrect"
for others. If React Router
picked the "right"
one, it would only be right for some people. Then, it would need to add a way for other users to substitute in their preferred query parsing package. There is no internal use of the search string by React Router that requires it to parse the key-value pairs, so it doesn't have a need to pick which one of these should be "right".
Having included that, It would just make more sense to just parse location.search
in your view components that are expecting a query object.
You can do this generically by overriding the withRouter from react-router like
customWithRouter.js
import { compose, withPropsOnChange } from 'recompose';
import { withRouter } from 'react-router';
import queryString from 'query-string';
const propsWithQuery = withPropsOnChange(
['location', 'match'],
({ location, match }) => {
return {
location: {
...location,
query: queryString.parse(location.search)
},
match
};
}
);
export default compose(withRouter, propsWithQuery)
and wherever you need query string, you could simply use it like
import withRouter from 'path/to/customWithRouter.js';
class Home extends Component {
constructor(props) {
super(props);
console.log('-!!!')
this.state = {
step: 1,
}
this.next = this.next.bind(this);
}
next(stepNumber=1) {
this.props.history.push({
pathname: `/adamchenwei/pen/YeJBxY?editors=0011&step=${stepNumber}`,
});
}
componentDidUpdate(prevProps) { // using componentDidUpdate because componentWillReceiveProps will be renamed to UNSAFE_componentWillReceiveProps from v16.3.0 and later removed
const {query: { step } } = this.props.history.location;
if(!_.isEqual(this.props.history.location.query, prevProps.history.location.query)) {
this.setState({
step
})
}
}
render() {
console.log('render!!!');
console.log(this);
const {
step
} = this.state;
console.log('---step');
console.log(step);
return(
<div>
<h1>Welcome to the Tornadoes Website!</h1>
<button onClick={()=> this.next(1)} > Step 1</button>
<button onClick={()=> this.next(2)} > Step 2</button>
{
step === 1 ? <h1>Step 1 here</h1> : null
}
{
step === 2 ? <h1>Step 2 here</h1> : null
}
</div>
);
}
}
const HomeWithQuery = withRouter(Home);
这篇关于检测查询参数react-router-dom v4.x中的更改并重新呈现组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!