React中的可重复使用的组件(附代码)

249 阅读4分钟

基本上,一个React应用程序只是一个组件树中的一堆组件。有一个根组件负责为下面的所有其他组件进行渲染。在现代React应用程序中,这些组件通常是功能组件。但它们也可以是类组件。然而,并不是所有这些组件在你的组件层次结构中都只使用一次。那么,因为组件有更普遍的用途而重用它们呢?在本教程中,我们将逐步完成使一个组件在我们的React应用程序中可重复使用的过程。

使React组件可重用

一般来说,我们通过把一个组件从特定的变成更通用的来使它更可重用。这可以通过为该组件提供一个API来实现。在React中,一个组件的API就是它的props。让我们通过重构一个组件来体验一下,把它从非常具体的变成更通用的。通常,当我们开始使用React应用程序时,除了通常称为App的根组件,我们没有任何组件。

import React from 'react';

const App = () => {
  const handleClick = () => console.log('Clicked!');

  return (
    <div>
      <button type="button" onClick={handleClick}>
        Click me!
      </button>
    </div>
  );
};

export default App;

例如,为了使这个HTML按钮在React中可重复使用,我们必须将其提取为自己的组件。让我们为它定义一个Button组件。

import React from 'react';

const App = () => {
  return (
    <div>
      <Button />
    </div>
  );
};

const Button = () => {
  const handleClick = () => console.log('Clicked!');

  return (
    <button type="button" onClick={handleClick}>
      Click me!
    </button>
  );
};

export default App;

在React的JSX中使用这个Button组件作为元素,每次都会创建这个Button组件的一个新实例。这已经是你为使一个组件在React中可重用而进行的一半工作了。然而,尽管从React的角度来看,这个组件是可重用的,但它还不是真正的可重用,因为每个Button组件都实现了同样的行为。在下一个代码片断中,所有的组件都会做同样的事情,因为它们遵循同样的实现细节。

import React from 'react';

const App = () => {
  return (
    <div>
      <Button />
      <Button />
    </div>
  );
};

让我们改变这种情况,给Button组件一个API,这是我们从外部指挥Button组件的接口。例如,从外部实现的最重要的东西是点击处理程序。每个按钮在点击时都应该有不同的表现。

const Button = ({ handleClick }) => {
  return (
    <button type="button" onClick={handleClick}>
      Click me!
    </button>
  );
};

现在,在你的组件中使用Button组件,你可以把点击处理函数作为道具传递给组件,但要为每个Button组件单独指定。

const App = () => {
  return (
    <div>
      <Button
        handleClick={() => console.log('Clicked button One!')}
      />
      <Button
        handleClick={() => console.log('Clicked button Two!')}
      />
    </div>
  );
};

从这里开始,你可以一步一步地重构它,把更多的属性移到特定的Button组件之外,通过使用它的API使它更通用。另一个属性可以是显示在按钮上的标签。

const App = () => {
  return (
    <div>
      <Button
        label={'Click Button One!'}
        handleClick={() => console.log('Clicked button One!')}
      />
      <Button
        label={'Click Button Two!'}
        handleClick={() => console.log('Clicked button Two!')}
      />
    </div>
  );
};

const Button = ({ label, handleClick }) => {
  return (
    <button type="button" onClick={handleClick}>
      {label}
    </button>
  );
};

我们也可以使用React内置的children属性,这在React中通常用于组合

const App = () => {
  return (
    <div>
      <Button handleClick={() => console.log('Clicked button One!')}>
        Click Button One!
      </Button>
      <Button handleClick={() => console.log('Clicked button Two!')}>
        Click Button Two!
      </Button>
    </div>
  );
};

const Button = ({ handleClick, children }) => {
  return (
    <button type="button" onClick={handleClick}>
      {children}
    </button>
  );
};

通过向外部提供API,Button组件几乎是100%通用的。但有一块是缺失的。我们的按钮的type 属性是在Button组件中连接的,我们不能从外部对它做任何事情。然而,我们也看到,这使事情变得更容易,因为大多数时候HTML按钮元素都有type="button" ,因此我们不需要从外部为每个Button组件提供它。但是,如果我们想改变type 属性(例如,将其改为submit ),又该怎么办?

const App = () => {
  return (
    <div>
      <Button handleClick={() => console.log('Clicked button One!')}>
        Click Button One!
      </Button>
      <Button
        type="submit"
        handleClick={() => console.log('Clicked button Two!')}
      >
        Click Button Two!
      </Button>
    </div>
  );
};

const Button = ({ type = 'button', handleClick, children }) => {
  return (
    <button type={type} onClick={handleClick}>
      {children}
    </button>
  );
};

我们可以为我们的Button组件的type 属性实现一个默认道具。每次我们从外部指定这个属性时,我们就会覆盖Button组件(这里:Button Two)中给出的默认道具。但每次没有提供任何东西时,就会使用默认的道具(这里:Button One)。


你已经看到了如何重构一个React组件,使之从特定的变成更通用的。通用的React组件通常在整个应用程序中被广泛使用,因为它们具有高度的可重用性。另一个好处是在一个地方拥有你的应用程序中广泛使用的一个组件的实现。如果这个组件的实现细节发生了变化,你可以在这个地方进行调整,并在你的应用程序中到处生效。