服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

【第2886期】无渲染组件

日期: 来源:前端早读课收集编辑:Starrier

前言

继续昨日【第2885期】精读《Headless 组件用法与原理》的 Headless 组件。今日前端早读课文章由 @Starrier 翻译分享。

正文从这开始~~

无头用户界面组件是一种不提供任何接口而提供最大视觉灵活性的组件。“等等,你是在提倡没有用户界面的用户界面模式么?”

是的,这正是我所提倡的。

掷硬币组件

假设你现在需要实现一个掷硬币的功能,当组件渲染时模拟一次掷硬币!一半的时间组件应该渲染 “正面”,一半的时间应该渲染 “反面”。你对你的产品经理说 “这需要多年的研究!” 然后你继续工作。

 const CoinFlip = () =>
Math.random() < 0.5 ? <div>Heads</div> : <div>Tails</div>;

事实证明,模仿掷硬币比你想象的要容易得多,所以你可以自豪地分享成果。你得到了回复,“这真的是太棒了!请更新那些显示很酷的硬币的图片好么?” 没问题!

 const CoinFlip = () =>
Math.random() < 0.5 ? (
<div>
<img src=”/heads.svg” alt=”Heads” />
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />
</div>
);

很快,他们会在营销材料中使用你的 <CoinFlip /> 组件,来向人们演示你的新功能有多么炫酷。“我们想在博客上发表文章,但是我们需要标签 'Heads' 和 'Tails',用于 SEO 和其他事情。” 哦,天啊,或许我们需要在商城网站中添加一个标志?

 const CoinFlip = (
// We’ll default to false to avoid breaking the applications
// current usage.
{ showLabels = false }
) =>
Math.random() < 0.5 ? (
<div>
<img src=”/heads.svg” alt=”Heads” />

{/* Add these labels for the marketing site. */}
{showLabels && <span>Heads</span>}
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />

{/* Add these labels for the marketing site. */}
{showLabels && <span>Tails</span>}
</div>
);

后来,出现了一个需求。“我们想知道你能否只给 APP 里的 <CoinFlip /> 添加一个重掷硬币的按钮?” 事情开始变得糟糕,以致于我不敢再直视 Kent C. Dodds 的眼睛。

 const flip = () => ({
flipResults: Math.random()
});

class CoinFlip extends React.Component {
static defaultProps = {
showLabels: false,
// We don’t repurpose `showLabels`, we aren’t animals, after all.
showButton: false
};

state = flip();

handleClick = () => {
this.setState(flip);
};

render() {
return (
// Use fragments so people take me seriously.
<>
{this.state.showButton && (
<button onClick={this.handleClick}>Reflip</button>
)}
{this.state.flipResults < 0.5 ? (
<div>
<img src=”/heads.svg” alt=”Heads” />
{showLabels && <span>Heads</span>}
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />
{showLabels && <span>Tails</span>}
</div>
)}
</>
);
}
}

很快就有同事找到你。“嗨,你的 <CoinFlip /> 性能太棒了!我们刚接到任务要开发新的 <DiceRoll /> 特性,我们希望可以重用你的代码!” 新骰子的功能:

  • 想要 “重新掷骰子” 的 onClick。

  • 希望在 APP 和商城网站中都显示。

  • 有完全不同的界面。

  • 有不同的随机性。

你现在有两个选项,回复 “对不起,我们不一样。” 或着你一边向 CoinFlip 中添加 DiceRoll 的复杂功能,一边看着组件无法承受过多职责而崩溃。(是否有一个给忧郁的程序员诗人的市场?我喜欢追求这种技术。)

无头组件了解一下

无头用户界面组件将组件的逻辑和行为与其视觉表现分离。当组件的逻辑足够复杂并与它的视觉表现解耦时,这种模式非常有效。实现 <CoinFlip/> 的无头将作为函数子组件或渲染属性,就像这样:

 const flip = () => ({
flipResults: Math.random()
});
class CoinFlip extends React.Component {
state = flip();
handleClick = () => {
this.setState(flip);
};
render() {
return this.props.children({
rerun: this.handleClick,
isHeads: this.state.flipResults < 0.5
});
}
}

