React全局组件

10

我是一名Vue.js开发者,最近开始学习React。

我有一个组件:PageContent.jsx,希望能够在render函数(JSX)中使用它而不必不断地导入它。

在Vue中,我们可以使用以下方法将组件全局化:

Vue.component(componentName, componentObject)

在React中是否有类似的东西?

3个回答

4

嗯,React中没有任何形式的“全局”组件。每个组件都必须被导入或作为prop传递。但如果你想避免在每个文件中添加import,有几种选择:

1)创建一个Higher Order Component,它可以渲染PageContent和包装的组件。

import PageContent from './PageContent';

const withPageContent = WrappedComponent => {
  return class extends React.Component {
    render () {
      return (
        <PageContent>
          <WrappedComponent />
        </PageContent>
      )
    }
  }
};

export default withPageContent;

// Usage

import withPageContent from './withPageContent';

class MyComponent extends React.Component {
  render () {
    return (
      <div>
        I'm wrapped in PageContent!
      </div>
    )
  }
}

export default withPageContent(MyComponent);

2) 将PageContent作为一个prop传递给组件:

import PageContent from './PageContent';

export default class App extends React.Component {
  render() {
    return (
      <React.Fragment>
        <Child1 content={PageContent} />
        <Child2 content={PageContent} />
      </React.Fragment>
    )
  }
}

// Usage

export default class Child1 extends React.Component {
  render () {
    const PageContent = this.props.content;
    return (
      <PageContent>
        I'm wrapped in PageContent!
      </PageContent>
    )
  }
}

export default class Child2 extends React.Component {
  render () {
    const PageContent = this.props.content;
    return (
      <PageContent>
        I'm wrapped in PageContent!
      </PageContent>
    )
  }
}

2
谢谢你的示例,不过我真的在寻找一些可以减少每个组件所需导入量的东西。不过如果我想使用React的话,似乎只能接受这种情况了。 - Stan Hurks
2
是的,您仍然需要导入某些内容,但是有一些技巧可以使它对您更容易。您可以使用webpack resolve使导入路径变得更短,并删除文件扩展名。您还可以创建一个单个文件,将多个组件导出,然后可以像这样一行导入多个组件:import { Button、 Input、 Icon } from 'utils/inputs'; - Chase DeAnda

4
我非常赞同Chase的回答。如果你需要另一种方法,可以使用context api。你可以在App根组件或另一个嵌套的组件树中声明一个想要轻松访问的组件集合。
以下是一个使用useContext hook的示例,但hooks并不是必须使用的。结构是标准的create-react-app结构。
我们想要全局访问的组件 - src/deep/Header.js:
function Header() {
  return (
    <h1>
      I am a global component
    </h1>
  );
}

export default Header;

上下文创建 - src/global-components-context.js:
import React from 'react';

const MyContext = React.createContext(null);

export default MyContext;

全局组件的分组 - src/global-components.js:
import Header from './deep/Header';

const contextValue = {
  Header,
};

export default contextValue;

应用程序的初始化文件 - src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import MyContext from './global-components-context';
import contextValue from './global-component';

ReactDOM.render(
  <MyContext.Provider value={contextValue}>
    <App />
  </MyContext.Provider>,
  document.getElementById('root')
);

在未导入组件的情况下使用该组件 - src / App.js

import { useContext } from 'react';
import globalComponent from './global-components-context';

function App() {
  const Context = useContext(globalComponent);
  return (
    <div className="App">
      <Context.Header />
    </div>
  );
}

export default App;

我认为这是React中最全局的组件。请注意,您仍然需要在想要使用全局组件的地方导入上下文。

另外还有一个声明,全局组件很难测试,通常很难理解。我相信这就是为什么React中没有标准解决方案的原因。

希望我能帮到你。


0

tl;dr: 在以下示例中使用Zustand全局状态管理库:
https://snack.expo.dev/3yNFvhCmI?platform=web


解决方案

有两种主要的方法可以实现这个目标:

  • Context API — Context API 是 React 中的一个内置功能,提供了一种简单的方法来在组件之间共享状态。
  • 状态管理库 — 第三方库,如 ReduxMobXZustand,用于全局状态管理。

虽然 Context API 的解决方案相对简单,不需要额外的依赖,但它可能导致不必要的重新渲染,并带来一些样板代码的开销。

考虑到这些因素以及其他因素,在这种情况下选择一个专用的状态管理库可能是有益的。个人建议不要在这种情况下使用 Redux,因为它的体积庞大、复杂、需要大量样板代码,并且可能对性能产生影响。特别是对于较小的项目来说,使用 Redux 会过度设计。


演示

两个工作示例展示了相同的用例,使用了两个React Native模态框:
(这里使用React Native只是因为我目前正在使用它;这可以很容易地重构为React)


使用Context API的逐步描述

言而无信,不如行而有据。”:

1. 项目结构:

- src
  - components
    - global
      - GlobalComponent1.js
      - GlobalComponent2.js
      - index.js
  - contexts
    - GlobalComponentsContext.js
  - screens
    - HomeScreen.js
- App.js

2. 基本原则:
import { createContext, useState } from 'react';

export const GlobalComponentsContext = createContext();

export const GlobalComponentsProvider = ({ children }) => {
  const globalState = {};

  [ globalState.value1, globalState.setValue1 ] = useState(false);
  [ globalState.value2, globalState.setValue2 ] = useState(false);

  return (
    <GlobalComponentsContext.Provider value={ globalState }>
      { children }
    </GlobalComponentsContext.Provider>
  );
};


3. 一个示例的全局组件:
import { GlobalComponentsContext } from '../../contexts/GlobalComponentsContext';

const GlobalComponent1 = () => {
  // accessing the global state; drop-in replacement for useState()
  const { value1, setValue1 } = useContext(GlobalComponentsContext);

  [...]
};

export default GlobalComponent1;

4. 用 Context.Provider 包装 App
import { GlobalComponentsProvider } from './src/contexts/GlobalComponentsContext';
import HomeScreen from './src/screens/HomeScreen';
import GlobalComponents from './src/components/global';

export default function App() {
  return (
    <GlobalComponentsProvider>
      <HomeScreen />
      <GlobalComponents />
    </GlobalComponentsProvider>
  )
}


5. 全局组件的示例用法:
import { useContext } from 'react';
import { View, Text, Button } from 'react-native';
import { GlobalComponentsContext } from '../contexts/GlobalComponentsContext';

const HomeScreen = () => {
  // Take the state variables that you need:
  const { value1, setValue2 } = useContext(GlobalComponentsContext);

  return (
    <View>
      <Text>Value1: {value1}</Text>
      <Button title="setValue2" onPress={() => setValue2(true)} />
    </View>
  );
};

export default HomeScreen;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接