简体   繁体   English

在组件中使用 React 上下文

[英]Using React context in a component

Say I create a simple React context to check if I am connected假设我创建了一个简单的 React 上下文来检查我是否已连接

import NetInfo, { NetInfoState } from '@react-native-community/netinfo';
import Constants, { AppOwnership } from 'expo-constants';
import React, { PropsWithChildren, createContext, useContext, useEffect, useState } from 'react';
import { Platform } from 'react-native';

const ConnectionContext = createContext<boolean>(undefined);

export function ConnectionProvider({ children }: PropsWithChildren<any>): JSX.Element {
  const [connected, setConnected] = useState(false);

  function handleConnectionChange(netInfo: NetInfoState) {
    setConnected(
      (Platform.OS === 'ios' && Constants.appOwnership === AppOwnership.Expo) ||
        (netInfo.isConnected && (netInfo.isInternetReachable ?? true))
    );
  }

  useEffect(() => {
    const subscriptionCancel = NetInfo.addEventListener(handleConnectionChange);
    return () => subscriptionCancel();
  }, []);

  return <ConnectionContext.Provider value={connected}>{children}</ConnectionContext.Provider>;
}

export function useConnection() {
  return useContext(ConnectionContext);
}

I was wondering if I want to use it in my existing component XYZ , is there a less roundabout way of doing it than the following我想知道我是否想在我现有的组件XYZ使用它,是否有比以下更迂回的方法

From:从:

export function XYZ() {
   ...xyz code...
}

to:至:

export function XYZ() {
  return (
    <ConnectionContextProvider>
      <RealXyz>
    </ConnectionContextProvider>
  );
}
function RealXyz() {
  const connected = useConnection();
  ...xyz code...
}

I don't think context is really necessary for this since a connection is more of a singleton type of thing.我不认为上下文真的是必要的,因为连接更像是一种单例类型的东西。 The following code should be in its own file, and you can import this hook anywhere in your app.下面的代码应该在它自己的文件中,你可以在你的应用程序的任何地方导入这个钩子。

let _isConnected = false;

export const useConnection = () => {
  const [isConnected, setConnected] = useState(_isConnected);

  useEffect(() => {
    function handleConnectionChange(netInfo: NetInfoState) {
      _isConnected =  (Platform.OS === 'ios' && Constants.appOwnership === AppOwnership.Expo) ||
        (netInfo.isConnected && (netInfo.isInternetReachable ?? true))
      
      setConnected(_isConnected);
    }
    
    const subscriptionCancel = NetInfo.addEventListener(handleConnectionChange);

    return () => subscriptionCancel();
  }, []);

  return isConnected;
}

Explanation:解释:

Let's say you have two components which use this hook.假设您有两个使用此钩子的组件。 When your app first renders, only ComponentA is mounted.当您的应用程序首次呈现时,只会安装 ComponentA。 Some time later the connection state changes to true .一段时间后,连接状态更改为true Then some time later ComponentB is mounted.然后一段时间后安装 ComponentB。 We want ComponentB to know that the connection state is currently true , which is why we use the singleton pattern (eg. private global variable _isConnected ).我们希望 ComponentB 知道连接状态当前为true ,这就是我们使用单例模式(例如私有全局变量_isConnected )的原因。 It doesn't matter much that there are multiple event listeners as those are cheap and get removed when the component is unmounted.有多个事件侦听器并不重要,因为它们很便宜并且在卸载组件时会被删除。

Context is handy if you have data that needs to be shared across multiple components and you do not want to pass it down the tree by props.如果您有需要在多个组件之间共享的数据,并且您不想通过 props 将其传递到树中,则 Context 很方便。

from the docs :文档

Context provides a way to pass data through the component tree without having to pass props down manually at every level. Context 提供了一种通过组件树传递数据的方法,而无需在每个级别手动向下传递 props。

In your example I would use useState , but to give you a good idea where you could opt for context check the following snippet:在您的示例中,我将使用useState ,但是为了让您了解可以选择上下文检查以下代码段的位置:

...

function ABC() {
  const connected = useConnection();
  ...abc code...
}

function ABCParent() {
  return <ABC />
}

...

function XYZ() {
  const connected = useConnection();
  ...xyz code...
}

function XYZParent() {
  return <XYZ />
}

...

function App() {
 return (
  <ConnectionContextProvider>
    <ABCParent />
    <XYZParent />
  </ConnectionContextProvider>
 )
}

The two components that make use of the context are "deep" in the tree and in separate branches.使用上下文的两个组件在树的“深处”和单独的分支中。 The example is a bit simple and you could easily pass the data that you need through props and still have a maintainable code base.这个例子有点简单,你可以很容易地通过 props 传递你需要的数据,并且仍然有一个可维护的代码库。

But ultimately if you feel that your data model can be "global" and you have enough dependents in separate branches or in the same branch in multiple levels go for context API.但最终,如果您觉得您的数据模型可以是“全局的”,并且您在单独的分支或多个级别的同一分支中有足够的依赖项,请使用上下文 API。

Some data model examples where I find the use of context API useful are theme, app settings, routing and translations.我发现使用上下文 API 有用的一些数据模型示例是主题、应用程序设置、路由和翻译。

One thing to note: The components that depend on a context will be less reusable (This is more relevant across projects) and sometimes you can opt for composition instead of using the context API.需要注意的一件事:依赖于上下文的组件的可重用性将降低(这在项目之间更相关),有时您可以选择组合而不是使用上下文 API。 Check the before you use context section of the docs for more information about this.查看文档的使用前上下文部分以获取有关此内容的更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM