反应:像妈妈朋友的儿子一样的插槽

组成组件时,经常会出现自定义组件内容的任务。例如,我们有一个DatePicker组件,我们需要在Web应用程序的不同部分显示不同的Apply按钮。

为了解决这些问题,当今的每一种流行技术都使用“插槽”的概念。Angular具有ngContentVueSvelteWebComponents具有插槽。如今,只有流行的React库没有完整的插槽概念。

在React中有几种方法可以解决这个问题:

  1. 组件可以完全呈现​​其所有子代,也可以通过React.Children API对其进行“爬升”并逐点操作子代

  2. 组件可以声明所谓的renderProps,并在正确的位置渲染从它们返回的内容:

    <MyComponent renderFooter={data => (<h1>Bye, ${data.name}</h1>)}/>

renderProps方法通常众所周知,没有基本缺陷。与成熟的插槽相比,除非使用起来不太方便。NPM有几个库,例如react-view-slot,但我认为它们不够方便,最重要的是,仅解决问题即可。

我决定尝试修复此致命缺陷,现在我将告诉您如何。

我看到了目标-我没有看到实施

在编写任何东西之前,了解要获取的API很有用。这是我想要的结果的草图:

const Component = props => {
  Component.NameSlot = useSlot(props.children);

  return (
    <div>
      <h1>
        <Component.NameSlot.Receiver>
          Default value
        </Component.NameSlot.Receiver>
      </h1>

      Hello {props.children}
    </div>
  );
};

function App() {
  return (
    <div>
      Hello!
      <Component>
        Foo
        <Component.NameSlot>
          Bobobo
        </Component.NameSlot>
      </Component>
    </div>
  );
}

这个想法是创建必要的插槽并将功能组件存储在静态属性中,然后在发送和接收端适当地使用它。

, . – , , , -, . , , API, :

import {createSlot} from 'react-slotify';

export const MySlot = createSlot();

export const Component = ({children}) => {
  return (
    <div>
      This component contains slot:
      
      <MySlot.Renderer childs={children}>
        This is default slot content
      </MySlot.Renderer>
      
      <div>It also renders children: {children}</div>
    </div>
  );
};
import {Component, MySlot} from './component';

const App = () => {
  return (
    <div>
      <Component>
        <MySlot>Slotted content</MySlot>
        Other content
      </Component>
    </div>
  );
};

, API, , –  MySlot, {children}, , MySlot.Renderer. , JS-, :

export function createSlot() {
  const Slot = ({ children, showChildren }) => {
    return showChildren ? children : null;
  }

  const Renderer = ({ childs, children }) => {
    const slotted = React.Children.toArray(childs).find(child => {
      return React.isValidElement(child) && child.type === Slot;
    });

    if (!slotted || !React.isValidElement(slotted)) {
      return children;
    }
    return React.cloneElement(slotted, { showChildren: true });
  };

  Slot.Renderer = Renderer;

  return Slot;
}

-, 20 . , React- , . . –  Slot. , :

export function createSlot() {
  const Slot = ({ children, showChildren }) => {
    return showChildren ? children : null;
  }
  return Slot;
}

, Slot –  , showChildren={true}. , , Slot .

– Renderer. –  -, Slot-, , showChildren={true}:

  const Renderer = ({ childs, children }) => {
    const slotted = React.Children.toArray(childs).find(child => {
      return React.isValidElement(child) && child.type === Slot;
    });

    if (!slotted || !React.isValidElement(slotted)) {
      return children;
    }
    return React.cloneElement(slotted, { showChildren: true });
  };

, Renderer , , Slot . .

–  Renderer Slot, : <MySlot.Renderer/>.

因此,在20行代码中,我们实现了一个概念,这是许多其他技术开发人员非常喜欢的,而React却没有。

我发表的成品实施的反应,slotify库GitHub上,并作为一个包NPM已经在TypeScript中并且支持插槽的参数化我很高兴收到建设性的批评。




All Articles