这个组件是无头的,因为它没有渲染任何东西,它期望当它在处理逻辑的时,各种 consumers 完成视觉表现。因此 APP 代码看起来应该是这样的:

 <CoinFlip>
{({ rerun, isHeads }) => (
<>
<button onClick={rerun}>Reflip</button>
{isHeads ? (
<div>
<img src=”/heads.svg” alt=”Heads” />
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />
</div>
)}
</>
)}
</CoinFlip>

商场站点代码:

 <CoinFlip>
{({ isHeads }) => (
<>
{isHeads ? (
<div>
<img src=”/heads.svg” alt=”Heads” />
<span>Heads</span>
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />
<span>Tails</span>
</div>
)}
</>
)}
</CoinFlip>

这很好不是么!我们把逻辑与视觉表现完全解耦!这给我们视觉上带来了很大的灵活性!我知道你正在思考什么......

你这小笨蛋,这不就是一个渲染属性么?

这个无头组件恰好是作为渲染工具实现的,是的!它也可以作为一个高阶组件来实现。即使是简单的实现,也可以到达我们的要求。它甚至可以作为 View 和 Controller 来实现。或者是 ViewModel 和 View。这里的重点是将翻转硬币的机制和该机制的 “界面” 分离。

那 <DiceRoll /> 呢?

这种分离的巧妙之处在于,推广我们的无头组件以及支持我们同事的新的 <DiceRoll /> 的特性会很容易。拿着我的 Diet Coke™:

 const run = () => ({
random: Math.random()
});

class Probability extends React.Component {
state = run();

handleClick = () => {
this.setState(run);
};

render() {
return this.props.children({
rerun: this.handleClick,

// By taking in a threshold property we can support
// different odds!
result: this.state.random < this.props.threshold
});
}
}

利用这个无头组件,我们在没有对 consumer 进行任何更改对情况下,交换 <CoinFlip /> 的实现:

 const CoinFlip = ({ children }) => (
<Probability threshold={0.5}>
{({ rerun, result }) =>
children({
isHeads: result,
rerun
})}
</Probability>
);

现在我们的同事可以分享我们的 <Probability /> 模拟程序机制了!

 const RollDice = ({ children }) => (
// Six Sided Dice
<Probability threshold={1 / 6}>
{({ rerun, result }) => (
<div>
{/* She was able to use a different event! */}
<span onMouseOver={rerun}>Roll the dice!</span>
{/* Totally different interface! */}
{result ? (
<div>Big winner!</div>
) : (
<div>You win some, you lose most.</div>
)}
</div>
)}
</Probability>
);

非常干净,不是么?

分离原则 —— Unix 哲学

这表达了一个存在很长时间对普遍基本原则,“Unix 基础哲学第四条”:

分离原则:将策略与机制分离,将接口和引擎分离 —— Eric S. Raymond。

我想借用书中的部分,并且用 “接口” 来替换 “策略” 一词。

接口和机制都倾向于在不同时间范围内变化,但接口的变化比机制要快得多。GUI 工具包那时尚的外观和体验会变,但是操作和组合却不会。

因此,将接口和机制结合在一起有两个不好的影响:它使得接口变的生硬,更难响应用户的需求,这意味着试图更改接口具有很强的不稳定性。

另一方面,通过将这两者分开,我们可以在没有中断机制的情况下试验新的接口。我们还可以更容易地为该机制编写好的测试(接口,因为它们太新了,难以证明这样的投资是合理的)。

我喜欢这里的真知灼见!这也让我们对何时使用无头组件模式有了一些了解。

  • 这个组件会持续多长时间?除了界面外,是否值得刻意保留这个机制?也许在另一个外观和体验不同的项目中可以使用这种机制?

  • 我们的界面改变的频率多快?同一机制会有多个接口么?

当你将 “机制” 和 “策略” 分离时,就会产生间接的成本。你需要确保分离的价值大于它的间接成本。我认为这在很大程度上是过去许多 MV* 模式出问题的地方,它们从这样一个公理开始,即所有的东西都应该以这种方式分开;而在现实中,机制和策略往往是紧密耦合的,或分离的成本并没有超过分离的好处。

开源无头组件和非平凡引用

