React是一个流行的前端JavaScript开发库。根据State Of JS 2021调查,它在认知度和使用率方面排名第一。
这意味着大多数的JavaScript开发人员可能知道或使用React。
尽管React在构建网络应用程序用户界面(UI)方面很受欢迎,但你也可以将React核心库用于其他方面。事实上,这个 [react-dom](https://reactjs.org/docs/react-dom.html)
库是在网页上渲染用户界面的东西,而不是React本身。React更像是一个引擎,可以被移植到任何环境。
开发者喜欢React的一个原因是它构建用户界面的方法。你只需要描述界面应该是什么样子的,React引擎就会负责放置和页面上的任何变化。
有一些库使用React来帮助开发者创建除网络应用之外的其他类型的应用程序,它们包括:
- React 360:用于构建3D虚拟现实应用
- React Desktop:用于构建桌面应用
- React Native:用于构建移动应用程序
- 墨水:构建命令行应用程序
在本教程中,我们将探讨命令行界面。我们还将建立一个应用程序,显示一些选定的加密货币和代币的实时价格。为了帮助获得代币的价格,我们将使用CoinGecko的API。
项目的工作版本可以在GitHub上找到。
注意:本文假设你能使用React来构建基本的前端网络应用。如果没有,这里有一个关于React JS的免费CodeCamp课程。本文还假设你能使用REST APIs,并且知道命令行上的基本命令,因为这些在本文中没有涉及。
好了,让我们开始吧。
什么是命令行界面? (CLI)
命令行界面是一种你可以通过文本与计算机互动的方式。它通过你在命令提示符中输入特殊命令来工作:
Windows操作系统中的命令行界面
在图形用户界面(GUI)产生之前,这是开发人员与计算机互动的方式。命令行界面在自动化任务和一般的软件开发中仍然很有用。
什么是Ink?
Ink是一个将React带到命令行的JavaScript库。它有助于使用基于组件的UI元素的概念开发CLI应用程序。
Ink允许你使用React的所有功能,包括基于类的组件、生命周期方法、功能组件、钩子,等等,用于构建命令行工具。
ink
库也有称为有用组件的插件。这些有用的组件并没有内置到ink
库中,而是由其他开发者构建的自定义组件,你可以将其导入到Ink项目中。
如何安装Ink
有两种安装Ink的方法它们是
- 用Babel手动安装Ink
- 使用
create-ink-app
命令
在这篇文章中,我们将使用create-ink-app
方法来快速启动一个Ink项目。
在命令行中,导航到你想放置Ink项目的文件夹或目录,然后运行下面的命令:
npx create-ink-app crypto-cli
安装Ink
这个命令在我们运行命令的文件夹内安装建立Ink项目所需的文件。在我们的例子中,文件夹和项目的名称是一样的(crypto-cli
)。
create-ink-app
还为我们的项目生成了一个可执行的命令,这样我们就可以通过在CLI上调用它的名字来运行我们的应用程序。
就这样,Ink 3(截至本文时,这是Ink的最新版本)已经安装完毕,我们准备开始构建命令行应用程序。
当我们运行crypto-cli
命令时,我们得到这样的输出。
运行的输出crypto-cli
为什么我们会有这样的输出?让我们探讨一下create-ink-app
安装的文件。
检查Ink安装的文件
项目的文件结构看起来像这样:
文件和文件夹create-ink-app提供
这些文件和文件夹是做什么的?
node_modules
:这个文件夹存放着我们的应用程序正常运行所需的所有软件包。这些包包括react
和ink
,但也包括react
和ink
的依赖项(如果有的话)。node-modules
也包括ink
的创建者认为会提供良好的开发者体验的包。.editor-config
: 这个文件有助于保持代码的一致性。很多开发者可能在这个项目上使用不同的IDE工作。为了确保编码风格一致,你可以使用.editor-config
。你可以在这里找到更多关于它的信息。.gitattributes
编写文件:我们将用它来配置我们的文件的属性,这些属性将被版本控制程序Git使用。你可以在这里找到更多信息。对于这个项目,我们不需要在这个文件中添加或删除任何东西。cli.js
: 在这个文件中,我们将使用ink
来渲染我们的应用程序。package-lock.json
: 我们用它来锁定我们应用程序的依赖关系到一个特定的版本,这样别人就可以随时随地轻松地复制我们的项目。package.json
文件:包含我们应用程序的元数据,包括名称、版本和依赖性。readme.md
: 为我们的项目提供一个标记性的readme文件。test.js
: 用于在我们的应用程序中编写测试。我们将不会在我们的项目中编辑这个文件。ui.js
React文件:这是用React进行前端Web开发的同义词App.js
。它导入并包含了我们项目将拥有的每一个组件。
看看package.json
,就会发现我们所安装的依赖性:
...,
"dependencies": {
"import-jsx": "^4.0.1",
"ink": "^3.2.0",
"meow": "^9.0.0",
"react": "^17.0.2"
},
...
我们项目的依赖性
你可能不熟悉import-jsx
和meow
。让我们来看看它们的作用。
import-jsx
:你使用这个库来导入和转译JSX文件,在ink
。meow
:CLI命令接受参数。meow
帮助我们在ink
中实现。
说得够多了,让我们开始构建。
如何构建CLI应用程序
在本教程中,正如我前面提到的,我们将建立一个应用程序,使用CoinGecko API显示一些加密货币和代币的价格。
如何创建页眉
我们将导入一个名为ink-big-text
的npm包。它是Ink提供的 "有用组件 "之一。我们将使用它在命令行中创建一个大头。
我们还将安装ink-gradient
来美化我们的页眉。它是Ink提供的另一个 "有用的组件"。
npm install ink-big-text ink-gradient
然后我们将编辑我们的ui.js
,它同样必须包含我们所有的组件:
// ui.js
const React = require('react');
const Gradient = require('ink-gradient');
const BigText = require('ink-big-text');
const App = () => (
<Gradient name="summer">
<BigText text="crypto cli" align='center' font='chrome'/>
</Gradient>
);
module.exports = App;
而当我们运行crypto-cli
,代码就会转化为这个美妙的页眉:
页眉的输出
如何显示我们的数据
为了显示我们的数据,我们需要创建一个Box
元素,将其排列成表格形式。Box
的工作方式就像网页上的display: flex;
的容器。你可以像Flexbox元素一样对它进行样式设计。
在从CoinGecko提取数据之前,我们暂时先创建模拟数据。src
内的一个文件data.json
将容纳我们的模拟数据。你可以在这里找到模拟数据。
接下来,我们将在src
文件夹内创建一个名为components
的文件夹。 我们还将在components
文件夹中创建一个名为Table.js
的文件。
然后,以下代码将进入Table.js
:
// Table.js
const React = require('react');
const { useState, useEffect } = React;
// Destructuring useState and useEffect from React
const { Box, Text, Newline } = require('ink');
// Destructuring the components we need from ink
const cryptoData = require('../data.json');
// Fetching mock data
const Table = () => {
const [data, setData] = useState([]);
useEffect(()=>{
setData(cryptoData);
});
return (
<Box borderStyle='single' padding={2} flexDirection='column'>
<Box>
<Box width='25%'><Text>COIN</Text></Box>
<Box width='25%'><Text>PRICE (USD)</Text></Box>
<Box width='25%'><Text>24 HOUR CHANGE</Text></Box>
<Box width='25%'><Text>ALL TIME HIGH</Text></Box>
</Box>
<Newline/>
{
data.map(({id, name, current_price, price_change_percentage_24h, ath}) => (
<Box key={id}>
<Box width='25%'><Text>{name}</Text></Box>
<Box width='25%'><Text>{current_price}</Text></Box>
<Box width='25%'><Text>{price_change_percentage_24h}</Text></Box>
<Box width='25%'><Text>{ath}</Text></Box>
</Box>
))
}
</Box>
)
}
module.exports = Table;
现在,我们将继续前进并将表组件导入我们的应用程序:
// ui.js
const React = require('react');
const Gradient = require('ink-gradient');
const BigText = require('ink-big-text');
const importJsx = require('import-jsx');
const Table = importJsx('./components/Table')
const App = () => (
<>
<Gradient name="summer">
<BigText
text="crypto cli"
align='center'
font='chrome'
/>
</Gradient>
<Table/>
</>
);
module.exports = App;
(perhaps, remove the 'use strict')
运行crypto-cli
,我们会得到这个结果:
使用模拟数据的输出
我喜欢在我的CLI应用程序中进行一些装饰。所以我们将继续使用ink
为我们提供的颜色:
// Table.js
const React = require('react');
const { useState, useEffect } = React;
const { Box, Text, Newline } = require('ink');
const cryptoData = require('../data.json');
const Table = () => {
const [data, setData] = useState([]);
useEffect(()=>{
setData(cryptoData);
})
return (
<Box borderStyle='single' padding={2} flexDirection='column'>
<Box>
<Box width='25%'><Text>COIN</Text></Box>
<Box width='25%'><Text>CURRENT PRICE (USD)</Text></Box>
<Box width='25%'><Text>24 HOUR CHANGE</Text></Box>
<Box width='25%'><Text>ALL TIME HIGH</Text></Box>
</Box>
<Newline/>
{
data.map(({id, name, current_price, price_change_percentage_24h, ath}) => (
<Box key={id}>
<Box width='25%'>
<Text>{name}</Text>
</Box>
<Box width='25%'>
<Text color='cyan'>{'$' + current_price.toLocaleString()}</Text>
</Box>
<Box width='25%'>
<Text backgroundColor={Math.sign(price_change_percentage_24h) < 0 ? 'red' : 'green'}>
{price_change_percentage_24h.toFixed(2) + '%'}
</Text>
</Box>
<Box width='25%'>
<Text color='green'>{'$' + ath.toLocaleString()}</Text>
</Box>
</Box>
))
}
</Box>
)
}
module.exports = Table;
要清楚的是,为了给ink
中的文本组件添加颜色,我们使用了道具(属性)color
。为了添加背景色,我们使用了属性backgroundColor
。然后我们添加了逻辑,检查24小时的变化是负的还是正的。
如果变化是正的,我们确保背景色是绿色,否则背景色将是红色。
当我们运行crypto-cli
,我们有以下输出:
添加样式后的输出
而手动否定data.json
中第二个24 HOUR CHANGE
的值,会产生以下输出:
否定一个值后的输出
如何从CoinGecko API中获取数据
这个阶段是我们从CoinGecko API获取实际数据的地方。以下是我们需要采取的步骤:
CoinGecko API页面
- 导航到 "硬币 "部分并点击
/coins/markets
导航到/coins/markets
- 点击 "试一试 "按钮。
- 输入 "USD "作为
vs_currency
。同时输入你喜欢的加密货币和代币的id
(我使用了比特币、莱特币、Matic-network、以太坊、Tether、Binancecoin、Solana、Aave、Cardano和TRON)。记住,在输入币种ID的时候不要加空格。
输入表格值
- 点击执行按钮
- 复制出它生成的链接。对我来说,这是我将用来进行API调用的链接。该链接取决于你选择的加密货币或代币。
复制突出显示的链接
https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=bitcoin%2Clitecoin%2Cmatic-network%2Cethereum%2Ctether%2Cbinancecoin%2Csolana%2Caave%2Ccardano%2Ctron&order=market_cap_desc&per_page=100&page=1&sparkline=false
我们现在将移动到我们的Table.js
,进行API调用。
安装 [axios](https://github.com/axios/axios)
这是一个对获取API数据有用的npm库。
npm install axios
然后,使用axios
,我们获取我们的数据:
const React = require('react')
const { useState, useEffect } = React;
const { Box, Text, Newline } = require('ink')
const axios = require('axios')
const url = 'https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=bitcoin%2Clitecoin%2Cmatic-network%2Cethereum%2Ctether%2Cbinancecoin%2Csolana%2Caave%2Ccardano%2Ctron&order=market_cap_desc&per_page=100&page=1&sparkline=false'
const Table = () => {
const [data, setData] = useState([])
useEffect(()=>{
axios.get(url)
.then(response => setData(response.data))
.catch(e => console.log(e))
},[])
// Fetching data and catching possible errors
return (
<Box borderStyle='single' padding={2}>
{
data.length === 0 ?
<Box>
<Text>Loading ...</Text>
</Box> :
<Box flexDirection='column'>
<Box>
<Box width='25%'><Text>COIN</Text></Box>
<Box width='25%'><Text>CURRENT PRICE (USD)</Text></Box>
<Box width='25%'><Text>24 HOUR CHANGE</Text></Box>
<Box width='25%'><Text>ALL TIME HIGH</Text></Box>
</Box>
<Newline/>
{
data.map(({id, name, current_price, price_change_percentage_24h, ath}) => (
<Box key={id}>
<Box width='25%'>
<Text>{name}</Text>
</Box>
<Box width='25%'>
<Text color='cyan'>{'$' + current_price.toLocaleString()}</Text>
</Box>
<Box width='25%'>
<Text backgroundColor={Math.sign(price_change_percentage_24h) < 0 ? 'red' : 'green'}>
{price_change_percentage_24h.toFixed(2) + '%'}
</Text>
</Box>
<Box width='25%'>
<Text color='green'>{'$' + ath.toLocaleString()}</Text>
</Box>
</Box>
))
}
</Box>
}
</Box>
)
}
module.exports = Table;
而对于我们选择的硬币,我们应该看到下面的输出(由于加密货币市场的波动性,很可能有不同的值):
最终输出
总结
在本教程中,我们学习了如何用React和Ink建立一个命令行应用程序。
我们还使用了CoinGecko API和Axios来获取我们的数据。
Ink提供了更多的组件,你可以以多种方式组合它,以创建真正有用的命令行程序。
谢谢你的阅读,我很快就会看到你。