本文是对翻译文章
“如何使用React + RxJS 6 + Recompose在GitHub上搜索用户”的回应,该文章昨天才教会我们如何一起使用React,RxJS和Recompose。 好吧,我现在建议看看没有这些工具如何实现。

免责声明在许多人看来,这篇文章包含了一些曳引的元素,是匆忙写出来的,而且是在粉丝上写的。
由于这是一篇退货文章,因此我决定以与原始版本相同的逐步格式进行构建。 此外,本文还旨在将原始实现与此处描述的实现进行比较。 因此,它包含大量的参考文献和引文。 让我们开始吧。
本文适用于具有React和RxJS经验的人。 我只是分享我认为对创建这样的UI有用的模板。
本文适用于具有Javascript(ES6),HTML和CSS经验的人。 另外,在我的实现中,我将使用
“消失的” SvelteJS 框架 ,但是它是如此简单,以至于您不需要具有使用它的经验就可以理解代码。
我们正在做同样的事情:

没有类,则使用生命周期或setState。
是的,没有类,可以使用生命周期或setState。 而且也没有React,ReactDOM,RxJS,Recompose。 此外,如果没有componentFromStream,createEventHandler,combinateLatest,map,startWith,setObservableConfig,BehaviorSubject,merge,of,catchError,delay,filter,map,plucple,switchMap,tap和{another bullshit},总之,您就会明白。
准备工作
您只需要在SvelteJS网站上的
REPL示例中即可。 您可以在本地嗅探,从那里下载源代码(带有特征图标的按钮)。
首先,创建一个简单的App.html文件,它将是小部件的根组件,其内容如下:
<input placeholder="GitHub username"> <style> input { font-size: 20px; border: 1px solid black; border-radius: 3px; margin-bottom: 10px; padding: 10px; } </style>
在下文中,我使用原始文章中的样式。 请注意,目前它们在范围内,即 仅适用于此组件,您可以在相关位置安全地使用标签名称。
我将直接在组件中编写样式,这是因为SFC,也因为REPL不支持将CSS / JS / HTML导出到其他文件,尽管使用
Svelte预处理器很容易做到这一点。
重新组合
休息中...
内联组件
...晒日光浴...
构型
...喝咖啡...
重组+ RxJS
...而其他...
地图
...工作。
添加事件处理程序
当然不是真正的处理程序,只是绑定:
<input bind:value=username placeholder="GitHub username">
好吧,我们定义默认的用户名值:
<script> export default { data() { return { username: '' }; } }; </script>
现在,如果您开始在输入字段中输入内容,则用户名值将更改。

