首页 文章

检测查询参数react-router-dom v4.x中的更改并重新呈现组件

提问于
浏览
8

一旦我进行查询参数更改,我不确定为什么它显示默认路由 . 这种问题有更好的方法吗?也许我不应该使用查询参数?开放接受教育!

版本“反应”:“^ 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

实际行为为空,页面上没有任何呈现

// 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'))

2 回答

  • 3

    从v4开始,React路由器不再为其位置对象提供查询参数 . 原因是

    有许多流行的包以略微不同的方式查询字符串 parsing/stringifying ,并且这些差异中的每一个可能是某些用户的 "correct" 方式和其他用户的 "incorrect" 方式 . 如果 React Router 选择了 "right" ,它只适合某些人 . 然后,它需要为其他用户添加一种替代其首选查询解析包的方法 . React Router没有内部使用搜索字符串来要求它解析键值对,因此不需要选择其中哪一个应该是"right" .

    包含它之后,只需解析期望查询对象的视图组件中的 location.search 就更有意义了 .

    你可以通过覆盖来自react-router之类的withRouter来实现这一点

    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)
    

    无论你需要什么查询字符串,你都可以简单地使用它

    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);
    
  • 1
    // A lose explanation. URL = localhost:3000/myRoute/2
    
    <Router history={history}>
      <Route path="/myRoute/:id" component={App} />
    </Router>
    
    class App extends Component {
      render() {
        const { id } = this.props.match.params
        
        return (
          <div>
            {id === 2 ? <div>id is 2</div> : <div>id not 2</div>}
          </div>
        )
      }
    }
    

相关问题