反应多个上下文

ATO*_*TOA 10 reactjs

我正在使用通过上下文传递的函数.

ChildComponent.contextType = SomeContext;
Run Code Online (Sandbox Code Playgroud)

现在我用this.context.someFunction();.这有效.

如果我需要来自两个不同父组件的函数,我该怎么做?

cor*_*ard 23

你仍然可以使用16.3 Context API的函数作为子消费者节点,这是React文档建议做的:

// Theme context, default to light theme
const ThemeContext = React.createContext('light');

// Signed-in user context
const UserContext = React.createContext({
  name: 'Guest',
});

class App extends React.Component {
  render() {
    const {signedInUser, theme} = this.props;

    // App component that provides initial context values
    return (
      <ThemeContext.Provider value={theme}>
        <UserContext.Provider value={signedInUser}>
          <Layout />
        </UserContext.Provider>
      </ThemeContext.Provider>
    );
  }
}

function Layout() {
  return (
    <div>
      <Sidebar />
      <Content />
    </div>
  );
}

// A component may consume multiple contexts
function Content() {
  return (
    <ThemeContext.Consumer>
      {theme => (
        <UserContext.Consumer>
          {user => (
            <ProfilePage user={user} theme={theme} />
          )}
        </UserContext.Consumer>
      )}
    </ThemeContext.Consumer>
  );
}
Run Code Online (Sandbox Code Playgroud)

要在组件的上下文中使用函数,通常将组件包装在HOC中,以便将上下文作为props传递:

export const withThemeContext = Component => (
  props => (
    <ThemeContext.Consumer>
      {context => <Component themeContext={context} {...props} />}
    </ThemeContext.Consumer>
  )
)

const YourComponent = ({ themeContext, ...props }) => {
  themeContext.someFunction()
  return (<div>Hi Mom!</div>)
}

export default withThemeContext(YourComponent)
Run Code Online (Sandbox Code Playgroud)


Dim*_*rov 13

另一种解决方案是创建一个单独的上下文来提供其他上下文:

import React, { createContext, memo, useContext } from "react";
import isEqual from "react-fast-compare";

export const MultiContext = createContext(null);
MultiContext.displayName = "MultiContext";

export const MultiContextProvider = memo(
  function({ map, children }) {
    const contextMap = {};
    for (const i in map) {
      contextMap[i] = useContext(map[i]);
    }

    return (
      <MultiContext.Provider value={contextMap}>
        {children}
      </MultiContext.Provider>
    );
  },
  (prevProps, nextProps) => isEqual(prevProps.children, nextProps.children)
);

MultiContextProvider.displayName = "MultiContextProvider";
Run Code Online (Sandbox Code Playgroud)

用法示例:

class DemoConsumer extends React.Component {
  static contextType = MultiContext;

  render() {
    return JSON.stringify({
      someValue: this.context.SomeContext.someValue,
      otherValue: this.context.OtherContext.otherValue,
    });
  }
}

function App() {
  return (
    <MultiContextProvider map={{ SomeContext, OtherContext }}>
      <MultiContextDemoClassConsumer />
    </MultiContextProvider>
  );
}
Run Code Online (Sandbox Code Playgroud)

演示:

import React, { createContext, memo, useContext } from "react";
import isEqual from "react-fast-compare";

export const MultiContext = createContext(null);
MultiContext.displayName = "MultiContext";

export const MultiContextProvider = memo(
  function({ map, children }) {
    const contextMap = {};
    for (const i in map) {
      contextMap[i] = useContext(map[i]);
    }

    return (
      <MultiContext.Provider value={contextMap}>
        {children}
      </MultiContext.Provider>
    );
  },
  (prevProps, nextProps) => isEqual(prevProps.children, nextProps.children)
);

MultiContextProvider.displayName = "MultiContextProvider";
Run Code Online (Sandbox Code Playgroud)
class DemoConsumer extends React.Component {
  static contextType = MultiContext;

  render() {
    return JSON.stringify({
      someValue: this.context.SomeContext.someValue,
      otherValue: this.context.OtherContext.otherValue,
    });
  }
}

function App() {
  return (
    <MultiContextProvider map={{ SomeContext, OtherContext }}>
      <MultiContextDemoClassConsumer />
    </MultiContextProvider>
  );
}
Run Code Online (Sandbox Code Playgroud)


gas*_*ard 7

您还可以将所有上下文简单地合并为一个上下文:

const AppContext = React.createContext({
  user: { name: 'Guest' },
  theme: 'light',
})

ChildComponent.contextType = AppContext;
Run Code Online (Sandbox Code Playgroud)

做完了 如果您在应用程序的某些部分具有不同的上下文(例如,不同的主题或用户),则只需合并新值。

  • 重新考虑您的解决方案。当上下文值在某些嵌套对象中更改时,它会进行额外的重新渲染,不是吗?用户和主题都可以具有嵌套的对象,并且在更改对象后,即使在不需要的情况下,它也导致在所有位置重新渲染(即使不需要)。请纠正我的错误 (7认同)
  • @HoussemBadri 也许你可以发布一个答案来证明你的建议? (5认同)
  • @sunpietro,如果上下文的值发生变化,任何使用该上下文的组件都将重新渲染,是的。这就是为什么在树的顶部有一个不经常更改的上下文以及在更接近其使用位置的地方更改的上下文是有意义的。 (2认同)