在路由更改时更新 Redux 状态

Posted

技术标签:

【中文标题】在路由更改时更新 Redux 状态【英文标题】:Update Redux state on route change 【发布时间】:2016-10-21 00:48:10 【问题描述】:

我一直试图弄清楚这一点,但我越来越困惑。

我想在每次离开或更改路线时重置/更改 Redux 状态。我使用 react-router-reduxhistory.listener 在每次路由更改时调度一个动作

history.listen(location => store.dispatch(resetManualsCategory()));

动作创建者:

export function resetManualsCategory() 
    return 
        type: 'RESET_MANUALS_CATEGORY'
    


减速器

export function manualCategories(state=[], action) 
    switch (action.type) 
        case 'SELECT_MANUALS_CATEGORY':
           [...]

        case 'RESET_MANUALS_CATEGORY':
            console.log('test reducer');
            return Object.assign(, state, 
                manualCategory: 'test'
            )

        default:
            return state
    

最让我困惑的是,如果我刷新页面或在顶部导航中单击两次路由,状态会更新,但是即使动作和减速器触发,单个路由更改也不会影响 redux 状态(显示控制台中的测试消息)。

我做错了什么,这里到底发生了什么?

【问题讨论】:

【参考方案1】:

我在更改路线时使用了不同的方法来重置状态。我没有收听历史/路由器,而是在我的页面容器上使用componentWillMount 事件来调度“重置页面”操作。 示例:

路由器:

<Provider store=store>
  <Router history=history>
    <Route path="/page1" component=Page1Container />
    <Route path="/page2" component=Page2Container />
  </Router>
</Provider>

Page1 容器:

class Page1Container extends Component 

  componentWillMount() 
    this.props.resetPage()
  

  render() 
    // render Page1
   


const mapStateToProps = (state) => 
  return 
    // ...
  


const mapDispatchToProps = (dispatch) => 
  return 
    // ...
    resetPage: () =>  dispatch(type: 'PAGE1_RESET_PAGE') 
  


export default connect(mapStateToProps, mapDispatchToProps)(Page1Container)

减速机:

const initialState = null

export function Page1Reducer (state = initialState, action) 
  switch (action.type) 
    case 'PAGE1_RESET_PAGE': 
      state = initialState
      break
    

    // ...
  


更新: 正如@DavidHarkness 提到的,这种方法的缺陷是组件在安装时会渲染两次。 除此之外,我现在倾向于认为这种解决方案并不优雅,最好避免在组件内部使用业务逻辑。 在 reducer 中移动逻辑将是一个更好的选择(请参阅@DiegoHaz 答案)。

【讨论】:

如果由于某种原因您只需要重置组件使用的状态部分,这似乎是一个很好的解决方案。 这不是用之前的状态渲染,然后立即用新的状态再次渲染吗?【参考方案2】:

目前我正在使用componentWillUnmount() 来执行此操作。我在减速器中有一个动作设置,我想重置以重置其状态,并从 componentWillUnmount() 方法调度该动作。

您可能会遇到的一个问题是,当使用 React Router 时,路由更改不会触发刷新,并且组件不会重新安装在同一路由上,例如,如果您有一个 posts/new 和一个 posts/edit /:id 路由都使用同一个组件来编辑帖子,在这些路由之间切换不会导致组件重新挂载。

因为这个 componentWillUnmount()NOT 运行,相同的组件只会接收新的道具。因此,您可以使用 componentWillReceiveProps(newProps) 进行比较并进行相应的更新。

如果您确实想强制重新挂载组件,您需要确保要重新挂载的组件具有不同的键属性,请参阅here 和here 了解更多信息。

【讨论】:

【参考方案3】:

react-router-redux 提供了一个 LOCATION_CHANGE 动作,该动作已经在每次路由更改时调度。你可以做的很简单:

import  LOCATION_CHANGE  from 'react-router-redux'

export function manualCategories(state=[], action) 
    switch (action.type) 
        case LOCATION_CHANGE:
            /*
              action.payload is something like:
              
                pathname: '/',
                search: '',
                hash: '',
                state: null,
                action: 'PUSH',
                key: 'xwl8yl',
                query: ,
                $searchBase: 
                  search: '',
                  searchBase: ''
                
              
            */

        default:
            return state
    

【讨论】:

LOCATION_CHANGE@@router/LOCATION_CHANGE 一样吗? 是的。您也可以使用“@@router/LOCATION_CHANGE”,但不建议这样做。 我刚刚意识到是什么导致了这个问题,它与这个问题略有不同。也许你能帮忙? ***.com/questions/37912180/… 如果您只想重置特定路线的状态,这是否也适用? 这个答案不再起作用了。 react-router-redux 已重命名为 connected-react-router,并且看起来不再像以前那样工作了。

以上是关于在路由更改时更新 Redux 状态的主要内容,如果未能解决你的问题,请参考以下文章

React,redux 组件不会在路由更改时更新

REACT + REDUX:在 redux 状态更改时 mapStateToProps 更新状态,但视图未按照新状态呈现

触发 Redux 操作以响应 React Router 中的路由转换

Redux - 异步 - 输入字段更改时的 POST 状态

更新:没有调用 Redux reducer 来更改 CSS 类

REACT + REDUX:在redux状态更改mapStateToProps更新状态但视图不按照新状态呈现