我的第一个包含 React 和 AWS 的作品集
嗨,dev.to!我创建了我的第一个作品集,并考虑记录这个过程。不过在开始之前,先声明一下:
- 我相信要为工作选择正确的工具,使用 React 进行作品集制作可能看起来有点过度,但我决定使用它主要是因为我想做得更好。
- 出于同样的原因,我选择使用 AWS 来部署它,而不是 Github 或 Netlifly。AWS 简直是庞然大物,我想尽可能多地学习。
呼!好吧,那我们开始吧。哦,这是作品集https://georginagrey.com
有趣的部分
在编写应用程序代码时,我学到了一些我认为值得分享的新技巧。
React 的 Context API
我的作品集是多语言的,为了实现这一点,我使用了React 的 Context,其目的是提供一种“全局”状态,让其他深度嵌套的组件可以访问它,从而避免在层层嵌套中传递props。它就是这样帮助我实现语言切换器的:
提供者
LanguageContext.js上存放着文本翻译,并且创建和导出了上下文。
//LanguageContext.js
export const languages = {
en: {...
},
es: {...
}
}
export const LanguageContext = React.createContext({
langText: languages.en,
toggleLanguage: () => { }
});
App组件是最外层的组件,toggleLanguage函数实际上就是在这里实现的。LanguageContext.Provider组件包装了所有需要使用“全局”状态的子组件。
共享访问状态的函数时要小心,这些函数需要明确绑定到状态,方法是使用super(props)关键字或bind(this)方法,否则深层嵌套的组件执行此函数将引发错误。
// App.js
...
import { LanguageContext, languages } from './LanguageContext';
...
constructor(props) {
super(props);
this.state = {
language: 'en',
langText: languages.en,
toggleLanguage: this.toggleLanguage
}
}
toggleLanguage = () => {...
}
render() {
return (
<div id="app" className={app}>
<LanguageContext.Provider value={this.state}>
<Menu />
<Main />
<Footer />
</LanguageContext.Provider>
</div>
)
}
消费者
由于LanguageContext.Consumer组件的存在,LanguagePicker组件嵌套深度大约为 3 层,这就是可以访问状态的方式。
// LanguagePicker.js
const LanguagePicker = () => (
<LanguageContext.Consumer>
{({ toggleLanguage, language }) => (
<div className={main} onClick={() => toggleLanguage()}>
...
<span>{language}</span>
</div>
)}
</LanguageContext.Consumer>
)
这也可以用 Redux 来实现,但我没用它做其他事情。不过, Context API不应该轻易使用,所以请记住这一点。
交叉口观察器 API
如果某个元素在视口内可见时需要触发某个行为,它就非常有用。我用它来触发一些动画,但最有意义的用例是提升网站的加载时间、首次内容绘制以及降低带宽占用。
<img>
即使组件尚未安装,该标签也会立即渲染其源中的任何内容,因此用户可能会下载可能永远都看不到的图像。首次内容绘制的速度也会有所降低,这也是意料之中的。
这里的技巧是使用占位符,获取原始图像并将其缩小到大约 10x10 像素的比例。只有当IntersectionObserver启动时,我们才会获取原始图像。以下是实现代码片段:
// Proyects.js
componentDidMount() {
this.observe();
}
observe() {
var options = {
threshold: [0.1]
}
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
const image = entry.target;
const src = image.dataset.src;
this.fetchImage(src).then(() => {
image.src = src;
});
}
});
}, options);
const images = document.querySelectorAll('img');
images.forEach(i => observer.observe(i));
}
专业提示:我使用Cloudinary来代替自己缩小图像,当url: 中提供c_scale时,您可以动态转换图像https://res.cloudinary.com/georginagrey/image/upload/c_scale,h_12,w_12/v1532709273/portfolio/portfolio.jpg
,如果您去掉那部分,您将获得原始图像。
注意: IntersectionObserver 并非在所有浏览器中都完全受支持,因此您可能需要使用 pollyfill 或 fallback。
用户界面
这是我最弱的一点,直到最近我才稍微了解了一下 CSS3,或者说我之前一直以为是这样,直到我开始用纯 CSS 给组件添加样式时,各种“陷阱”都让我措手不及。我不得不重写了好几遍,直到我决定使用emotion。虽然css-in-js引起了一些争议,但我还是决定尝试一下,而且我很喜欢它,我再也不用担心在处理不同的组件时会覆盖规则了。
布局非常简单,我采用了移动优先的方法,并且只使用了flexbox。
堆栈
简而言之,这是一个 React 静态网站,托管在由 CloudFront 和 Route53 提供服务的 S3 存储桶上。
- 创建 React 应用
- 情感(css-in-js)
- Firebase(用于联系表单)
- AWS S3 bucket(静态文件托管)
- AWS Cloudfront(CDN、SSL 证书、文本压缩)
- AWS Route53(DNS路由)
我怎么会变成这样?!
在编写了主要的 React 组件并设计了其中大部分的样式之后,我偶然发现了 Google 的Lighthouse审计工具,我下载了 Chrome 扩展程序并生成了一份报告(本地),几秒钟内我就得到了结果和一系列优化机会,例如,通过在服务器中启用“文本压缩”,在我的情况下,应用程序的加载速度应该会提高大约 3 秒。
我不知道那是什么意思,所以在谷歌搜索了一会儿之后,我偶然发现了Cloudfront,最重要的是你可以免费申请 SSL 证书。
设置一切其实并不像听起来那么难,这里有一个非常实用的指南。您将获得什么?托管、更强大的性能、更快的交付速度和安全的 HTTPS。
它是免费的吗?
S3 和 CloudFront本身并不是免费的,而是按需付费服务,因此对于低流量网站,在 1 年免费套餐到期后,我们讨论的是每月支付几美分的费用(如果有的话)。
Route53 是 DNS 提供商,每个托管区域每月固定收费 0.51 美元,所以每年只需 6 美元。在本例中,我已经在 GoDaddy 注册了一个域名,为了使用 Route53,我直接获取了 Route53 提供的 DNS 名称,并将其保存在GoDaddy 的“管理名称服务器”表单中。
缓存和使 CloudFront 失效
正如预期的那样,每次请求进入 CloudFront 时,它都会提供缓存的内容,而不是每次都去 S3 存储桶查找文件,内容保持缓存的时间取决于配置的默认 TTL时间范围,请在此处阅读有关它的更多信息。
由于我仍在维护网站,我将默认 TTL 设置为
3600 秒(1 小时),并cache-control:max-age=0
在源 S3 存储桶的元数据中添加了一个标头 。但我很快会恢复该设置,并使用Invalidation来代替,它会强制刷新缓存,而无需等待缓存过期。这样做实际上也更省钱。
编辑:
我收到月结单了!以下是 AWS Princing 的设置示例:
CloudFront为美洲/欧洲套餐处理了超过 2300 个请求。此外,DNS路由和存储费用总计0.62 美元。由于预计流量不会激增,因此价格不会更高。
就是这样!...我想🤔
这不是我第一次处理 AWS,但这是我第一次编写网站前端代码,因此非常感谢任何评论。
感谢您的光临👋