鸡蛋和鸡肉问题
没有母鸡,没有鸡蛋,没有其他动物的问题,我们不使用RxJS。
编织在一起
一切都已经反应并建立了联系。 所以我们喝咖啡。
用户组件
该组件将负责显示我们将其姓名转移给他的用户。 它将从App组件接收值并将其转换为AJAX请求。
“哇,哇,放轻松吧”©
对于我们来说,这个组件将是愚蠢的,并且只会根据先前已知的模型显示漂亮的用户卡。 数据可以来自哪里和/或界面要显示在哪个位置都无所谓。
User.html组件将如下所示:
<div class="github-card user-card"> <div class="header User" /> <a class="avatar" href="https://github.com/{login}"> <img src="{avatar_url}&s=80" alt={name}> </a> <div class="content"> <h1>{name || login}</h1> <ul class="status"> <li> <a href="https://github.com/{login}?tab=repositories"> <strong>{public_repos}</strong>Repos </a> </li> <li> <a href="https://gist.github.com/{login}"> <strong>{public_gists}</strong>Gists </a> </li> <li> <a href="https://github.com/{login}/followers"> <strong>{followers}</strong>Followers </a> </li> </ul> </div> </div> <style> </style>
jsx / css
CSS刚刚添加到组件中。 代替JSX,我们在Svelte中嵌入了
HTMLx 。
货柜
容器是用户组件的任何父组件。 在这种情况下,它是应用程序的组件。
去抖时间
如果操作仅覆盖数据模型中的值,则调试文本输入没有任何意义。 因此,在绑定本身中,我们不需要此。
拔
过滤器
地图
连接
让我们回到App.html并导入User组件:
import User from './User.html';
资料要求
GitHub提供了一个用于检索用户信息的API:
为了演示,我们只编写了一个小的api.js文件,该文件将抽象数据的接收并导出相应的函数:
import axios from 'axios'; export function getUserCard(username) { return axios.get(`https://api.github.com/users/${username}`) .then(res => res.data); }
就像这样,我们将此函数导入到App.html中。
现在,我们用一种更特定的语言来表达问题:更改数据模型(用户名)中的一个值时,我们需要更改另一个值。 我们将分别称为用户-从API获取的用户数据。 反应性全是荣耀。
为此,请使用App.html中的以下构造编写一个计算的Svelte属性:
<script> import { getUserCard } from './api.js'; ... export default { ... computed: { user: ({ username }) => username && getUserCard(username) } }; </script>
就是这样,现在当您更改用户名时,将发送一个请求以接收有关此值的数据。 但是,由于活页夹会响应每一个更改,即输入文本字段,因此会有太多的请求,我们将很快超过所有可用的限制。
在原始文章中,此问题由RxJS内置的debounceTime函数解决,该函数防止我们过多地请求数据。 对于我们的实施,您可以使用独立的解决方案,例如
反跳承诺或任何其他合适的解决方案,因为有很多选择。
<script> import debounce from 'debounce-promise'; import { getUserCard } from './api.js'; ... const getUser = debounce(getUserCard, 1000); ... export default { ... computed: { user: ({ username }) => username && getUser(username) } }; </script>
因此,此lib创建传递给它的函数的反跳版本,然后在计算属性中使用它。
switchMap
阿贾克斯
RxJS提供了自己的ajax实现,可与switchMap一起使用!
由于我们不使用RxJS,尤其是不使用switchMap,因此可以使用任何库来使用ajax。
我使用
axios是因为它对我来说很方便,但是您可以使用任何东西,并且不会改变问题的本质。
试一下
首先,我们需要注册User组件以将其用作模板标签,因为导入本身不会将该组件添加到模板上下文中:
<script> import User from './User.html'; ... export default { components: { User } ... }; </script>
尽管看似乱七八糟,但除其他外,这允许为同一组件的实例赋予不同的标记名称,从而使模板在语义上更易于理解。
此外,用户价值不是数据本身,而是对数据的承诺。 因为我们是自由加载者,根本不想做任何工作,所以只喝饼干咖啡。
为了将真实数据传输到用户组件,我们可以使用特殊的设计来处理诺言:
{#await user} {:then user} {#if user} <User {...user} /> {/if} {/await}
在将数据对象传递给用户组件之前,先检查数据对象是否存在是有意义的。 使用Spread运算符可以在创建User组件实例时将对象“拆分”为单独的道具。

缩短工作时间。
错误处理
尝试输入不存在的用户名。
...
我们的应用程序已损坏。
您的可能是肯定的,但我们的绝对不是)))什么也不会发生,尽管事实并非如此。
catchError
添加一个附加块用于拒绝承诺处理:
{#await user} {:then user} {#if user} <User {...user} /> {/if} {:catch error} <Error {...error} /> {/await}
组件错误
<div class="error"> <h2>Oops!</h2> <b>{response.status}: {response.data.message}</b> <p>Please try searching again.</p> </div>
现在我们的用户界面看起来好多了:
而且不要说,最重要的是不要努力。

加载指示器
简而言之,进一步的异端始于各种各样的BehaviorSubjects和其他类似的东西。 我们只添加了一个加载指示器,我们不会挤大象:
{#await user} <h3>Loading...</h3> {:then user} {#if user} <User {...user} /> {/if} {:catch error} <Error {...error} /> {/await}
结果呢
两个微小的无逻辑组件(用户和错误)和一个控制组件(应用程序),其中最复杂的业务逻辑在一行中描述-创建一个计算属性。 无需从头到脚刷任何可观察到的物体,也无需连接+100500不需要的工具。
→
互动演示编写简单明了的代码。 编写更少的代码,这意味着更少的工作和与家人在一起的更多时间。 活着!
一切幸福与健康!
全部:)
菲
如果您已经看过REPL中的示例,那么您可能已经注意到了吐司,并在左下方显示了警告:
已编译,但有1条警告-检查控制台以获取详细信息
如果您不太懒于打开控制台,则会看到以下消息:
未使用的CSS选择器
.user-card .Organization {
背景位置:右上方;
}
Svelte Static Analyzer通知我们未使用某些组件样式。 另外,根据您的请求或默认编译器设置的命令,未使用的样式将从最终的CSS捆绑包中删除,而无需您的参与。
P /秒
阅读
有关Svelte的其他文章 ,并查看俄语电报频道
SvelteJS 。 我们将很高兴见到您!