在 React Native 中使用多个上下文提供程序的更好方法

Better way to use multiple context providers in ReactNative

我有一个正在使用 3 Context Provider 的应用程序。为了让应用程序正常运行,我必须将 <App/> 包裹在所有这些 providers 中。随着我的应用程序的增长,我希望有更多的提供商来提供我必须连接的更多类型的数据。我已经开始觉得可能有更好的方法将提供程序传递到 <App />

我的App.js代码:

import React from 'react';
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import { Provider as BlogProvider} from './src/context/BlogContext';
import { Provider as VehicleProvider} from './src/context/VehicleContext';
import { Provider as AuthProvider} from './src/context/AuthContext';

import IndexScreen from './src/screens/IndexScreen';
import ShowScreen from './src/screens/ShowScreen';
import CreateScreen from './src/screens/CreateScreen';
import EditScreen from './src/screens/EditScreen';
import VehicleScreen from './src/screens/VehicleScreen';

const navigator = createStackNavigator(
  {
    Index: IndexScreen,
    Show: ShowScreen,
    Create: CreateScreen,
    Edit: EditScreen,
    Debug: DebugScreen,
    Vehicle: VehicleScreen,

  },
  {
    initialRouteName: 'Index',
    defaultNavigationOptions: {
      title: 'Main'
    }
  }
);

const App = createAppContainer(navigator);

export default () => {
  return (
    <BlogProvider>
      <VehicleProvider>
        <AuthProvider>
             <App />
        </AuthProvider>
      </VehicleProvider>
    </BlogProvider>
  );
};

我的一些问题是:

  1. 有没有更好的方法在 App 中使用多个上下文提供程序。
  2. 这些provider的嵌套顺序对App有影响吗?
  3. 我们可以跳过在 <App/> 中添加提供程序,而是将它们导入到需要它的任何屏幕中,并将该屏幕元素包装在其中吗?

答案

答案一:

  1. 没有更好的方法来添加应用程序级提供程序,但某些提供程序没有上下文应用程序级别的意思(我们不需要应用程序内所有地方的上下文)。一些供应商有模块级别。所以你可以包裹在特定的树或组件之外
const UserScreen = () => (
  <UserProvider>
    <UserScreen />
  <UserProvider />
)

答案二:

  1. 在工作中没有效果,但有时我们需要从父函数调用子函数,因此,我们需要使用ref。在这个嵌套级别提供程序中,我们必须使用 forwardRef。其余的一切正常。

答案3:

  1. 是的,我们可以跳过 App.js 中的提供程序,如果该提供程序不是应用程序级的,这意味着我们不需要在应用程序的任何地方使用上下文。如果我们需要一个或两个屏幕或一棵树中的上下文,那么我们可以将该屏幕或树包装在提供者中,不要在 App.js
  2. 中使用
  1. 我不确定你所说的“更好”是什么意思。如果你只是想清理你的 App 组件,你可以将 Provider 渲染抽象为一个单独的函数。 or 可能会根据你的需要帮你完成

  2. 如果像您的示例一样,您用所有 Providers 包装整个应用程序并且它们彼此独立,那么顺序将无关紧要。否则它们的行为与其他组件没有什么不同,只有 children 可以访问其数据并且数据流是单向的。

  3. 是的,您无需为整个应用程序提供所有数据。

我不会按提问的顺序回答。

回答 3

如果提供者仅为特定组件提供上下文,您应该在该组件中导入和使用它。 不要 用它包裹 App

原因是每当提供者更新时,每个消费者都会重新渲染,你不能不使用 React.memoReactPureComponentshouldComponentUpdate 来停止它。 You should not overuse context

const Root = () => {
  return (
    <AppProvider>
      <ComponentProvider>
        <App/>
      <ComponentProvider>
    </AppProvider>
  )
}

const App = () => {
  return (
    <>
      <ComponentA/>
      <ComponentB/>
    <>
  )
}

const ComponentContext = createContext()
const ComponentProvider = ({ children }) => {
  // If any value here is updated --> all consumer will be render
  // --> App re-render --> ComponentA and ComponentB re-render
  return (
    <ComponentContext.Provider value={{ value1, value2, value }}>
      {children}
    </ComponentContext.Provider>
  )
}

你应该这样做

const Root = () => {
  <AppProvider>
    <App/>
  </AppProvider>
}

const App = () => {
  return (
   <>
    <ComponentA/>
    <ComponentB/>
   <>
  )
}

const ComponentA = () => {
  return (
    <ComponentProvider>
      <OtherComponent/>
    <ComponentProvider>
   )
}

const ComponentContext = createContext()
const ComponentProvider = ({ children }) => {
  // If any value here is updated --> all consumer (ComponentA only) will be render
  return (
    <ComponentContext.Provider value={{ value1, value2, value3 }}>
      {children}
    </ComponenContext.Provider>
  )
}

回答 1

答案 3 可以解决这个问题,在正确的位置使用上下文(对于仅使用上下文的组件。不要在 App 级别随机使用每个上下文)。如果您的上下文经常更新,我建议不要使用 other ways,这样您可以使用 React.memoPureComponentshouldComponentUpdate 来防止不必要的重新渲染以优化性能。

答案 2

订单不会影响应用程序。

  1. 有没有更好的方法在应用程序中使用多个上下文提供程序。

回答:是

  • 你可以使用任何数字 Context Providers 环绕你的 App,但要确保那些 Providers 的数据不应该经常更新并且它们被视为全局状态表示它们可以从您应用程序的任何位置访问或将被访问。例如:您的应用主题、身份验证状态、用户个人资料……
  • 如果数据被视为特定用例,仅在 App 的少数几个地方使用,则不应使用 Context Provider,因为如果更新数据,则其所有子项都将被更新被迫重新渲染,无论你使用任何 React API 来阻止它,就像 React.memo。参考this
  1. 这些提供者的嵌套顺序对App有影响吗

回答:是

  • 正如我在回答 1 中所说,如果 Provider 有经常更新的数据是更新频率较低的数据的父级,它将影响其所有子级,因此您可以通过包装最较少更新最外层作为父级。
  1. 我们能否跳过添加提供程序的步骤,而是将它们导入到需要它的任何屏幕中,并将该屏幕元素包装在其中?

答案:这取决于您的用例。