React Router V4 not updating content on optional parameter change

时间:2017-07-12 08:00:28

标签: reactjs react-router

I am new to React and I am working on the search functionality of a site. I am using a create-react-app base.

Here is the routing:

<BrowserRouter>
    <App>
        <Switch>
            <Route path='/' exact component={Home} />
            <Route path='/blah' component={Blah} />
            <Route path='/boop' component={Boop} />
            <Route path="/search/:searchTerm?" component={Search} />
            <Route path="*" component={NotFound} />
        </Switch>
    </App>
</BrowserRouter>

Note the search one has an optional parameter. I am picking up this parameter fine in Search.js

import React, { Component } from 'react';
import { Link } from 'react-router-dom';

import SearchResults from './SearchResults';

export default class Search extends Component {

    constructor(props) {
        super(props);
        this.state = {
            searchTerm: this.props.match.params.searchTerm
        }
    }

    render() {
        return (
            <div className="Search">
                SEARCH: {this.state.searchTerm}
                <SearchResults searchTerm={this.state.searchTerm} />
            </div>
        );
    }
}

Over in the actual form that triggers the search, this snippet handles the click:

handleClick(event) {        
    this.props.history.push('/search/'+this.state.value);
}

This works and displays results for paths like /search/test and /search/woo. The only problem is when I go directly from one search to another.

/search/test -> /search/woo updates the path in the address bar, but does not render the content of the woo page with the new search results.

Going to another path between makes it work. So /search/test -> /boop -> /search/woo all works as expected.

Am I missing something here? Do I need to manually trigger this somehow, or should optional parameter changes trigger the components to update?

Thanks!

1 个答案:

答案 0 :(得分:1)

You need to sync state to props on every change if you want to store this term in component's state.

export default class Search extends Component {
    ...

    componentWillReceiveProps(nextProps) {
      const newSearchTerm = nextProps.match.params.searchTerm
      if(this.state.searchTerm !== newSearchTerm) {
          this.setState(() => ({ searchTerm: newSearchTerm }))
      }
    }

    ...
}

But there is no reason to do it. Use this.props in render. It could be as simple as this

export default ({ match: { params: { searchTerm } } }) => (
    <div className="Search">
       SEARCH: {searchTerm}
       <SearchResults searchTerm={searchTerm} />
     </div>
)