React是一个基于组件的JavaScript库,其受欢迎程度持续增长。在2021年的一项全球研究中,超过40%的受访开发者表示在使用React。React的广泛使用不应该是一个惊喜。React很灵活,容易学习,并提供了编写自定义组件的能力。这些自定义组件,或单独的UI块,是可重复使用的,可以很容易地在其他React应用程序中共享。
然而,React的一个方面不那么简单,就是将自定义组件集成到静态网站中。在本教程中,我们将演示如何使用部件将React组件与完全由HTML构建的静态网站整合。
打开你最喜欢的文本编辑器,让我们开始吧!
什么是widget?
小组件是一块用户界面,它在内部处理数据逻辑和数据展示,独立于网页上的其他元素。小组件用于将动态内容(如弹出式窗口、图片传送带或动态列表)添加到一个独立的、静态的应用程序。
小工具是不受框架影响的。本教程的重点是React组件的集成,但同样的方法也可以用于你选择的框架中创建的组件。
天气小部件是一个常见的小部件的例子,许多人每天都与之互动。它利用用户的地理位置显示附近地点的当前天气状况。这个小部件处理几个任务,如获得访问用户位置的许可和获取天气数据。
嵌入天气小部件的应用程序或网站不需要关心如何获取数据或如何向用户显示数据。这些任务由小组件来处理。
创建一个小部件
让我们创建一个小部件,它将从Crypto Compare API读取数据,并按市值显示顶级加密货币列表。
首先,我们需要建立一个React项目。
要创建和运行一个React应用程序,系统中必须同时安装Node.js和npm。
打开终端,并运行以下命令。
npx create-react-app ReactWidgetDemo
cd ReactWidgetDemo
在src 文件夹内,创建两个新文件夹:components 和hooks 。我们将创建一个自定义钩子,从Crypto Compare API中获取数据。
在hooks 文件夹内,创建一个新文件:useCryptoData.js 。
import { useEffect, useState } from "react";
const useCryptoData = () => {
const [cryptoData, setCryptoData] = useState([]);
const [isLoading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
// fetch the data and set cryptData
setLoading(false);
}, [])
return { cryptoData, isLoading }
};
在useCryptoData 自定义钩子中,我们采用useState React钩子来创建两个状态变量:cryptoData 和isLoading 。
cryptoData 状态变量将存储来自API的数据。isLoading 状态将显示数据获取是否正在进行中。
现在,我们将使用fetch() 方法从Crypto Compare API中获取数据,然后设置cryptoData 状态。
import { useEffect, useState } from "react";
const useCryptoData = () => {
const [cryptoData, setCryptoData] = useState([]);
const [isLoading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch(
"https://min-api.cryptocompare.com/data/top/mktcapfull?limit=10&tsym=USD"
)
.then((res) => res.json())
.then((data) => {
console.log(data);
const preparedData = [];
data.Data.forEach((d) => {
const { Id, Name, FullName, ImageUrl, Url } = d.CoinInfo;
let Price, Change24hr;
if (d.DISPLAY?.USD) {
const { PRICE, CHANGEPCT24HOUR } = d.DISPLAY.USD;
Price = PRICE;
Change24hr = CHANGEPCT24HOUR;
}
preparedData.push({
Id,
Name,
FullName,
ImageUrl: `https://www.cryptocompare.com${ImageUrl}`,
Url: `https://www.cryptocompare.com${Url}`,
Price,
Change24hr
});
});
setCryptoData(preparedData);
})
.finally(() => setLoading(false));
}, []);
return { cryptoData, isLoading };
};
export default useCryptoData;
components 文件夹将放置主要的小工具组件文件。在CryptoList 组件文件中导入useCryptoData 钩子。
import useCryptoData from "./useCryptoData";
const CryptoItem = (props) => (
<div className="item">
<img src={props.ImageUrl} className="icon" alt={props.Name} />
<div className="display-container">
<div className="name">{props.Name}</div>
<div className="fullname">{props.FullName}</div>
</div>
<div className="price-container">
<div className="price">{props.Price}</div>
<div
className={`price-change ${
parseInt(props.Change24hr) < 0 ? "danger" : "success"
}`}
>
{props.Change24hr}
</div>
</div>
</div>
);
const CryptoList = () => {
const { cryptoData, isLoading } = useCryptoData();
return (
<div>
<div className="container">
{!isLoading ? (
cryptoData.map((itemData) => (
<CryptoItem key={itemData.Id} {...itemData} />
))
) : (
<p className="loading-text">Loading Data...</p>
)}
</div>
</div>
);
};
export default CryptoList;
接下来,在主App() 组件内使用CryptoList 组件。
import CryptoList from "./components/CryptoList";
import "./styles.css";
export default function App() {
return (
<div>
<CryptoList />
</div>
);
}
现在,让我们为该组件添加样式,以改善其外观。
@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@500;600&display=swap");
:root {
--dark: #1e2329;
--light: #fafafa;
--success: #03a66d;
--danger: #cf304a;
}
* {
font-family: "Open Sans", sans-serif;
}
.name,
.loading-text {
color: var(--light);
font-size: 16px;
font-weight: 600;
}
.fullname {
color: #b6b6b6;
font-size: 14px;
margin-top: 3px;
font-weight: 500;
}
.item {
display: flex;
align-items: center;
padding: 12px 0px;
border-bottom: 1px solid #949191;
}
.item:first-child {
padding-top: 0px;
}
.item:last-child {
padding-bottom: 0px;
border-bottom: 0px;
}
.container {
background-color: var(--dark);
padding: 20px;
border-radius: 12px;
box-shadow: rgba(0, 0, 0, 0.1) 0px 10px 30px;
}
.icon {
height: 24px;
width: 24px;
margin-right: 14px;
}
.price-container {
margin-left: auto;
display: flex;
flex-direction: column;
align-items: flex-end;
}
.price {
font-weight: 500;
color: var(--light);
font-size: 16px;
}
.price-change {
margin-top: 3px;
}
.price-change.danger {
color: var(--danger);
}
.price-change.success {
color: var(--success);
}
为了让React应用程序启动和运行,从项目根部使用以下命令。
npm run start
这将建立一个本地开发服务器,并在3000端口运行应用程序。
打开浏览器,进入http://localhost:3000。
转到CodeSandbox,看看演示的CryptoListwidget的运行情况。
使用小组件
现在是时候在一个独立的静态HTML网页中使用演示的CryptoList widget了。我们将使用一个iframe来嵌入widget。
我们将把React应用程序的URL传递给src 属性的<iframe /> 。在这个例子中,URL是http://localhost:3000。
<iframe
src="http://localhost:3000"
style="border: none;"
width="100%"
></iframe>
这里是iframe和widget的代码,与静态网页中的其他元素一起包含。
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
.row {
display: flex;
flex-direction: row;
}
.col {
flex: 1;
}
</style>
<title>Static website</title>
</head>
<body style="min-height: 100vh">
<div class="row">
<div class="col">
<div>Excepteur sint occaecat cupidatat non proident.</div>
<iframe
src="http://localhost:3000"
style="border: none; min-height: 98vh"
width="100%"
></iframe>
</div>
<div class="col">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
</body>
</html>
这里是嵌入HTML网页中的演示CryptoList widget。
在React应用程序之间共享组件
根据项目的情况,可能有必要在React应用之间共享widget,而不是将它们整合到静态网站中。为了给React应用创建可共享的部件,我们可以创建一个通用的部件库并在npm上发布。本指南包含关于如何为React创建npm包的详细说明。
或者,我们可以从仓库导入软件包。
npm i https://github.com/{username}/{repo}.git
我们可以在不同的React项目中安装该包,并在我们的JSX文件中导入该组件。通过这种方法,小部件可以被单独维护。每当小部件的功能或风格更新时,这将反映在React项目中,只需更新npm包即可。
结论
在React中制作可共享的widget是非常容易的。在本教程中,我们演示了如何使用React建立一个简单的小工具,然后将其与静态HTML网页集成。
作为一个开发者,了解使用iframe嵌入widget的利弊很重要。这可能不是每个用例的首选方案。对于涉及大量嵌入式部件的项目,考虑迁移到Gatsby或其他React的静态网站生成器。
要了解更多关于React的信息,请看它的网站或MDN上的React资源。
The postCreating shareable React widgetsappeared first onLogRocket Blog.