上下文没有通过redux connect()传递

时间:2016-05-09 18:46:01

标签: javascript reactjs react-router redux react-redux

修改:我可以根据设置{ pure: false }的Redux故障排除中的建议更改上下文中的子连接更新但是我需要将其添加到所有连接的组件中我想要更新的孩子的父母。对于许多组件来说,这似乎很奇怪且效率低下。

首先,在深入研究我认为存在的问题之前,我将描述我期望的最终结果。

我想从路由组件的孙子组件中访问react router的参数。有几个参考文献表示,如果你没有使用"recording, persisting, and replaying user actions, using time travel",没有必要将当前路由与商店同步,所以到目前为止我已经避免使用它了。丹·阿布拉莫夫(Dan Abramov)表示here可以让他们不同步,只使用这条路线作为真理的来源。

类似的问题没有解决我的问题: https://stackoverflow.com/a/36633892/2300773
Passing store through context with <Provider> not working in connect() based scenario

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

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

Here是一个JSFiddle,它显示了一个非常小的场景,其中上下文没有经过&#34; connected&#34;更新。成分

以下是我的实际代码,其中我将当前路由参数作为路由器组件/view/:viewSlug)的上下文发送。我已经尝试将组件设置为连接中的{ pure: false },如redux troubleshooting中所述,但没有运气。

父(App)组件

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

3 个答案:

答案 0 :(得分:8)

在与Dan Abramov进行快速讨论之后,似乎没有一种良好的方式将params传递给各种深层组件。 (Discussion here)。一旦React Router 3.0发布,这将是非常简单的正确实现。

解决方法

目前我发现的唯一解决方法是将子组件以及子组件和路径组件之间的任何祖先组件设置为“非纯”组件。

使用 connect()功能时,可以使用options参数完成此操作。

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

此信息可在Redux Troubleshooting page

中找到

答案 1 :(得分:1)

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

添加 contextTypes

import PropTypes from 'prop-types';

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

现在,我们可以发现this.context有一个值,并且 store this.context.store上可用

有关更多说明,请检查this comment also

答案 2 :(得分:0)

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

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

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

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

现在它没有params,但你可以解析pathname并以旧学校的regexp方式获取它们。 :)

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

<强>更新

还有另一种方法 - 在redux商店中保存您的应用状态:

…
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
    }
}