要获取一个真正的示例性非平凡无头组件,可以了解一下我朋友 Kent C. Dodds 在 Paypal 上的项目:downshift 的文章。事实上,正是 downshift 给了这篇文章一些灵感。在不提供任何用户界面的情况下,downshift 提供了复杂的自动完成、下拉、选择体验,这些体验都是可以访问的。在这里看看它所有可用的方法。

我希望随着时间的推移,会出现更多类似的项目。我无法计算有多少次我想使用一个特定的开源 UI 组件,但却无法这样做,因为在满足设计要求的方式上,它并不是 “主题化的” 或 “可剥离的”。无头组件完全通过 “自带接口” 的要求来解决这个问题。

在一个设计系统和用户界面库都是无头的世界里,你的界面可以有一种高端定制的感觉,以及优秀开源库的持久性和可访问性。你仅需要将时间花费在你所需要的部分 —— 一个独特的,外观及体验都只属于你 APP 的部分。

我可以继续讨论从国际化到 E2E 测试集成的好处,但我建议你最好自己去体验。

关于本文
译者:@Starrier
译文:https://github.com/xitu/gold-miner/blob/master/TODO1/headless-user-interface-components.md
作者:@Merrick Christensen
原文:https://medium.com/merrickchristensen/headless-user-interface-components-565b0c0f2e18
校对者:@xunge0613、@Moonliujk

这期前端早读课
对你有帮助,帮” 赞 “一下,
期待下一期,帮” 在看” 一下 。

相关阅读

  • 【第2885期】精读《Headless 组件用法与原理》

  • 前言Headless 组件即无 UI 组件,框架仅提供逻辑,UI 交给业务实现。今日前端早读课文章由 @黄子毅分享,公号:前端精读评论授权。正文从这开始~~Headless 组件即无 UI 组件,框架仅提
  • 专业的设计师如何产出不专业的方案

  • 经常看到读者私信说想看组件相关的文章,诚然,认识和了解组件很重要,但只是了解组件、会用组件是否就能做出好的设计?我想以某知名打车软件活动页为例,展开聊聊。这是一个在打车过
  • 掇刀审计局:关注信访资金 创人民满意窗口

  • 近日,荆门市掇刀区审计局在区信访局主要领导经济责任审计中,重点关注信访维稳资金使用管理、阳光信访工作机制流程等情况。图为审计人员现场走访场景审计人员通过查阅资料、比
  • 天23转债:加深一体化布局,组件龙头归来

  • 摘要天合光能本期转债募集资金为88.65亿元,扣除发行费用后主要用于年产35GW直拉单晶项目以及流动资金的补充,本期转债将于3/15上市。加深一体化布局的组件龙头。公司核心产品
  • 可视化搭建 - 组件值校验

  • 组件值校验,即在组件值变化时判断是否满足校验逻辑,若不满足校验逻辑,可以拿到校验错误信息进行错误提示或其他逻辑处理。声明 valueValidator 可开启值校验:import { Component

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 【第2886期】无渲染组件

  • 前言继续昨日【第2885期】精读《Headless 组件用法与原理》的 Headless 组件。今日前端早读课文章由 @Starrier 翻译分享。正文从这开始~~无头用户界面组件是一种不提供任何接
  • 【人社日课】如何查询自己的档案存在哪里?

  • 来源:人力资源社会保障部政务微信推荐阅读●【“三抓三促”行动进行时】甘肃省人社厅组织全省首期职业技能等级认定考评员培训班●权威解读《资格规定》《考试办法》,您关心的
  • 【早说】做空

  • Short-selling is similar to“Getting something for nothing”: when an investor predicts that the price of something is going to fall in the future, he or she ca
  • 从5000万到3亿,一个隐形冠军的两次变革

  • “管理变革中,重要的决策都要遵循‘共商、共创、共建’原则。”好文5510字 | 9分钟阅读作者:刘寅斌 易淼 董佳骅 陈思 温方琪在工业自动化领域,防爆本安自控系统关联设备是一种
  • 这才是领导和下属的最好关系

  • “培养下属,改变不是目的,变好才是。”好文2990字 | 5分钟阅读来源:张丽俊(ID:zhanglijunCherry)作者:张丽俊,创业酵母创始人,酵母咨询创始人。在职场上,领导和下属的关系非常微妙,不是