上下文未通过 redux connect() 传递

Context not being passed through redux connect()

编辑: 我能够根据设置 { pure: false } 的 Redux 故障排除中的建议对上下文更改进行连接 Child 更新,但是我需要将此添加到我要更新的 Child 的 parents 的所有连接组件。必须对很多组件执行此操作似乎很奇怪且效率低下。


首先,在深入探讨我认为的问题所在之前,我将描述我想要的最终结果。

我想访问 react router from within a grandchild component of my Route component. There are several references that say it is not necessary to sync the current route with the store if you are not using "recording, persisting, and replaying user actions, using time travel" so I have avoided it so far. Dan Abramov states 的参数,可以保留它们 un-synced 并且只使用路由作为真实来源。

我的问题没有答案的类似问题:

由于 react-router 不提供当前参数作为上下文,我选择从 Route 组件添加当前参数作为上下文。我可以沿着组件树一直访问上下文,直到到达使用 connect() 设置的 Child。页面的初始呈现为 Child 提供了正确的上下文。但是,当上下文发生变化时,Child 不会更新。 connect() 似乎正在剥离上下文 link。

这是 connect() 的预期行为吗?如果是这样,组件应该如何在不将它们同步到商店的情况下访问路由参数?

Here 是一个 JSFiddle,显示了一个非常小的场景,其中上下文不会更新到 "connected" 组件之后。

这是我的一些实际代码,我将当前路由参数作为上下文从 路由器组件 (/view/:viewSlug) 发送。我 尝试按照 redux troubleshooting 中的描述在 connect 中将组件设置为 { pure: false } 但没有成功。

Parent(应用程序)组件

class App extends Component {
  getChildContext() {
    const { viewSlug } = this.props

    return { viewSlug }
  }

  ...
}

App.PropTypes = {
  ...
}

App.childContextTypes = {
  viewSlug: PropTypes.string
}

...

export default connect(mapStateToProps)(App)

孙(日)容器

import Day from '../components/Day'

const mapStateToProps = (state, ownProps) => {
  ...
}

export default connect(mapStateToProps)(Day)

孙(日)分量

class Day extends Component {
  ...
}

Day.PropTypes = {
  ...
}

Day.contextTypes = {
  viewSlug: PropTypes.string.isRequired
}

export default Day

在与 Dan Abramov 快速讨论后,似乎没有 好的 方法可以将参数向下传递到各种深层组件。 (Discussion here)。一旦 React Router 3.0 发布,这将非常容易正确实施。

解决方法

目前我发现的唯一解决方法是将子组件以及子组件和路由组件之间的任何祖先组件设置为 "un-pure" 组件。

这可以在使用 connect() 函数时通过选项参数完成。

export default connect(mapStateToProps, null, null, { pure: false })(MyComponent)

此信息是在 Redux Troubleshooting page

上找到的

我有同样的问题:我在路由路径中有一个语言参数,我将其存储为上下文并在我的应用程序的所有组件中使用。当我连接 redux store 时,上下文属性不再更新。

正如您所提到的,有一个 { pure: false } 参数可以强制重新渲染组件的次数超过需要的次数。

另一种不使用上下文的解决方案。您可以使用 react-router-redux 保存和更新 Redux 存储中更改的 URL。它有自己的动作 LOCATION_CHANGE,它有一个有效载荷对象:

routing: {
    locationBeforeTransitions: {
        pathname: 'view/someView',
        search: '',
        …
    }
}

目前它没有参数,但您可以解析 pathname 并以老式正则表达式的方式获取它们。 :)

请阅读这个问题,还有一些其他解决方法:https://github.com/facebook/react/issues/2517

更新:

还有另一种方式——在 redux store 中保存你的应用状态:

…
import { setCurLang } from '../actions/langActions';

const App = React.createClass({
    componentWillMount(){
        this.props.actions.setCurLang(this.props.params.curLang);
    },
    shouldComponentUpdate: function(nextProps) {
        return nextProps.params.curLang !== this.props.params.curLang;
    },
    componentWillUpdate(nextProps) {
        this.props.actions.setCurLang(nextProps.params.curLang);
    },
    render() {
        return (
            <div>
                {/* here you can use your saved URL-param as prop,
                    and it will be updated each time react router changes */}
                {this.props.curLang}
            </div>
        )
    }
});
function mapStateToProps(state) {
    return {
        curLang: state.curLang
    }
}
function mapDispatchToProps(dispatch) {
    return {
        actions: bindActionCreators( { setCurLang }, dispatch)
    }
}
export default connect(null, mapDispatchToProps)(App);

我的reducer(这个是简化过的,当然你可以在这里用combineReducers):

const curLang = 'de';

export default function reducer(state = curLang, action) {
    switch (action.type){
        case 'SET_CUR_LANG':
            return { ...state, cur: action.curLang }
        default:
            return state;
    }
}

和操作:

export function setCurLang(curLang) {
    return {
        type: 'SET_CUR_LANG',
        curLang: curLang
    }
}

使用react-redux connect()收不到this.context的原因 是我们没有指定 contextTypes check this comment

像这样添加contextTypes

import PropTypes from 'prop-types';

Myapp.contextTypes = { store: PropTypes.object };

现在,我们可以发现this.context有值,商店this.context.store上可用

查看更多插图this comment also