> For the complete documentation index, see [llms.txt](https://xiaohesong.gitbook.io/today-i-learn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://xiaohesong.gitbook.io/today-i-learn/front-end/react-1/overreact/ui-element-problem-and-build-yourself.md).

# ui-element-problem-and-build-yourself

在[上一篇文章中](https://github.com/xiaohesong/TIL/blob/master/front-end/react/overreact/things-i-dont-known-as-2018.md), 我谈论了我的知识的不足。你可能会得出结论，我建议你解决平常的问题。我没有！这是一个广阔的领域。

我坚信你可以“从任何地方开始”，不需要以任何特定的顺序学习技术。但我也非常重视获得专业知识。就个人而言，我最感兴趣的是创建用户界面。

**我一直在考虑我所知道的并且认为有价值的东西。** 当然，我熟悉一些技术（例如JavaScript和React）。但是经验中更重要的教训是难以记住的。我从来没试过把它们说出来。这是我第一次尝试编目和描述其中一些。

有很多关于技术和库的“学习路线图”。哪个库将在2019年流行？2020年呢？你应该学习Vue还是React?Angular?Redux或者Rx怎么样？你需要去学习Apollo？REST或GraphQL？很容易迷茫，如果作者说错了怎么办？

**我学习最大的突破点不是关于某项技术。** 相反，当我努力解决特定的UI问题时，我学到的最多。有时候，我会发现对我有帮助的库或模式。在其他情况下，我会提出自己的解决方案（好的和坏的）。

这是对问题的理解，实验解决方案以及应用不同策略的结合，这些策略在我的生活中带来了最有价值的学习体验。**这篇文章只关注问题。**

如果做用户界面，那么可能直接解决一些问题或者使用库来处理其中一些挑战。在这种情况下，我都鼓励你创建一个没有库的小应用程序，并重现他，解决这些问题。任何一个都没有一个正确的方案。学习来自探索问题的空间并尝试不同的可能之间的权衡。

* **一致性(Consistency)** 你点击“赞”按钮，文字更新：“你和其他3个朋友都喜欢这篇文章。” 你再次点击他，文本会翻转回去。听起来很容易。但是也许这样的`label`存在于屏幕上的几个地方。也许还有一些其他的可见的改变（例如按钮背景）。之前从服务器获取并在悬停时可见的“喜欢者”列表现在应包含您的姓名。如果你去了其他的地方再返回当前页面，应该保持着喜欢的状态。即使是局部的一致性，也会带来挑战。但是其他用户也可能修改我们显示的数据（例如，通过喜欢我们正在查看的帖子）。我们如何在屏幕不同的部分保持同步的数据继续同步？我们如何以及何时使本地数据与服务器保持一致，反之亦然？
* **响应(Responsiveness)** 人们只能在有限的时间内容忍没有内容展示的反馈。对于手势和滚动等连续动作，此限制很低。（即使跳过一个16ms的帧也感觉“很笨拙”）。对于像点击这样的*离散*行为，有研究称用户认为任何<100毫秒的延迟就很快。如果操作需要更长时间，我们需要显示一个可视指示器。但是有一些反直觉的挑战。导致页面布局“跳转”或经过多个加载“阶段”的指示符会让操作感觉比以前更长。类似地，以丢弃动画帧为代价在20ms内处理交互可能比在30ms内处理它并没有丢帧的情况下更慢。大脑不是基准。我们如何让我们的应用程序响应不同类型的输入？
* **潜在Latency)** 计算和网络访问都需要时间。有时我们可以忽略计算成本，如果它不会损害我们目标设备的响应能力（确保在低端设备频谱上测试应用程序）。但处理网络延迟是不可避免的 - 它可能需要几秒钟！我们的应用程序不能只是冻结等待数据或代码加载。这意味着任何依赖于新数据，代码或资产(assets)的操作都可能是异步的，需要处理“加载”情况。但几乎每个屏幕都会发生这种情况。我们如何优雅地处理延迟而不显示旋转器的“级联”或空“洞”？我们如何避免布局跳转？我们如何在不每次“重写”代码的情况下更改异步依赖关系？
* **Navigation** 我们希望在我们与之交互时UI保持“稳定”。事情不应该在我们的眼皮底下消失。无论是在应用内启动（例如点击链接）还是由于外部事件（例如点击“后退”按钮），导航也应该遵循这一原则。例如，在配置文件屏幕上切换`/profile/likes`和`/profile/follows`的选项卡不应该清除选项卡视图外的搜索输入。甚至导航到另一个屏幕就像走进一个房间。人们希望以后能够回去找到他们离开时的东西（也许还有一些新东西）。如果你处于Feed中间，请点击个人资料，然后返回，在Feed中失去你的位置会令人沮丧 - 或者等待它再次加载。我们如何构建我们的应用来处理任意导航而不会丢失重要的上下文？
* **Staleness** 我们可以通过引入本地缓存使“后退”按钮导航即时。在那个缓存中，我们可以“记住”一些数据以便快速访问，即使我们理论上可以重新获取它。但缓存带来了自己的问题。缓存可能会变得陈旧。如果我更改了头像，它也应该在缓存中更新。如果我发布新帖子，则需要立即显示在缓存中，否则缓存需要失效。这可能变得困难且容易出错。如果发布失败怎么办？缓存在内存中保留多长时间？当我们重新获取Feed时，我们是否使用缓存的“拼接”新提取的Feed，或者将缓存丢弃？缓存中如何表示分页或排序？
* **Entropy** 热力学第二定律说“随着时间的推移，事情变得一团糟”（好吧，不完全是这样）。这也适用于用户界面。我们无法预测确切的用户互动及其顺序。在任何时候，我们的应用程序可能处于一个令人难以置信的可能状态之一。我们尽最大努力使结果可预测并受到我们设计的限制。我们不想查看错误截图，并惊疑“这是怎么发生的”。对于N种可能状态，它们之间存在N×（N-1）个可能的转换。例如，如果一个按钮可以处于5种不同状态（正常，活动，悬停，危险，禁用）中的一种状态，则更新按钮的代码必须正确，以便进行5×4 = 20次可能的转换 - 或禁止其中一些转换。我们如何驯服可能状态的组合爆炸并使视觉输出可预测？
* **Priority** 有些事情比其他事情更重要。对话框可能需要物理地“出现”在产生它的按钮上方并“突破”其容器的剪辑边界。新计划的任务（例如，响应点击）可能比已经开始的长期任务（例如，在屏幕折叠下方呈现下一个帖子）更重要。随着我们的应用程序的增长，由不同的人和团队编写的部分代码竞争有限的资源，如处理器，网络，屏幕区域和捆绑大小预算。有时你可以在共同的“重要性”范围内对竞争者进行排名，比如CSS `z-index`属性。[但他很少会结束](https://blogs.msdn.microsoft.com/oldnewthing/20050607-00/?p=35413)。每个开发人员都偏向于认为他们的代码很重要。如果一切都很重要，那就没有不是的了！我们如何获得独立的小部件来合作而不是争取资源？
* **Accessibility** 无法访问的网站不是一个利基问题。例如，在英国，残疾影响了五分之一的人。 [(这是一个不错的信息图)](https://www.abrightclearweb.com/web-accessibility-in-the-uk/)。我也亲自感受到了这一点。虽然我只有26岁，但我很难阅读细字体和低对比度的网站。我尝试使用触控板的次数较少，而且我害怕有一天我必须通过键盘导航不良的网站。我们需要让我们的应用程序对于有困难的人来说并不可怕 - 而且好消息是有很多低调的成果。它始于教育和工具。但我们还需要让产品开发人员轻松做正确的事情。我们可以做些什么来使可访问性成为默认值而不是事后的想法？
* **Internationalization** 我们的应用程序需要在世界各地工作。人们不仅会讲不同的语言，而且还需要从产品工程师那里以最少的努力支持从右到左的布局。我们如何在不牺牲延迟和响应能力的情况下支持不同的语言？
* **Delivery** 我们需要将应用程序代码提供给用户的计算机。我们使用什么样的传输和格式？这可能听起来很简单，但这里有许多需要权衡。例如，原生应用程序倾向于以巨大的应用程序大小为代价提前加载所有代码。Web应用程序往往具有较小的初始有效负载，但代价是使用期间的延迟更长。我们如何选择引入延迟的时间点？我们如何根据使用模式优化交付？我们需要什么样的数据才能获得最佳解决方案？
* **Resilience** 如果你是昆虫学家，你可能会喜欢bugs，但你可能不喜欢在你的程序中看到它们。但是，你的一些bug将不可避免地进入生产阶段。那么会发生什么？一些错误会导致错误但定义明确的行为。例如，在某些情况下，代码可能会显示不正确的视觉输出。但是如果渲染代码崩溃了怎么办？然后我们无法继续，因为视觉输出会不一致。渲染单个帖子的崩溃不应该“降低”整个Feed或使其进入半破碎状态，从而导致进一步崩溃。我们如何以隔离渲染和获取失败的方式编写代码并保持应用程序的其余部分运行？容错对用户界面意味着什么?
* **Abstraction** 在一个小应用程序中，我们可以对许多特殊情况进行硬编码以解决上述问题。但应用程序往往会增长。我们希望能够[重用, fork, 连接部分代码](https://overreacted.io/optimized-for-change/)，并集体处理它们。我们希望在不同人熟悉的部分之间定义明确的界限，并避免使经常变化的逻辑过于僵化。我们如何创建隐藏特定UI部分的实现细节的抽象？我们如何避免重新引入我们应用程序增长时遇到的相同问题？

当然，我还没有提到很多问题。这份清单并非详尽无遗！例如，我没有谈到设计师和工程协作，或调试和测试。也许下一次。

作为解决方案，将特定视图库或数据提取库作为解决方案来阅读这些问题很诱人。我鼓励你假装这些库不存在，并从那个角度再次阅读。你将如何解决这些问题？给他们一个小应用程序的尝试！ （我很想在GitHub上看到你的实验 - 随时给我发推文回复。）

些问题的有趣之处在于它们大多数都出现在任何规模上。你可以在小型小部件中看到它们，比如打字或工具提示，以及Twitter和Facebook等大型应用程序。

**想想您喜欢使用的应用程序中的非平凡UI元素，并查看此问题列表。你能描述一下开发商选择的一些权衡吗？尝试从头开始重建类似的行为！**

通过在小型应用程序中试验这些问题而不使用库，我学到了很多关于UI工程的知识。我建议任何想要深入了解UI工程权衡的人。
