当上下文发生变化时,使用上下文的子组件不应该自动更新吗?

Shouldn't child components that use context update themselves automatically when context gets changed?

我正在尝试创建本地化解决方案。

出于测试目的,我有以下结构

index.js

import { Provider } from 'react-redux';
import store from './store';  //This is a redux store
import LocalizedComponent from './components/containers/HomeContainer';

function App() {
  return (
    <Provider store={store}>
      <LocalizedComponent />
    </Provider>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

HomeContainer 组件是一个 HOC,它将一个简单的展示组件包装到一个本地化组件中。

localization.jsx

import React, { PropTypes } from 'react';
import STRINGS from 'strings'; //This is an object containing translations


const translate = mapper => (Component) => {
  function LocalizedComponent(props, { store }) {
    const language = store.getState().language;
    const translatedProps = mapper(STRINGS, language);
    return (
      <Component {...props} {...translatedProps} />
    );
  }
  LocalizedComponent.contextTypes = {
    store: React.PropTypes.object
  };

  return LocalizedComponent;
};

export default translate;

mapper是这样的函数

const mapTranslationToProps = (strings, language) => ({
  <property key>: strings.<some key>[language]
});

Component 可能是这样的

Home.jsx

import React from 'react';

function SomeComponent(props) {
  return (
    <div>
      <p>{props.<property key>}</p>
    </div>
  );
}
SomeComponent.propTypes = {
  <property key>: React.PropTypes.string
};
SomeComponent.defaultProps = {
  <property key>: ''
};

export default SomeComponent;

为了将所有这些结合在一起,我们这样做

HomeContainer.jsx

import Home from 'components/presentational/Home';
import translate from 'components/HOC/Localization';

const mapTranslationToProps = (strings, language) => ({
  <property key>: strings.<some key>[language]
});

LocalizedComponent = translate(mapTranslationToProps)(SomeComponent);

export default LocalizedComponent;

第一次渲染时,通过 context 从状态中选择正确的 language 并相应地显示文本

然而,当我发送一个改变状态 language 的动作时,组件没有得到更新。

我的印象是,上下文的更改会触发重新渲染(如果适用),但似乎并非如此。

我尝试使用生命周期方法将 localization.jsx 中的 LocalizedComponent 实现为 class,但我注意到 shouldComponentUpdate 在状态更改时甚至不会触发。

我希望 LocalizedComponents 在所选语言更改时自动更新。显然我一定是做错了什么。

谁能帮我理解一下?

如果你使用 React-Redux 你应该使用 connect 方法将你的组件连接到 redux store。
更新 context 值不会触发组件重新渲染 - 当 context 中的任何内容发生更改时,不会通知 React 组件。仅当 React 组件的状态已更改、其父级已重新渲染或 forceUpdate 已被调用时,才会重新渲染。在你的例子中,上下文只是指向一个充当 redux 存储的对象,而 React 组件不知道这个对象的变化。 此外,你不应该更新上下文。根据反应 docs:

Don't do it.

React has an API to update context, but it is fundamentally broken and you should not use it.

此外,在 React-Redux 上下文存储中 属性 总是指向同一个存储对象——当状态更新时,只有一些内部存储对象属性被更改,但上下文仍然持有相同的对象引用,所以实际上上下文值没有改变。

有两种解决方案可确保在分派操作后 redux 状态发生更改时通知并更新您的组件。

如果你使用 React-Redux,你应该使用 React-Redux connect。根据文档 connect returns:

A higher-order React component class that passes state and action creators into your component derived from the supplied arguments.

当给定组件使用的状态属性发生变化时,连接到存储的组件将自动重新呈现。

如果您不使用 React-Redux,您也可以使用 Redux store subscribe 方法手动订阅商店更新。根据文档 subscribe:

Adds a change listener. It will be called any time an action is dispatched, and some part of the state tree may potentially have changed. You may then call getState() to read the current state tree inside the callback.