
对于不使用现成的组件集(例如material-ui)而是实现自己的组件的开发人员而言,本文将主要有用。 例如,已经为该产品开发了一种产品,该产品反映了按钮,模式窗口等的外观。 为了正确地实现这样的设计系统,其所有原子都需要为其组成增加良好的支持。 换句话说,必须确保任何单个组件都可以集成并完美地集成到较大的复合组件中。 如果他不适合,那么对他的自定义提供简单的支持将是很好的。 尽管如此,这是一个单独的大话题,也许我会在下一次再谈。
歌词
大家好 我从一篇简单但有用的文章开始了在中心的旅程。 对于我来说,结果太详细了,但是我仍然试图适应读者,而不是我自己。 在撰写下一个关于更复杂主题的文章(如果有)之前,我希望根据反馈(如果有)调整我的演示文稿。
使用的术语:
- 可视组件是返回嵌入DOM中的元素的组件。 例如,
return (<div />)
。 仅返回另一个组件的组件不应以视觉方式进行解释。
引言
开发组件时,不能使其完全通用。 在您的头脑中,您始终从使用它的特定选项开始。 事实证明,开发之后,您的同事开始“将组件推向任何地方”。 您对他们感到生气:“好吧,我没有为此开发它! 它不是要完成此任务的!” 当然,改进是不可避免的,甚至是必要的。 但这不应该是改进,例如抛出新的道具以将缩进从4px增加到8px,这将在五十种情况中的一种或两种情况下使用。 组件必须具有自定义的外部几何形状。
TypeScript,帮帮忙
考虑该接口,该接口应位于例如
src/Library/Controls.ts
。 对该字段给出了简短的评论,下面我们将对其进行更详细的分析。
export interface VisualComponentProps {
这是组件道具界面。 哪一个 所有视觉组件。 它们应应用于其根元素。
每个已开发视觉组件的道具都应使用此界面进行扩展。
立即注意所有这些道具都是可选的。 考虑他们。
children
组件位于React.Component类组件,React.FC组件组件中,但是在未指定React.FC类型的情况下它们不在普通函数中。 因此,我们问他。className/style
使用类似的名称,就像通常的JSX'nom <div />中一样。 我们不产生语义。 例如, 在道具中使用此名称标识原则来指定ref链接 。doNotRender
用作条件条件下 JSX 渲染中痛苦的拐杖的替代方法。 应用此解决方案,我们无需在渲染方法中放置大括号,这会损害代码的可读性。 比较2个代码段:
原始条件渲染:
App.tsx
renderComponent() { const {props, state} = this; const needRender = state.something; return ( <PageLayout> <UIButton children={'This is a button'} /> {needRender && <UIButton children={'This is another button'} /> } </PageLayout> ); }
乍得道具doNotRender:
App.tsx
renderComponent() { const {props, state} = this; const needRender = state.something; return ( <PageLayout> <UIButton children={'This is a button'} /> <UIButton children={'This is another button'} doNotRender={!needRender} /> </PageLayout> ); }
在第一个版本中,我们增加了底部按钮的嵌套级别,尽管就其含义而言,其嵌套与顶部按钮处于同一级别。 在我的编辑器中看起来很糟糕,在这里我使用宽度为2个空格的制表符,在这里情况更糟。
在第二个选项中,我们具有相等的嵌套,但是doNotRender可能不会引起注意,并且开发人员将无法理解正在发生的事情。 但是,如果在您的项目中每个视觉组件都是根据此原理制作的,则此问题将立即消失。
- 如果我们不想使用
doNotRender true
呈现null
,而是某种自定义元素, fallback
需要fallback
。 它与React Suspense类似地使用,因为它具有相似的含义(我们不产生语义)
我想展示如何正确使用它。 让我们做一个简单的按钮。
注意:在下面的代码中,我还使用css-modules,sass和类名。
UIButton.tsx
import * as React from 'react'; import { VisualComponentProps } from 'Library/Controls'; import * as css from './Button.sass'; import cn from 'classnames';
App.tsx
renderComponent() { const {props, state} = this; const needRenderSecond = true; return ( <PageLayout> <UIButton children={'This is a button'} style={{marginRight: needRenderSecond ? 5 : null}} /> <UIButton disabled children={'This is another button'} doNotRender={!needRenderSecond} /> </PageLayout> ); }
结果:

反思与结论
使用诸如divs之类的组件,创建各种包装,合成,专业化等组件,
超出其原始功能的框架,非常方便 。
可以说,由于设计系统中没有条件黄色按钮,并且开发人员需要制作它们,所以问题不在于组件,而在于需要创建的事实。 但是,现实情况是这种情况经常发生。 “……但是我们必须生活!我们必须生活。” 另外,css级联原理并非总是可以在实践中实现,并且您可能会遇到这样的情况,即您的样式只是与另一个选择器(或如上所述)的更高特异性重叠。 在这里,风格只会有所帮助。
最后,我将添加一些(从字面上看)的时刻。
- 请注意,doNotRender不会完全重复条件渲染行为。 您还将运行生命周期方法,只是render将返回后备或null。 在某些复杂的组件中,您可能要避免执行生命周期方法。 为此,您只需要对组件进行内置的特殊化处理即可 。
使用UIButton示例:将UIButton重命名为UIButtonInner并在其下添加以下代码:
UIButton.tsx
export function UIButton(props: ButtonProps) { if (props.doNotRender) return props.fallback || null; return <UIButtonInner {...props} />; }
PS不要在此函数中进行UIButton递归调用错误!
- 在极少数情况下,包装器和被包装的组件上的样式可以独立更改时,以下界面可能对您有用
Library/Controls.ts
export interface VisualComponentWrapperProps extends VisualComponentProps { wrappedVisual?: VisualComponentProps; }
及其使用UIButton.tsx
interface ButtonSomeWrapperProps extends ButtonBasicProps, VisualComponentWrapperProps { myCustomProp?: number; } export function UIButtonSomeWrapper(props: ButtonSomeWrapperProps) { if (props.doNotRender) return props.fallback || null; const {
使用这种方法开发应用程序将显着提高组件的可重用性,减少不必要的拐杖样式(仅针对其他组件的需求谈论组件样式文件中描述的样式)和道具,并添加结构化代码。 仅此而已。 在下一篇文章中,我们将开始从代码方面而不是从CSS角度来解决组件可重用性的问题。 或者,我会写一些更有趣的东西。 谢谢您的关注。