使用 react-router-dom 在位置更改时调度 Redux 操作
Dispatching Redux actions on location change with react-router-dom
我正在将 React 和 Redux 用于搜索应用程序。使用 react-router-dom
,我将 /search/:term?
路由到 Search
组件:
<Router>
<Switch>
<Route exact path="/search/:term?" component={Search} />
<Redirect to="/search" />
</Switch>
const Search = (props) => {
const { term } = props.match.params;
return (
<div>
<SearchForm term={term}/>
<SearchResults />
</div>
)
};
当用户在 SearchForm
组件中提交搜索时,我将调度一个操作来提交搜索查询。如果给出一个术语,我也会在构造函数中启动搜索,最初:
class SearchForm extends Component {
constructor(props) {
super(props);
const term = props.term ? props.term : '';
this.state = {
term: term,
}
if (term) {
this.props.submitSearch(term);
}
}
handleSubmit = (e) => {
e.preventDefault();
if (this.state.term) {
this.props.submitSearch(this.state.term);
}
}
render = () => {
<form
onSubmit={this.handleSubmit.bind(this)}>
...
</form>
}
}
我正在使用 react-router-dom
中的 withRouter
,因此 URL 在提交搜索时更新。
当用户在他们的浏览器中导航返回时会出现问题。 URL 导航返回,道具更新(即 props.match.params.term
),但是搜索不重新提交。这是因为 submitSearch
操作仅在 SearchForm.constructor
中调度(如果术语在 URL 中则在初始加载时搜索)和 SearchForm.handleSubmit
.
在 URL 发生变化时侦听状态更改为 term
,然后调度搜索操作的最佳方法是什么?
我目前的解决方案是在 componentWillRecieveProps
生命周期方法中调度 submitSearch
如果新道具与当前道具不匹配:
componentWillReceiveProps(nextProps) {
if (this.props.term !== nextProps.term) {
this.setState({
term: nextProps.term,
});
this.props.submitSearch(nextProps.term);
}
}
然后,我没有在提交表单时调度操作,而是将一个新位置推送到 history
上,然后 componentWillReceiveProps
进行调度:
handleSubmit = (e) => {
e.preventDefault();
if (this.state.term) {
this.props.history.push('/search/'+this.state.term);
}
}
这个解决方案感觉有点不对,但它确实有效。 (其他人似乎同意:Evil things you do with redux — dispatch in updating lifecycle methods)
这样做是否违反了 React 或 Redux 原则?我可以做得更好吗?
我会在 componentDidMount
中检索路由参数,因为您正在推送新路由并因此重新加载视图。
在您的 SearchForm 中,它看起来像这样。
state = {
term: '';
}
onChange = (term) => this.setState({ term })
onSubmit = () => this.props.history.push(`/search/${this.state.term}`);
并且在您的搜索结果中:
componentDidMount() {
this.props.fetchResults(this.props.term)
}
保持 SearchResult 组件干燥是一件好事。有几种方法可以实现,这里是使用 higher order components aka HOC :
export default FetchResultsHoc(Component) => {
@connect(state => ({ results: state.searchResults }))
class FetchResults extends React.Component {
componentDidMount(){
dispatch(fetchResults(this.props.match.params.term))
}
render(){
<Component {...this.props} />
}
}
return FetchResultsHoc;
}
然后您将使用装饰器调用 SearchResult 组件。
import { fetchResults } from './FetchResultsHoc';
@fetchResults
export default class SearchResult extends React.PureComponent { ... }
// You have now access to this.props.results inside your class
我正在将 React 和 Redux 用于搜索应用程序。使用 react-router-dom
,我将 /search/:term?
路由到 Search
组件:
<Router>
<Switch>
<Route exact path="/search/:term?" component={Search} />
<Redirect to="/search" />
</Switch>
const Search = (props) => {
const { term } = props.match.params;
return (
<div>
<SearchForm term={term}/>
<SearchResults />
</div>
)
};
当用户在 SearchForm
组件中提交搜索时,我将调度一个操作来提交搜索查询。如果给出一个术语,我也会在构造函数中启动搜索,最初:
class SearchForm extends Component {
constructor(props) {
super(props);
const term = props.term ? props.term : '';
this.state = {
term: term,
}
if (term) {
this.props.submitSearch(term);
}
}
handleSubmit = (e) => {
e.preventDefault();
if (this.state.term) {
this.props.submitSearch(this.state.term);
}
}
render = () => {
<form
onSubmit={this.handleSubmit.bind(this)}>
...
</form>
}
}
我正在使用 react-router-dom
中的 withRouter
,因此 URL 在提交搜索时更新。
当用户在他们的浏览器中导航返回时会出现问题。 URL 导航返回,道具更新(即 props.match.params.term
),但是搜索不重新提交。这是因为 submitSearch
操作仅在 SearchForm.constructor
中调度(如果术语在 URL 中则在初始加载时搜索)和 SearchForm.handleSubmit
.
在 URL 发生变化时侦听状态更改为 term
,然后调度搜索操作的最佳方法是什么?
我目前的解决方案是在 componentWillRecieveProps
生命周期方法中调度 submitSearch
如果新道具与当前道具不匹配:
componentWillReceiveProps(nextProps) {
if (this.props.term !== nextProps.term) {
this.setState({
term: nextProps.term,
});
this.props.submitSearch(nextProps.term);
}
}
然后,我没有在提交表单时调度操作,而是将一个新位置推送到 history
上,然后 componentWillReceiveProps
进行调度:
handleSubmit = (e) => {
e.preventDefault();
if (this.state.term) {
this.props.history.push('/search/'+this.state.term);
}
}
这个解决方案感觉有点不对,但它确实有效。 (其他人似乎同意:Evil things you do with redux — dispatch in updating lifecycle methods)
这样做是否违反了 React 或 Redux 原则?我可以做得更好吗?
我会在 componentDidMount
中检索路由参数,因为您正在推送新路由并因此重新加载视图。
在您的 SearchForm 中,它看起来像这样。
state = {
term: '';
}
onChange = (term) => this.setState({ term })
onSubmit = () => this.props.history.push(`/search/${this.state.term}`);
并且在您的搜索结果中:
componentDidMount() {
this.props.fetchResults(this.props.term)
}
保持 SearchResult 组件干燥是一件好事。有几种方法可以实现,这里是使用 higher order components aka HOC :
export default FetchResultsHoc(Component) => {
@connect(state => ({ results: state.searchResults }))
class FetchResults extends React.Component {
componentDidMount(){
dispatch(fetchResults(this.props.match.params.term))
}
render(){
<Component {...this.props} />
}
}
return FetchResultsHoc;
}
然后您将使用装饰器调用 SearchResult 组件。
import { fetchResults } from './FetchResultsHoc';
@fetchResults
export default class SearchResult extends React.PureComponent { ... }
// You have now access to this.props.results inside your class