- 学习 React Error Boundaries
- 纯 New 向:GitHub 为免费用户提供私有仓库
- 数据盘点之 2019 年要学点什么
- [email protected] 支持 React Hooks
- React.lazy 实践
学习 React Error Boundaries
React.lazy + Suspense 可以检测到组件树中的所有懒加载的组件,并根据其加载状态调用 fallback。其中的实现原理与 React Error Boundaries 是类似的,而 React Error Boundaries 的实现原理又与 try-catch 类似。今天就对 React Error Boundaries 进行一些简单的学习。
Error Boundaries 的作用
React 16 引入了「错误边界」的概念,用于将部分 UI 的异常捕获(渲染期间、生命周期方法内、整个组件树构造函数内)并执行回退的版本,而不是「破坏」了整个应用。听上去,和 try-catch 确实很相近!
当我们在类组件内定义名为 componentDidCatch(error, info)
的方法,则该组件成为一个「错误边界」,示例代码如下(React 文档):
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
// Display fallback UI
this.setState({ hasError: true });
// You can also log the error to an error reporting service
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
然后包住其他组件来使用:
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
这样一来,如果 MyWidget 存在 UI 异常,这一块就会被替换成 <h1>Something went wrong.</h1>
。如果没使用「错误边界」对其进行捕获,根据 React 16 目前的设计,任何未被错误边界捕获的错误将会卸载整个 React 组件树。
如果你有看过上一篇讲 React.lazy 的文章,可能会发现上面的代码和使用动态 import 的那段示例代码出奇的类似:
const LoadDescription = () => import('./Description');
class App extends React.Component {
state = {
Description: null,
};
componentDidMount() {
LoadDescription.then(Description => {
this.setState({ Description: Description.default });
});
}
render() {
const { Description } = this.state;
return (
<div>
<h1>My Movie</h1>
{Description ? <Description /> : 'Loading...'}
</div>
);
}
}
他们都是利用生命周期钩子来修改一个 flag,并根据 flag 来决定渲染的内容。只不过,React.lazy 将这块模板代码抹去了,使用起来非常整洁。
「错误边界」的使用主要针对的是「声明式」的 UI,而不是「命令式」的代码。如果是我们通常的代码,那么还是应该使用 try-catch 来做。
此外需要补充的是,「错误边界」是无法捕获事件处理器内部错误的,如果需要对这类问题进行处理,也同样需要使用 try-catch。
纯 New 向:GitHub 为免费用户提供私有仓库
GitHub 一直以来都限制免费用户创建私有存储库,除非你是氪金玩家。这也从某种程度上使得只想存放代码的开发者对泄露问题产生担忧。
如今,一切都发生了变化,GitHub 宣布为用户提供不限量的私有仓库。当然,这其中也存在一部分约束:
免费用户的私有仓库限制最多三个共同开发者。因此,小型项目自然是 OK 的,比如团队搞搞拉练之类的,但是商业使用并不合适。
这一举动可能是 GitHub 故意通过这种低风险的方式,利用新推出的免费支持,来减少一些已有的付费用户。
在此之前,如果不想掏钱就想创建私有 gi t存储库的话,一些开发人员被迫使用了 GitHub 竞争对手的服务 - 最常见的是 BitBucket。显然,今天的新闻可能对其他代码共享平台来说并不是好消息,但它确实意味着开发者们不再被迫为他们的私人和公共项目使用两套代码管理服务了。
不过有趣的是,GitHub 的文化是展示自我与分享,那么这种广泛提供的私有仓库又该如何解释呢?没有免费的私人存储库本质上意味着人们不得不放出半成品的代码,如今,人们可以在最后才把已经整理干净的完成品放出来,这会伤害 GitHub 的开放和坦诚的文化吗?
源地址:
https://thenextweb.com/dd/201...
https://twitter.com/github/st...
数据盘点之 2019 年要学点什么
又到了新的一年,作为一个学不动的前端工程师,依旧要勇敢的思考今年再学点什么,以迎接每次可能的提问:你有没有了解过 ___(任意填充)___?这里,我们将围绕与面试有关的内容,结合数据给出分析,看一看趋势。
框架
我们这里只针对三板斧进行分析:React、Angular、Vue 进行分析,因为通常的工作场景里还是这三个的应用更为广泛。在今年,React 的用户仍坚定的拥护着 React —— 毕竟没有什么有说服力的理由去换别的,因此 React 在 2018 年仍引领着前端界。Vue 并没有 超越 Angular,但是这三家都仍然呈指数成长,一年又一年。
预测:React 仍会在 2019 年延续优势
如果你看过 state of js 2018,应该还会记得 React 有这个非常高的用户满意率,并且丝毫没有受到其他挑战者影响的感觉。2019 年目测也不会有什么动摇它的框架出现,除非出现了什么特别牛逼的东西异军突起。
当然,React 本身还是在不断发展的,例如新的 React hooks API 可以代替一部分自 React 0.14 就出现的 class 模式。此外,React 一些 API 的进步,如针对 code splitting、concurrent render 的更好地支持,都会让它在 2019 年难以被撼动地位。
作者真的狂吹 React。
数据源
我们将从 3 个数据源来对度量工业界当下的兴趣和使用状况:
- 谷歌搜索 trends
- 包下载量
- Indeed.com 上的求职版
注意,求职数据可能与国内有出入,毕竟国人不咋用这个。
谷歌搜索 trends
可以看到,在 2018 年之前,还是 Angular 的搜索更多,但 2018 年 React 迎头赶上,并在年末维持着优势。Vue 在图上大致是可见的状态,不过目前仍然是占据较低的比例。作为对比,下面是去年的统计图:
可以看到,Angular 是辉煌过。
包下载量
包下载量可以更为清晰的展示出他们的实际使用。下面是三个框架从 2014 年至 2018 年的情况:
React 月下载量 2014 -- 2018:
Angular 月下载量 2014 -- 2018:
Vue 月下载量 2014 -- 2018:
可以看出,这三者都仍然处于成长的状态。
Indeed.com
下图是今年招聘要求上提及的几个技术栈的统计对比:
- React: 24,640
- Angular: 19,032
- jQuery: 14,272
- Vue: 2,816
- Ember (not pictured): 2,397
jQuery 和 Ember 并没有增加太多,但其他三个仍然在增加,也算是某种程度的下滑了。下图是去年的统计,可以看出,jQuery 的排名依据被 Angular 超过了:
其他 JavaScript 生态
关于 TypeScript
作者在这里明确表示 TypeScript 被过誉(overrated)了。在他看来,TypeScript 并没有显著减少生产 bug 的密度,而且还总是报一些并不是错误的错误。
其他建议学习的内容
- GraphQL
- Redux
- redux-saga
- react-feature-toggles
- RITEway,更易读的单元测试
其他兴起的技术
- 区块链
- AI / Machine Learning
- PWA
- AR / VR / MR
- 机器人、无人机、自动驾驶
- 量子计算
源地址:https://medium.com/javascript...
[email protected] 支持 React Hooks
[email protected] 和 [email protected] 已经发布,想要尝鲜用下有 Hooks 的最新 build 的同学可以试试看了。Dan 他们刚休假回来,后续将会专注于将支持 Hooks 的稳定版的研发。
Dan 表示,在稳定版发布之前,会期望做好这些内容:useEffect 的 lint 规则、支持 Hooks 的 DevTools、更好的警告提示、更整洁的测试 effects 的方法等等。
不过,这并不意味着 16.8.0 会包含 Hooks,这只说明 16.8.0-alpha.0 支持,真正的 release 还需要等一些版本。
源地址:https://twitter.com/dan_abram...
React.lazy 实践
React.lazy 的使用方法与优点已经在前面的几期每日一瞥有所提及,本期将结合一篇博客来讲讲具体项目中我们应该如何使用。
从基本场景开始
好的,我们先准备一个 Demo,基于这个例子往下延展:
const Lazycomponent1 = React.lazy(()=>import('./lazy.component1.js'))
const Lazycomponent2 = React.lazy(()=>import('./lazy.component2.js'))
const Lazycomponent3 = React.lazy(()=>import('./lazy.component3.js'))
const Lazycomponent4 = React.lazy(()=>import('./lazy.component4.js'))
function AppComponent() {
return
(<div>
<Suspense fallback={<div>loading ...</div>}>
<LazyComponent1 />
<LazyComponent2 />
<LazyComponent3 />
<LazyComponent4 />
</Suspense>
</div>)
}
上面的代码引入了多个 lazy load 的组件,并指定同一个 Suspense fallback 来处理 loading 状态。注意,上述 Demo 中,要等到每一个 lazy load 的组件都加载好后才会正常渲染,在此之前会渲染出一个 <div>loading ...</div>
。
Catching Loading Errors
还记得前面讲过的 Error Boundary 吗?如果我们想设计的更健壮一些,比如为网络请求失败、找不到文件或文件路径错误等问题提供一个兜底方案,我们就可以考虑下 Error Boundary,这样即使失败我们也能够以更优雅的姿势失败。方案如下:
const Lazycomponent1 = React.lazy(()=>import('./lazy.component1.js'))
const Lazycomponent2 = React.lazy(()=>import('./lazy.component2.js'))
const Lazycomponent3 = React.lazy(()=>import('./lazy.component3.js'))
const Lazycomponent4 = React.lazy(()=>import('./lazy.component4.js'))
import ErrorBoundary from './error.boundary.js'
function AppComponent() {
return
(<div>
<ErrorBoundary>
<Suspense fallback={<div>loading ...</div>}>
<LazyComponent1 />
<LazyComponent2 />
<LazyComponent3 />
<LazyComponent4 />
</Suspense>
<ErrorBoundary/>
</div>)
}
<ErrorBoundary />
要如何实现,前面一期每日一瞥已经有所涉及,也可以查阅文档。总之可以看到,使用时包一层即可。
基于路由的 code splitting
接下来要到重点了。一般来说,split 的方式有基于路由的方法和基于组件的方法。我们先来看基于路由的方法。
改造之前,我们来看下在一个 SPA 项目里,我们都是如何组织各个路由的:
// index,js
// ...
const App = () =>
(<Switch>
<Route path='/about' component={About} />
<Route path='/faq' component = {FAQ} />
<Route path='/careers' component = {Careers} />
</Switch>)
那么引入 React.lazy,只需要如下改写:
// index,js
// ...
const LazyAbout = React.lazy(()=>import('./About.js'))
const LazyFAQ = React.lazy(()=>import('./FAQ.js'))
const LazyCareers = React.lazy(()=>import('./Careers.js'))
const App = () =>
(<Switch>
<Route path='/about' component={LazyAbout} />
<Route path='/faq' component = {LazyFAQ} />
<Route path='/careers' component = {LazyCareers} />
</Switch>)
然后利用 Webpack 做 code-splitting,我们就会得到如下打 chunk 的结果:
react-app/
- index.html
- index.bacd0123.js (contains App)
- about.1234.js (contains About component)
- faq.5678.js (contains FAQ component)
- careers.9012.js (contains Careers component)
/** index.html **/
<head>
<div id="root"></div>
<script src="index.bacd0123.js"></script>
</head>
基于组件的 code splitting
这个就看需要咯,此处略。