嗨钱网是哪里的的利息和其他平台比起来怎么样?

Web性能优化之服务端渲染 React 同构直出 - 推酷
Web性能优化之服务端渲染 React 同构直出
React 的实践从去年在 PC QQ家校群开始,由于 PC 上的网络及环境都相当好,所以在使用时可谓一帆风顺,偶尔遇到点小磕绊,也能够快速地填补磨平。而最近一段时间,我们将手Q的家校群重构成 React,除了原有框架上存在明显问题的原因外,选择React也是因为它确实有足够的吸引力以及优势,加之在PC家校群上的实践经验,斟酌下便开始了,到现在已有页面在线上正常跑起。
由于移动端上的网络及环境迥异,性能偏差。所以在移动端上用 React 时,遇到了不少的坑点,也花了一些力气在上面。关于在移动端上的优化,可看我们团队的另一篇文章的
一提到优化,不得不提直出
关于这块可以查看
,这篇文章较详细的分析直出的概念及一步步优化,也结合了 手Q家校群使用快速的 数据直出 方式来优化性能的总结与性能数据分析
一提到 React,不得不提同构
同构基于服务端渲染,却不止是服务端渲染。
服务端渲染到同构的这一路
服务端渲染的方案早在后台程序前后端包办的时代上就有了,那时候使用JSP、PHP等动态语言将数据与页面模版整合后输出给浏览器,一步到位
这个时候,前端开发跟后端揉为一体,项目小的时候,前后端的开发和调试还真可以称为一步到位。但当项目庞大起来的时候,无论是修改某个样式要起一个庞大服务的尴尬,还是前后端糅合的地带变得越来越难以维护,都很难过。
前后端分离后,服务端渲染的模式就开始被淡化了。这时候的服务端渲染比较尴尬,由于前后端的编码语言不同,连页面模板都不能复用,只能让在前后端开发完成后,再将前端代码改为给后端使用的页面模板,增大了工作量。最终也还是跟后台包办殊途同归。
Node 驾着祥云腾空而来,谷歌 V8 引擎给力支持,众前端拿着看家本领(JavaScript)开始涉足服务端,于是服务端渲染上又一步进阶
由于前后端时候的相同的语言,所以前后端在代码的共用上达到了新的高度,页面模版、node modules 都可以做成前后通用。同构的雏形,只是共用的代码还是有局限。
有了Node 后,前端便有了更多的想象空间。前端框架开始考虑兼容服务端渲染,提供更方便的 API,前后端共用一套代码的方案,让服务端渲染越来越便捷。当然,不只是 React 做了这件事,但 React 将这种思想推向高潮,同构的概念也开始广为人传。
关于 React 网上已有大多教程,可以查看阮老师的react-demos。关于 React 上的数据流管理方案,现在最为火热的 Redux 应该是首选,具体可以查看另一篇文章 React 数据流管理架构之Redux ,此篇就不再赘述,下面讲讲 React 同构的理论与在手Q家校群上的具体实践总结。
React 同构
React 虚拟 Dom
React 的虚拟 Dom 以对象树的形式保存在内存中,并存在前后端两种展露原型的形式
客户端上,虚拟 Dom 通过 ReactDOM 的 Render 方法渲染到页面中
服务端上,React 提供的另外两个方法:ReactDOMServer.renderToString 和 ReactDOMServer.renderToStaticMarkup 可将其渲染为 HTML 字符串。
React 同构的关键要素
完善的 Compponent 属性及生命周期与客户端的 render 时机是 React 同构的关键。
DOM 的一致性
在前后端渲染相同的 Compponent,将输出一致的 Dom 结构。
不同的生命周期
在服务端上 Component 生命周期只会到 componentWillMount,客户端则是完整的。
客户端 render 时机
同构时,服务端结合数据将 Component 渲染成完整的 HTML 字符串并将数据状态返回给客户端,客户端会判断是否可以直接使用或需要重新挂载。
以上便是 React 在同构/服务端渲染的提供的基础条件。在实际项目应用中,还需要考虑其他边角问题,例如服务器端没有 window 对象,需要做不同处理等。下面将通过在手Q家校群上的具体实践,分享一些同构的 Tips 及优化成果
以手Q家校群 React 同构实践为例
手Q家校群使用 React + Redux + Webpack 的架构
同构实践 Tips
1. renderToString 和 renderToStaticMarkup
ReactDOMServer 提供 renderToString 和 renderToStaticMarkup 的方法,大多数情况使用 renderToString ,这样会为组件增加 checksum
React 在客户端通过 checksum 判断是否需要重新render
相同则不重新render,省略创建DOM和挂载DOM的过程,接着触发 componentDidMount 等事件来处理服务端上的未尽事宜(事件绑定等),从而加快了交互时间; 不同 时,组件将客户端上被重新挂载 render。
renderToStaticMarkup则不会生成与 react 相关的data-*,也不存在 checksum,输出的 html 如下
在客户端时组件会被重新挂载,客户端重新挂载不生成 checknum( 也没这个必要 ),所以该方法只当服务端上所渲染的组件在客户端不需要时才使用
2. 服务端上的数据状态与同步给客户端
服务端上的产生的数据需要随着页面一同返回,客户端使用该数据去 render,从而保持状态一致。服务端上使用 renderToString 而在客户端上依然重新挂载组件的情况大多是因为在返回 HTML 的时候没有将服务端上的数据一同返回,或者是返回的数据格式不对导致,开发时可以留意 chrome 上的提示如
3. 服务端需提前拉取数据,客户端则在 componentDidMount 调用
平台上的差异,服务端渲染只会执行到 compnentWillMount 上,所以为了达到同构的目的,可以把拉取数据的逻辑写到 React Class 的静态方法上,一方面服务端上可以通过直接操作静态方法来提前拉取数据再根据数据生成 HTML,另一方面客户端可以在 componentDidMount 时去调用该静态方法拉取数据
4. 保持数据的确定性
这里指影响组件 render 结果的数据,举个例子,下面的组件由于在服务端与客户端渲染上会因为组件上产生不同随机数的原因而导致客户端将重新渲染。
Class Wrapper extends Component {
render() {
return (&h1&{Math.random()}&/h1&);
可以将 Math.random() 封装至Component 的 props 中,在服务端上生成随机数并传入到这个component中,从而保证随机数在客户端和服务端一致。如
Class Wrapper extends Component {
render() {
return (&h1&{this.props.randomNum}&/h1&);
服务端上传入randomNum
let randomNum = Math.random()
var html = ReacDOMServer.renderToString(&Wrapper randomNum={randomNum} /&);
5. 平台区分
当前后端共用一套代码的时候,像前端特有的 Window 对象,Ajax 请求 在后端是无法使用上的,后端需要去掉这些前端特有的对象逻辑或使用对应的后端方案,如后端可以使用 http.request 替代 Ajax 请求,所以需要进行平台区分,主要有以下几种方式
1.代码使用前后端通用的模块,如 isomorphic-fetch
2.前后端通过webpack 配置 resolve.alias 对应不同的文件,如
客户端使用 /browser/request.js 来做 ajax 请求
resolve: {
'request': path.join(pathConfig.src, '/browser/request'),
服务端 webpack 上使用 /server/request.js 以 http.request 替代 ajax 请求
resolve: {
'request': path.join(pathConfig.src, '/server/request'),
3.使用 webpack.DefinePlugin 在构建时添加一个平台区分的值,这种方式的在 webpack UglifyJsPlugin 编译后,非当前平台( 不可达代码 )的代码将会被去掉,不会增加文件大小。如
在服务端的 webpack 加上下面配置
new webpack.DefinePlugin({
&__ISOMORPHIC__&: true
在JS逻辑上做判断
if(__ISOMORPHIC__){
// do server thing
// do browser thing
4.window 是浏览器上特有的对象,所以也可以用来做平台区分
var isNode = typeof window === 'undefined';
if (isNode) {
// do server thing
// do browser thing
6. 只直出首屏页面可视内容,其他在客户端上延迟处理
这是为了减少服务端的负担,也是加快首屏展示时间,如在手Q家校群列表中存在 “我发布的” 和 “全部” 两个 tab,内容都为作业列表,此次实践在服务端上只处理首屏可视内容,即只输出 “我发布的” 的完整HTML,另外一个tab的内容在客户端上通过 react 的 dom diff 机制来动态挂载,无页面刷新的感知。
7. componentWillReceiveProps 中,依赖数据变化的方法,需考虑在 componentDidMount 做兼容
举个例子,identity 默认为 UNKOWN,从后台拉取到数据后,更新其值,从而触发 setButton 方法
componentWillReceiveProps(nextProps) {
if (nextProps.role.get('identity') !== UNKOWN &&
nextProps.role.get('identity')
!== this.props.role.get('identity'))) {
this.setButton();
同构时,由于服务端上已做了第一次数据拉取,所以上面代码在客户端上将由于 identity 已存在而导致永不执行 setButton 方法,解决方式可在 componentDidMount 做兼容处理
componentDidMount() {
// .. 判断是否为同构
if (identity !== UNKOWN) {
this.setButton(identity);
8. redux在服务端上的使用方式 (redux)
下图为其中一种形式,先进行数据请求,再将请求到的数据 dispatch 一个 action,通过在reducer将数据进行 redux 的 state 化。还有其他方式,如直接 dispatch 一个 action,在action里面去做数据请求,后续是一样的,不过这样就要求请求数据的模块是 isomorphism 即前后端通用的。
9. 设计好 store state (redux)
设计好 store state 是使用 redux 的关键,而在服务端上,合理的扁平化 state 能在其被序列化时,减少 CPU 消耗
10. 两个 action 在同个component中数据存在依赖关系时,考虑setState的异步问题 (redux)
客户端上,由于 react 中 setState 的异步机制,所以在同个component中触发多个action,会出现一种情况是:第一个 action 对 state 的改变还没来得及更新component时,第二个action便开始执行,即第二个 action 将使用到未更新的值。
而在同构中,如果第一个 action (如下的 fetchData)是在服务端执行了,第二个 action 在客户端执行时将使用到的是第一个 action 对 state 改变后的值,即更新后的值。这时,同构需要做兼容处理。
fetchData() {
this.props.setCourse(lastCourseId, lastCourseName);
render() {
this.props.updateTab(TAB);
11. immutable 在同构上的姿势 (immutable/redux)
手Q家校群上使用了 immutable 来保证数据的不可变,提高数据对比速度,而在同构时需要注意两点
1.服务端上,从 store 中拿到的 state 为immutable对象,需转成 string 再同HTML返回
2.客户端上,从服务端注入到HTML上的 state 数据,需要将其转成 immutable对象,再放到 configureStore 中,如
var __serverData__ = Immutable.fromJS(window.__serverData__);
var store = configureStore(__serverData__);
12. 使用 webpack 去做 ES6 语法兼容 (webpack)
实际上,如果是一个单独的服务的话,可以使用babel提供的方式来让node环境兼容好 E6
require(&babel-register&)({
extensions: [&.jsx&],
presets: ['react']
require(&babel-polyfill&);
但如果是以同一个直出服务器,多个项目的直出代码都放在这个服务上,那么,还是建议使用 webpack 的方式去兼容 ES6,减少 babel 对全局环境的影响。使用 webpack 的话,在项目完成后,可将 es6 代码编译成 es5 再放到真正的 server 上,这样也可以减少动态编译耗时。
13. 不使用 webpack 的 css in js 的方式
使用webpack时,默认是将css文件以 css in js 的方式打包起来,这种情况将增加服务端运行耗时,通过将 css 外链,或在webpack打包成独立的css文件后再inline进去,可以减少服务端的处理耗时及负荷。
14. UglifyJsPlugin 在服务端编译时慎用
上面提及使用webpack编译后的代码放到真正的server上去跑,在前端发布前一般会进行代码uglify,而后端实际上没多大必要,在实际应用中发现,使用 UglifyJsPlugin 后运行服务端会报错,需慎用。
15. 纠正 __dirname 与 __filename 的值 (webpack)
当服务端代码需要使用到 __dirname 时,需在 webpack.config.js 配置 target 为 node,并在 node 中声明__filename和__dirname为true,否则拿不到准确值,如在服务端代码上添加 console.log(__dirname); 和 console.log(__filenam );
在服务端使用的 webpack 上指定 target 为 node,如下
target: 'node',
__filename: true,
__dirname: true
经 webpack 编译后输出如下代码,可看出 __dirname 和 __filename 将正确输出
而不在webpack上配置时,__dirname则为 / ,__filename则为文件名,这是不正确的
16.将 webpack 编译后的文件暴露出来 (webpack)
使用 webpack 将一个模块编译后将形成一个立即执行函数,函数中返回对象。如果需要将编译后的代码也作为一个模块供其他地方使用时,那么需要重新将该模块暴露出去( 如当业务上的直出代码只是作为直出服务器的其中一个任务时,那么需要将编译后的代码作为一个模块 exports 出去,即在编译后代码前重新加上 module.exports = ,从而直出服务将能够使用到这个编译后的模块代码 )。写了一个 webpack 插件来自动添加 module.exports,比较简单,有兴趣的欢迎使用
,效果如下
编译后( 不含module.exports )
编译后自动将模块exports出去
17. 去掉index.scss和浏览器专用模块(webpack)
当服务端上不想处理样式模块或一些浏览器才需要的模块(如前端上报)时,需要在服务端上将其忽略。尝试 webpack 自带的 webpack.IgnorePlugin 插件后出现一些奇奇怪怪的问题,重温
时想起 webpack 在执行时会将原文件经webpack loaders进行转换,如 jsx 转成 js等。所以想法是将在服务端上需要忽略的模块,在loader前执行前就将其忽略。写了个ignored-loader,可以将需要忽略的模块在 loader 执行前直接返回空,所以后续就不再做其他处理,简单但也满足现有需求。
服务端上的耗时增加了,但整体上的首屏渲染完成时间大大减少
服务端上增加的耗时
服务端渲染方案将数据的拉取和模板的渲染从客户端移到了服务端,由于服务端的环境以及数据拉取存在优势(详见
),所以在相比下,这块耗时大大减少,但确实存在,这两块耗时是服务端渲染相比于客户端渲染在服务端上多出来。所以本次也做了耗时的数据统计,如下图
从统计的数据上看,服务端上数据拉取的时间约 61.75 ms,服务端render耗时为16.32 ms,这两块时间的和为 78 ms,这耗时还是比较大。所以此次在 同构耗时在计算上包含了服务端数据拉取与模板渲染的时间
首屏渲染完成时间对比
服务端渲染时由于不需要等待 JS 加载和 数据请求(详见
),在首屏展示时间耗时上将大大减少,此次在手Q家校群列表页首屏渲染完成时间上,优化前平均耗时约1281.39 ms,而同构优化后平均耗时为 552.82 ms,有了 728ms 的优化 ,提升约 56.7% 的性能,秒开搓搓有余!
在Chrome上页面展示情况对比
2.优化后(同构直出)
可明显看出同构直出后,白屏时间大大减少,可交互时间也得到了提前,产品体验将变得更好。
服务端渲染的方式能够很好的减少首屏展示时间,React 同构的方式让前后端模板、类库、以及数据模型上共用,大大减少的服务端渲染的工作量。
由于在服务端上渲染模板,render 时过多的调用栈增加了服务端负载,也增加了 CPU 的压力,所以可以只直出首屏可视区域,减少Component层级,减少调用栈,最后,做好容灾方案,如真的服务端挂了( 虽然情况比较少 ),可以直接切换到普通的客户端渲染方案,保证用户体验。
以上,便是近期在 React 同构上的实践总结,如有不妥,恳请斧正,谢谢。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致深入理解 React | React
深入理解 React
这是一篇源自 的。
在我看来, React 是较早使用 JavaScript 构建大型、快速的 Web 应用程序的技术方案。它已经被我们广泛应用于 Facebook 和 Instagram 。
React 众多优秀特征中的其中一部分就是,教会你去重新思考如何构建应用程序。
本文中,我将跟你一起使用 React 构建一个具备搜索功能的产品列表。
如果你无法看到本页内嵌的代码片段,请确认你不是用 https 协议加载本页的。
从原型( mock )开始
假设我们已经拥有了一个 JSON API 和设计师设计的原型。我们的设计师显然不够好,因为原型看起来如下:
JSON接口返回数据如下:
{category: &Sporting Goods&, price: &$49.99&, stocked: true, name: &Football&},
{category: &Sporting Goods&, price: &$9.99&, stocked: true, name: &Baseball&},
{category: &Sporting Goods&, price: &$29.99&, stocked: false, name: &Basketball&},
{category: &Electronics&, price: &$99.99&, stocked: true, name: &iPod Touch&},
{category: &Electronics&, price: &$399.99&, stocked: false, name: &iPhone 5&},
{category: &Electronics&, price: &$199.99&, stocked: true, name: &Nexus 7&}
第一步:拆分用户界面为一个组件树
你要做的第一件事是,为所有组件(及子组件)命名并画上线框图。假如你和设计师一起工作,也许他们已经完成了这项工作,所以赶紧去跟他们沟通!他们的 Photoshop 图层名也许最终可以直接用于你的 React 组件名。
然而你如何知道哪些才能成为组件?想象一下,当你创建一些函数或对象时,用到一些类似的技术。其中一项技术就是,指的是,理想状态下一个组件应该只做一件事,假如它功能逐渐变大就需要被拆分成更小的子组件。
由于你经常需要将一个JSON数据模型展示给用户,因此你需要检查这个模型结构是否正确以便你的 UI (在这里指组件结构)是否能够正确的映射到这个模型上。这是因为用户界面和数据模型在 信息构造 方面都要一致,这意味着将你可以省下很多将 UI 分割成组件的麻烦事。你需要做的仅仅只是将数据模型分隔成一小块一小块的组件,以便它们都能够表示成组件。
由此可见,我们的 app 中包含五个组件。下面我已经用斜体标示出每个组件对应的数据。
FilterableProductTable (橘色): 包含整个例子的容器
SearchBar (蓝色): 接受所有 用户输入( user input )
ProductTable (绿色): 根据 用户输入( user input ) 过滤和展示 数据集合( data collection )
ProductCategoryRow (青色): 为每个 分类( category ) 展示一列表头
ProductRow (红色): 为每个 产品( product ) 展示一列
如果你仔细观察 ProductTable ,你会发现表头(包含“ Name ”和“ Price ”标签)并不是单独的组件。这只是一种个人偏好,也有一定的争论。在这个例子当中,我把表头当做 ProductTable 的一部分,因为它是渲染“数据集合”的一份子,这也是 ProductTable 的职责。但是,当这个表头变得复杂起来的时候(例如,添加排序功能),就应该单独地写一个 ProductTableHeader 组件。
既然我们在原型当中定义了这个组件,让我们把这些元素组成一棵树形结构。这很简单。被包含在其它组件中的组件在属性机构中应该是子级:
FilterableProductTable
ProductTable
ProductCategoryRow
ProductRow
第二步: 利用 React ,创建应用的一个静态版本
既然已经拥有了组件树,是时候开始实现应用了。最简单的方式就是创建一个应用,这个应用将数据模型渲染到 UI 上,但是没有交互功能。拆分这两个过程是最简单的,因为构建一个静态的版本仅需要大量的输入,而不需要思考;但是添加交互功能却需要大量的思考和少量的输入。我们将会知道这是为什么。
为了创建一个渲染数据模型的应用的静态版本,你将会构造一些组件,这些组件重用其它组件,并且通过 props 传递数据。 props 是一种从父级向子级传递数据的方式。如果你对 state 概念熟悉,那么*不要使用 state *来构建这个静态版本。 state 仅用于实现交互功能,也就是说,数据随着时间变化。因为这是一个静态的应用版本,所以你并不需要 state 。
你可以从上至下或者从下至上来构建应用。也就是说,你可以从属性结构的顶部开始构建这些组件(例如,从 FilterableProductTable 开始),或者从底部开始( ProductRow )。在简单的应用中,通常情况下从上至下的方式更加简单;在大型的项目中,从下至上的方式更加简单,这样也可以在构建的同时写测试代码。
在这步结束的时候,将会有一个可重用的组件库来渲染数据模型。这些组件将会仅有 render() 方法,因为这是应用的一个静态版本。位于树形结构顶部的组件( FilterableProductTable )将会使用数据模型作为 prop 。如果你改变底层数据模型,然后再次调用 React.render() , UI 将会更新。查看 UI 如何被更新和什么地方改变都是很容易的,因为 React 的单向数据流(也被称作“单向绑定”)保持了一切东西模块化,很容易查错,并且速度很快,没有什么复杂的。
如果你在这步中需要帮助,请查看。
穿插一小段内容: props 与 state 比较
在 React 中有两种类型的数据“模型”: props 和 state 。理解两者的区别是很重要的;如果你不太确定两者有什么区别,请大致浏览一下。
第三步:识别出最小的(但是完整的)代表 UI 的 state
为了使 UI 可交互,需要能够触发底层数据模型的变化。 React 通过 state 使这变得简单。
为了正确构建应用,首先需要考虑应用需要的最小的可变 state 数据模型集合。此处关键点在于精简:不要存储重复的数据。构造出绝对最小的满足应用需要的最小 state 是有必要的,并且计算出其它强烈需要的东西。例如,如果构建一个 TODO 列表,仅保存一个 TODO 列表项的数组,而不要保存另外一个指代数组长度的 state 变量。当想要渲染 TODO 列表项总数的时候,简单地取出 TODO 列表项数组的长度就可以了。
思考示例应用中的所有数据片段,有:
最初的 products 列表
用户输入的搜索文本
复选框的值
过滤后的 products 列表
让我们分析每一项,指出哪一个是 state 。简单地对每一项数据提出三个问题:
是否是从父级通过 props 传入的?如果是,可能不是 state 。
是否会随着时间改变?如果不是,可能不是 state 。
能根据组件中其它 state 数据或者 props 计算出来吗?如果是,就不是 state 。
初始的 products 列表通过 props 传入,所以不是 state 。搜索文本和复选框看起来像是 state ,因为它们随着时间改变,也不能根据其它数据计算出来。最后,过滤的 products 列表不是 state ,因为可以通过搜索文本和复选框的值从初始的 products 列表计算出来。
所以最终, state 是:
用户输入的搜索文本
复选框的值
第四步:确认 state 的生命周期
OK,我们辨别出了应用的 state 数据模型的最小集合。接下来,需要指出哪个组件会改变或者说拥有这个 state 数据模型。
记住: React 中数据是沿着组件树从上到下单向流动的。可能不会立刻明白哪个组件应该拥有哪些 state 数据模型。这对新手通常是最难理解和最具挑战的,因此跟随以下步骤来弄清楚这点:
对于应用中的每一个 state 数据:
找出每一个基于那个 state 渲染界面的组件。
找出共同的祖先组件(某个单个的组件,在组件树中位于需要这个 state 的所有组件的上面)。
要么是共同的祖先组件,要么是另外一个在组件树中位于更高层级的组件应该拥有这个 state 。
如果找不出拥有这个 state 数据模型的合适的组件,创建一个新的组件来维护这个 state ,然后添加到组件树中,层级位于所有共同拥有者组件的上面。
让我们在应用中应用这个策略:
ProductTable 需要基于 state 过滤产品列表,SearchBar 需要显示搜索文本和复选框状态。
共同拥有者组件是 FilterableProductTable 。
理论上,过滤文本和复选框值位于 FilterableProductTable 中是合适的。
太酷了,我们决定了 state 数据模型位于 FilterableProductTable 之中。首先,给 FilterableProductTable 添加 getInitialState() 方法,该方法返回 {filterText: '', inStockOnly: false} 来反映应用的初始化状态。然后传递 filterText 和 inStockOnly 给 ProductTable 和 SearchBar 作为 prop 。最后,使用这些 props 来过滤 ProductTable 中的行,设置在 SearchBar 中表单字段的值。
你可以开始观察应用将会如何运行:设置 filterText 为 &ball& ,然后刷新应用。将会看到数据表格被正确更新了。
第五步:添加反向数据流
到目前为止,已经构建了渲染正确的基于 props 和 state 的沿着组件树从上至下单向数据流动的应用。现在,是时候支持另外一种数据流动方式了:组件树中层级很深的表单组件需要更新 FilterableProductTable 中的 state 。
React 让这种数据流动非常明确,从而很容易理解应用是如何工作的,但是相对于传统的双向数据绑定,确实需要输入更多的东西。 React 提供了一个叫做 ReactLink 的插件来使其和双向数据绑定一样方便,但是考虑到这篇文章的目的,我们将会保持所有东西都直截了当。
如果你尝试在示例的当前版本中输入或者选中复选框,将会发现 React 会忽略你的输入。这是有意的,因为已经设置了 input 的 value 属性,使其总是与从 FilterableProductTable 传递过来的 state 一致。
让我们思考下我们希望发生什么。我们想确保无论何时用户改变了表单,都要更新 state 来反映用户的输入。由于组件只能更新自己的 state , FilterableProductTable 将会传递一个回调函数给 SearchBar ,此函数将会在 state 应该被改变的时候触发。我们可以使用 input 的 onChange 事件来监听用户输入,从而确定何时触发回调函数。 FilterableProductTable 传递的回调函数将会调用 setState() ,然后应用将会被更新。
虽然这听起来有很多内容,但是实际上仅仅需要几行代码。并且关于数据在应用中如何流动真的非常清晰明确。
就这么简单
希望以上内容让你明白了如何思考用 React 去构造组件和应用。虽然可能比你之前要输入更多的代码,记住,读代码的时间远比写代码的时间多,并且阅读这种模块化的清晰的代码是相当容易的。当你开始构建大型的组件库的时候,你将会非常感激这种清晰性和模块化,并且随着代码的复用,整个项目代码量就开始变少了 :)。
A Facebook & Instagram collaboration.
Facebook Inc.
Documentation licensed under .

我要回帖

更多关于 嗨钱网利息 的文章

 

随机推荐