11

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

每次离开或更改路线时,我都想重置/更改 Redux 状态。每次路由更改时,我都会使用react-router-redux调度动作history.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 状态(在控制台)。

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

4

3 回答 3

22

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
    }
}
于 2016-06-19T20:04:08.587 回答
8

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

路由器:

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

第 1 页容器:

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 答案)。

于 2017-07-05T04:22:25.920 回答
3

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

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

因为这个componentWillUnmount()不会运行,同一个组件只会收到新的 props 因此,您可以使用componentWillReceiveProps(newProps)进行比较并相应地更新。

如果您确实想强制重新安装组件,则需要确保要重新安装的组件具有不同的键属性,请参阅此处此处了解更多信息。

于 2018-01-08T09:35:47.660 回答