首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反应继承与组合模式

反应继承与组合模式
EN

Stack Overflow用户
提问于 2020-07-18 00:06:42
回答 2查看 290关注 0票数 2

(这更多地是一个哲学/教学问题,而不是一个实际问题。)

我试图在React中解释组合对继承的好处。我立刻想到了一个会打破继承等级的体系结构:

代码语言:javascript
复制
class Border extends React.Component {}

class ColorBorder extends Border {}

class DashedBorder extends Border {}

class DashedColorBorder extends ??? {}

然后我想,“哈!这将是很容易实现与组成!”

编辑下面的其他内容,从核心问题上转移注意力:“你如何最有效地演示在继承会分崩离析的岩石中,构图如何反应?”这是我最感兴趣的问题。/EDIT

但有趣的是,我还是被困住了:

代码语言:javascript
复制
const Border = ({ children }) => (
  <div className="Border">
    {children}
  </div>
)

const ColorBorder = ({ color, children }) => (
  <Border style={{ borderColor: color }}>
    {children}
  </Border>
)

const DashedBorder = ({ children }) => (
  <Border style={{ borderStyle: 'dashed' }}>
    {children}
  </Border>
)

const DashedColorBorder = ({ color, children }) => (
  // how to use both ColorBorder and DashedBorder?
)

从实际的角度来看,解决方案很简单:只需扩展Border以接受更多的道具,就不用理会这些废话了。但我很好奇,为了争论,是否有办法做到这一点。

这让我怀疑,这是否是一个很好的例子,说明了组合在继承中的主导地位,以及是否有一个更好的更明显的例子。大多数文章用不精确的术语谈论反应成分,迅速跳入HOCs等等。进一步说,他们甚至没有试图解释使用继承和它开始下降的地方的反应。我总想弄明白“为什么不?”人们相信构图更好,我正在寻找怎样做的例子。

我能想出的最好办法就是这个,但我很好奇其他人会怎么处理它。在这些示例中,我不满意您仍然需要手动提供一个:

代码语言:javascript
复制
const Border = ({ children, style }) => (
  <div className="Border mb-3" style={style}>
    {children}
  </div>
)

const ColorBorder = ({ color, children }) => (
  React.Children.map(children, child => (
    React.cloneElement(child, {
      style: { ...child.props.style, borderColor: color },
    })
  ))
)

const DashedBorder = ({ children }) => (
  React.Children.map(children, child => (
    React.cloneElement(child, {
      style: { ...child.props.style, borderStyle: 'dashed' },
    })
  ))
)

const DashedColorBorder = ({ color, children }) => (
  <DashedBorder>
    <ColorBorder color={color}>
      {children}
    </ColorBorder>
  </DashedBorder>
)

export const App = () => (
  <div className="App">
    <Border>
      Hello world
    </Border>

    <ColorBorder color="green">
      <Border>
        Hello world
      </Border>
    </ColorBorder>

    <DashedBorder>
      <Border>
        Hello world
      </Border>
    </DashedBorder>

    <DashedColorBorder color="red">
      <Border>
        Hello world
      </Border>
    </DashedColorBorder>
  </div>
)
EN

回答 2

Stack Overflow用户

发布于 2020-07-18 04:40:14

为了避免使用cloneElement,您可以使用上下文,如下所示,尽管在实践中,这仍然比简单地制作一个独立的<DashedColorBorder>组件要痛苦得多。为了演示目的,我还添加了一个<ThickBorder>组件。

代码语言:javascript
复制
import React, { useContext } from "react";

const StyleContext = React.createContext({});

const Border = ({ style, children }) => (
  <div
    className="Border"
    style={{
      ...useContext(StyleContext),
      ...style // keep if you want to be able to override style directly
    }}
  >
    {children}
  </div>
);

const ColorBorder = ({ color, innerMost = true, children }) => {
  return (
    <StyleContext.Provider value={{ ...useContext(StyleContext), 
     borderColor: color }}>
      {innerMost ? <Border>{children}</Border> : children}
    </StyleContext.Provider>
  );
};

const DashedBorder = ({ innerMost = true, children }) => {
  return (
    <StyleContext.Provider value={{ ...useContext(StyleContext), 
     borderStyle: "dashed" }}>
      {innerMost ? <Border>{children}</Border> : children}
    </StyleContext.Provider>
  );
};

const ThickBorder = ({ innerMost = true, children }) => {
  return (
    <StyleContext.Provider value={{ ...useContext(StyleContext), 
     borderWidth: "5px" }}>
      {innerMost ? <Border>{children}</Border> : children}
    </StyleContext.Provider>
  );
};

const DashedColorBorder = ({ color, children }) => (
  <DashedBorder innerMost={false}>
    <ColorBorder color={color}>{children}</ColorBorder>
  </DashedBorder>
);

const ThickDashedColorBorder = ({ color, children }) => (
  <ThickBorder innerMost={false}>
    <DashedColorBorder color={color}>{children}</DashedColorBorder>
  </ThickBorder>
);

export default function App() {
  return (
    <div className="App">
      <Border>Hello world</Border>
      <ColorBorder color="green">Hello world</ColorBorder>
      <DashedBorder>Hello world</DashedBorder>
      <DashedColorBorder color="red">Hello world</DashedColorBorder>
      <ThickDashedColorBorder color="blue">Hello world</ThickDashedColorBorder>
    </div>
  );
}

CodeSandbox演示

票数 1
EN

Stack Overflow用户

发布于 2020-07-18 03:38:44

I 修改你的代码

代码语言:javascript
复制
import React from "react";
import "./styles.css";

const Border = ({ children, style }) => (
  <div className="Border mb-3" style={{ borderStyle: "solid", ...style }}>
    {children}
  </div>
);

const ColorBorder = ({ color, children }) => (
  <Border style={{ borderColor: color }}>{children}</Border>
);

const DashedBorder = ({ children }) => (
  <Border style={{ borderStyle: "dashed" }}>{children}</Border>
);

const DashedColorBorder = ({ color, children }) => (
  <Border style={{ borderColor: color, borderStyle: "dashed" }}>
    {children}
  </Border>
);

const App = () => (
  <div className="App">
    <Border>Hello world</Border>

    <ColorBorder color="blue">Hello world</ColorBorder>

    <DashedBorder>Hello world</DashedBorder>

    <DashedColorBorder color="red">Hello world</DashedColorBorder>
  </div>
);

export default App;

我的一般建议是避免继承和cloneElement,除非绝对必要。

在Facebook,我们在数千个组件中使用React,我们还没有找到任何建议创建组件继承层次结构的用例。 道具和组合为您提供了以显式和安全的方式定制组件外观和行为所需的所有灵活性。请记住,组件可以接受任意道具,包括原语值、React元素或函数。

https://reactjs.org/docs/composition-vs-inheritance.html

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62963238

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档