React-引领未来的用户界面开发框架-读书笔记(一)

这本书的主要内容都是以react v0.12为主,ES5语法,笔记中将会使用react v0.14和RS6。

第1章 react简介

1.本质上是一个状态机,它以精简的模型管理复杂的随着时间而变化的状态。

2.它不是model-view-controller,它是mvc中的v(view),用来渲染视图。

3.React运用虚拟的dom实现了一个强大的渲染系统。

4.(1)React就像高性能3d游戏引擎,以渲染函数为基础。这些函数读入当前的状态,将其转换为目标页面上的一个虚拟表现。只要react被告知状态有变化,它就会重新运行这些函数,计算页面的一个新的虚拟表现,接着自动化把结果转换成必要的dom更新来反应新的表现。

4.(2)乍一看,这种方式应该比通常的javascript方案(按需更新每一个元素要慢),但react确实是这么做的:它是用了非常高效的算法,计算出虚拟页面当前版本和新版间的差异,基于这些差异对dom进行必要的最少更新。

5.所以说react赢就赢在了:

  • 最小化了重绘,
  • 并避免了不必要的dom操作,
  • 这两点都是公认的性能瓶颈。

6.react的虚拟表示差异算法,不但能够把这些问题的影响降到最低。 ,还能简化应用的维护成本。当用户输入或者有其他更新导致状态改变时,我们只要简单的通知react状态改变了,它就能自动化地处理剩下的事情。我们无须深入到详细的过程之中。

7.react在整个应用中只使用单个事件处理器,并且会把所有的事件委托到这个处理器上。这一点也提升了react的性能。因为如果有很多时间处理器也会导致性能问题。

第2章 JSX

什么是JSX

JSX即JavaScript XML——一种在React组件内部构建标签的类XML语法。

与以往在JavaScript中嵌入HTML标签的几种方案相比,JSX有如下几点明显的特征:

  1. JSX是一种句法变换——每一个JSX节点都对应着一个JavaScript函数
  2. JSX既不提供也不需要运行时库。
  3. JSX并没有改变会添加JavaScript的语义——它只是简单的函数调用而已。



使用JSX前

React.DOM.h1({className: 'question'}, 'Question');                  // v0.11React.createElement('h1', {className: 'question'}, 'Question');     // v0.12

使用JSX之后

<h1 className="question">Queations</h1>;

使用JSX的好处

  1. 允许使用熟悉的语法来定义html元素树
  2. 提供更佳语义化且易懂的标签
  3. 程序结构更容易被直观化
  4. 抽象了react element的创建过程
  5. 可以随时掌控html标签以及生成这些标签的代码
  6. 是原生的javascript

定义一个自定义组件

const React = require('react');
const ReactDOM = require('react-dom');
class Divider extends React.Component {render() {return (<div classNams="divider"><h2>Questions</h2><hr/></div>)}
}
ReactDOM.render(<Divider></Divider>,document.getElementById('init')
);

使用动态值

JSX将两个花括号之间的内容{。。。}渲染为动态值。

简单值:

var text = "Questions"
class Divider extends React.Component {render() {return (<div classNams="divider"><h2>{text}</h2><hr/></div>)}
}
ReactDOM.render(<Divider></Divider>,document.getElementById('init')
);

复杂逻辑使用函数求值:

class Date extends React.Component {
    dataToString = (d) => {return [d.getFullYear(),d.getMonth + 1,d.getDate()].join('-')}render() {return (<h2>{this.dataToString(new Date())}</h2>)}
}
ReactDOM.render(<Date></Date>,document.getElementById('init')
);

react通过将数组中的每一个元素渲染为一个节点的方式对数组进行自动求值。

var text = ['hello', 'world']
class Hello extends React.Component {render() {return (<h2>{text}</h2>)}
}
ReactDOM.render(<Hello></Hello>,document.getElementById('init')
);
// 渲染为 <h2>helloworld</h2>

子节点

将上面介绍过的例子改写为:

const React = require('react');
const ReactDOM = require('react-dom');
class Divider extends React.Component {render() {return (<div classNams="divider"><h2>{this.props.children}</h2><hr/></div>)}
}
ReactDOM.render(<Divider>Questions</Divider>,document.getElementById('init')
);

注意,后面的示例中我们不会再写const React = require('react');const ReactDOM = require('react-dom');ReactDOM.render(<Divider>Questions</Divider>,document.getElementById('init'));这几行代码。

React将开始标签与结束标签之间的所有子节点保存在一个名为this.props.children的特殊组件属性中。在上面的例子中,this.props.children == ["Questions"]

条件判断

if/else逻辑很难用HTML标签来表达,直接往JSX中加入if语句会渲染出无效的JavaScript:

// 这是错误的示范
<div className={if(isComplete) { 'is-complete' }}>。。。</div>

而解决的办法就是使用以下某种方法:

  • 使用三目运算符
  • 设置一个变量并在属性中引用
  • 将逻辑转化到函数中
  • 使用&&运算符

使用三目运算符

render(){return(<div className={this.state.isComplete ? 'is-complete' : ''}>...</div>)
}

使用变量

getIsComplete = () => {return this.state.isComplete ? 'is-complete' : '';
}
render(){var isComplete = this.getIsComplete();return(<div className={isComplete}>...</div>)
}

使用函数

getIsComplete = () => {return this.state.isComplete ? 'is-complete' : '';
}
render(){return(<div className={this.getIsComplete()}>...</div>)
}

使用逻辑与(&&)运算符

render(){return(<div className={this.state.isComplete && 'is-complete'}>...</div>)
}

非dom属性值

key

  • 通过给组件设置一个独一无二的键,并确保它在一个渲染周期中保持一致,使得react能够更智能地决定应该重用一个组件,还是销毁并重新创建一个组件,进而提升渲染性能。

ref

  • ref允许父组件在render方法之外保持对子组件的一个引用
  • 在jsx中,你可以通过在属性中设置期望的引用名来定义一个引用。
render () {return (<div><input ref="myInput" .../></div>);
}

接着就可以在组件中的任何地方使用this.refs.myInput获取这个引用了(不是真实的dom,是react在需要时用来创建dom的一个描述对象。若要访问真实的节点,则可以使用:this.refs.myInput.getDOMNode() )

dangerouslySetInnerHTML(随时可能发生变化)

render () {var htmlString = {__html: "<span>an html string</span>"}return (<div dangerouslySetInnerHTML={htmlString}></div>);
}

事件

在jsx中,捕获一个事件就像给组件的方法设置一个属性一样简单。

handleClick = (event) => {//...
}
render () {return (<div onClick={this.handleClick.bind(this)}></div>);
}

注释

jsx的本质就是javascript,所以可以在标签内添加原生的js注释。 注释可以用以下2种形式添加:

  • 1.当做一个元素的子节点
  • 2.内联在元素的属性中

1.作为子节点:

<!-- 子节点形式的注释只需要简单地包裹在花括号内即可,并且可以跨多行。-->
<div>{/* 这是注释内容 */}<input type="text" name="" value="" placeholder="">
</div>

2.作为内联属性

// 内联的注释可以有两种形式。首先,可以使用多行注释:
<div><input/*这是多行注释内容!*/type="text" placeholder="address" />
</div>// 其次也可以使用单行注释
<div><inputtype="text"  // 这是单行注释placeholder="address" />
</div>

特殊属性

  • htmlFor (for)
    • 由于jsx会转换为js,所以有些关键词我们不能用,比如这个。
<label htmlFor="for-text" ...>
  • className (class)
<div className={classes} ...>

样式

简单的驼峰属性命名即可

render () {var styles = {borderColor: "#888",borderThinkness: "1px"};return (<div style={styles}></div>);
}

如果需要添加浏览器前缀瑞 -webkit-、-ms- 大驼峰(除了 ms ), 如:

var divStyle = {WebkitTransition: 'all', // 'W' 是大写msTransition: 'all'      // 'ms' 为小写
};

没有jsx的react

所有的jsx标签最后都会被转换为原生的javascript。因此jsx对于react来说并不是必需的。然而,jsx确实减少了一部分复杂性。如果你不打算在react中使用jsx,那么在react中创建元素时需要知道以下三点:

  • 1.定义组件类
  • 2.创建一个为组件类产生实例的工厂
  • 3.使用工厂来创建ReactElement实例

page 19.

第3章 组件的生命周期

React为每个组件提供了生命周期钩子函数去响应不同的时刻:

  • 1.实例化(创建时)
  • 2.活动期(存在期)
  • 3.销毁时(被销毁)

生命周期方法

react组件以简洁的生命周期api来单单提供你所需要的方法(而不是所有方法)。

实例化

一个实例初次被创建所调用的生命周期方法和其他各个后续实例被创建时所调用的方法略有不同。

所以:当你首次使用一个组件类时,有如下调用顺序:

  • getDefaultProps
  • getInitialState
  • componentWillMount
  • render
  • componentDidMount

而该组件类的所有后续应用,将会如下:

  • getDefaultProps
  • componentWillMount
  • render
  • componentDidMount

⚠️区别在于后续的不必执行:getInitialState函数,其余函数如常。(有待进一步理解)

React在ES6的实现中去掉了getInitialState这个hook函数,规定state在constructor中实现,如下:

class App extends React.Component {constructor(props) {super(props);this.state = {};}...}

Babel的Blog上还有一种实现方法,即直接使用赋值语句:

Class App extends React.Component {
constructor(props) {super(props);
}state = {}
...}

存在期

随着应用状态的改变,以及组件逐渐受到影响,依次调用如下方法:

  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

销毁&清理期

最后,组件被使用完后,componentWillUnmount方法将会被调用,目的是给这个实例提供清理自身的机会。

接下来,应该具体的理解 p24~30的内容(各个时期的各个函数的具体运作)。这里不过多阐述以增加篇幅,只理清思路即可。

我认为这段内容,应该是react的第一块关键内容,乃设计之精心之处,应多多揣摩,烂熟于胸。

由于原书的内容是基于ES5的,下面的章节对使用ES6时的生命周期进行讲解:

第二章 - ES6版 React组件生命周期小结

下面所写的,只适合前端的React。(React也支持后端渲染,而且和前端有点小区别,不过我没用过。)

相关函数

简单地说,React Component通过其定义的几个函数来控制组件在生命周期的各个阶段的动作。

在ES6中,一个React组件是用一个class来表示的(具体可以参考官方文档),如下:

// 定义一个TodoList的React组件,通过继承React.Component来实现
class TodoList extends React.Component {...
}

这几个生命周期相关的函数如下:

constructor(props, context)

构造函数,在创建组件的时候调用一次。

componentWillMount()

在组件挂载之前调用一次。如果在这个函数里面调用setState,本次的render函数可以看到更新后的state,并且只渲染一次。

componentDidMount()

在组件挂载之后调用一次。这个时候,子主键也都挂载好了,可以在这里使用refs。

componentWillReceiveProps(nextProps)

props是父组件传递给子组件的。父组件发生render的时候子组件就会调用componentWillReceiveProps(不管props有没有更新,也不管父子组件之间有没有数据交换)。

shouldComponentUpdate(nextProps, nextState)

组件挂载之后,每次调用setState后都会调用shouldComponentUpdate判断是否需要重新渲染组件。默认返回true,需要重新render。在比较复杂的应用里,有一些数据的改变并不影响界面展示,可以在这里做判断,优化渲染效率。

componentWillUpdate(nextProps, nextState)

shouldComponentUpdate返回true或者调用forceUpdate之后,componentWillUpdate会被调用。

componentDidUpdate()

除了首次render之后调用componentDidMount,其它render结束之后都是调用componentDidUpdate。

componentWillMount、componentDidMount和componentWillUpdate、componentDidUpdate可以对应起来。区别在于,前者只有在挂载的时候会被调用;而后者在以后的每次更新渲染之后都会被调用。

ReactElement render()

render是一个React组件所必不可少的核心函数(上面的其它函数都不是必须的)。记住,不要在render里面修改state。

componentWillUnmount()

组件被卸载的时候调用。一般在componentDidMount里面注册的事件需要在这里删除。

更新方式

在react中,触发render的有4条路径。

以下假设shouldComponentUpdate都是按照默认返回true的方式。

  1. 首次渲染Initial Render
  2. 调用this.setState (并不是一次setState会触发一次render,React可能会合并操作,再一次性进行render)
  3. 父组件发生更新(一般就是props发生改变,但是就算props没有改变或者父子组件之间没有数据交换也会触发render)
  4. 调用this.forceUpdate

下面是我对React组件四条更新路径地总结:

React组件

注意,如果在shouldComponentUpdate里面返回false可以提前退出更新路径。

一个React组件生命周期的测试例子

代码比较简单,没有逻辑,只是在每个相关函数里面alert一下。

点击链接来试试这个例子。

源码

const React = require('react');
const ReactDOM = require('react-dom');
class LifeCycle extends React.Component {constructor(props) {super(props);alert("Initial render");alert("constructor");this.state = {str: "hello"};}componentWillMount() {alert("componentWillMount");}componentDidMount() {alert("componentDidMount");}componentWillReceiveProps(nextProps) {alert("componentWillReceiveProps");}shouldComponentUpdate() {alert("shouldComponentUpdate");return true;        // 记得要返回true}componentWillUpdate() {alert("componentWillUpdate");}componentDidUpdate() {alert("componentDidUpdate");}componentWillUnmount() {alert("componentWillUnmount");}setTheState() {let s = "hello";if (this.state.str === s) {s = "HELLO";}this.setState({str: s});}forceItUpdate() {this.forceUpdate();}render() {alert("render");return(<div><span>{"Props:"}<h2>{parseInt(this.props.num)}</h2></span><br /><span>{"State:"}<h2>{this.state.str}</h2></span></div>);}
}class Container  extends React.Component {constructor(props) {super(props);this.state = {num: Math.random() * 100};}propsChange() {this.setState({num: Math.random() * 100});}setLifeCycleState() {this.refs.rLifeCycle.setTheState();}forceLifeCycleUpdate() {this.refs.rLifeCycle.forceItUpdate();}unmountLifeCycle() {// 这里卸载父组件也会导致卸载子组件React.unmountComponentAtNode(document.getElementById("container"));}parentForceUpdate() {this.forceUpdate();}render() {return (<div><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.propsChange.bind(this)}>propsChange</a><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.setLifeCycleState.bind(this)}>setState</a><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.forceLifeCycleUpdate.bind(this)}>forceUpdate</a><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.unmountLifeCycle.bind(this)}>unmount</a><a href="javascript:;" className="weui_btn weui_btn_primary" onClick={this.parentForceUpdate.bind(this)}>parentForceUpdateWithoutChange</a><LifeCycle ref="rLifeCycle" num={this.state.num}></LifeCycle></div>);}
}ReactDOM.render(<Container></Container>,document.getElementById('init')
);

示例解读:

⚠️所有的弹窗都是在子组件中的

  1. 首次加载:Initial render、constructor、componentWillMount、render、componentDidMount
  2. 改变父的state:componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate
  3. 改变子的state:shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate
  4. 父forceUpdate:componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate(和2一样)
  5. 子forceUpdate:componentWillUpdate、render、componentDidUpdate
  6. 卸载父:componentWillUnmount


本系列文章转自http://me.molinblog.com/,感谢作者。
http://me.molinblog.com/blog/developing-a-react-edge-1.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/286796.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android之提示This version of Android Studio cannot open this project, please retry with Android Studio

1 问题 编译项目&#xff0c;错误提示如下 This version of Android Studio cannot open this project, please retry with Android Studio 2 解决办法 很明显&#xff0c;看英语翻译也知道&#xff0c;是由于AS版本太低导致&#xff0c;升级AS就可以了。

Netflix 的 API 架构演变历程

Netflix 以其松耦合和高度可扩展的微服务架构而闻名&#xff0c;Netflix API 的后端架构经历了 4 个主要阶段。&#x1d40c;&#x1d428;&#x1d427;&#x1d428;&#x1d425;&#x1d422;&#x1d42d;&#x1d421; &#x1d40c;&#x1d428;&#x1d427;&#x1d…

五、Web App 基础可视组件属性(IVX 快速开发教程)

五、基础可视组件属性 在 iVX 中各个组件存在不同的属性&#xff0c;这些属性用于设置显示的样式或者是自身具备的特征等&#xff0c;通过更改这些属性可以极大的方便我们进行项目的创作。 大多数组件都拥有相同的属性&#xff0c;相同属性在以下内容中不会赘述介绍&#xff…

zabbix自动发现(Discovery)功能使用

随着监控主机不断增多&#xff0c;有的时候需要添加一批机器&#xff0c;特别是刚用zabbix的童鞋 需要将公司的所有服务器添加到zabbix&#xff0c;如果使用传统办法去单个添加设备、分组、项目、图像…..结果应该是让人吐的结果。 鉴于这个问题我们可以好好利用下Zabbix大…

Apache之三种工作模式和配置性能优化

1 Apache的3种模式和版本 Apache目前一共有三种稳定的MPM&#xff08;Multi-Processing Module&#xff0c;多进程处理模块&#xff09;模式&#xff0c;它们分别是prefork&#xff0c;worker和event。 我们可以使用httpd -V 命令查看apache的版本和模式&#xff0c;如果你服务…

lsof命令

lsof, LiSt Opened Files, 列出打开的文件, 听起来很简单的样子. 但想*nix中很多其他工具一样, lsof把这件简单的事情做到了炉火纯青. 因为Unix认为”一切皆文件”, 那么”打开的文件”就不仅仅是传统意义上打开的文件了, 还可以是网络/Unix域套接字, 匿名/具名管道, 共享库文件…

六、WebApp 二手信息站点页面制作(IVX 快速开发教程)

六、二手信息站点页面制作 在了解了基础可视组件后&#xff0c;我们可以通过这些可视组件进行站点页面开发&#xff0c;在此以一个二手交易网站站点页面为例&#xff0c;本教程示例并不是成熟完善的示例&#xff0c;需要各位读者进行少量完善&#xff0c;示例只是用于功能讲解…

Blazor University (25)路由 —— 通过 HTML 导航

原文链接&#xff1a;https://blazor-university.com/routing/navigating-our-app-via-html/通过 HTML 导航源代码[1]链接到 Blazor 组件中的路由的最简单方法是使用 HTML 超链接。<a href"/Counter">This works just fine</a>Blazor 组件中的超链接会被…

OpenReports中文支持方案

此文章在《OpenReports中文支持完全解决方案.doc》的基础上做优化&#xff0c;并贴出代码。已测试通过。 一、主要解决的问题 1 页面显示支持中文 2 与服务器或数据库的交互支持中文 3 查询结果支持中文 4 导出文件名及内容支持中文 二、解决方案及方法 1 …

七、功能性组件与事件逻辑(IVX 快速开发教程)

七、功能性组件与事件逻辑 由于 iVX 极度易用的特性&#xff0c;在 iVX 中开发微信小程序、WebApp、小游戏应用的开发流程大致相同。介绍完基础可视化组件后通过后台的服务、数据库与事件结合即可完成一个应用的开发&#xff1b;此篇将会介绍 iVX 功能性组件与事件&#xff0c…

WPF 基础控件之 ToggleButton 样式

其他基础控件1.Window2.Button3.CheckBox4.ComboBox5.DataGrid 6.DatePicker7.Expander8.GroupBox9.ListBox10.ListView11.Menu12.PasswordBox13.TextBox14.RadioButtonToggleButton 实现下面的效果1&#xff09;ToggleButton来实现动画&#xff1b;Border嵌套 Ellipse并设置T…

反射调用 java bean的set和get方法

v一、使用java.beans.PropertyDescriptor import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method;public class PropertyUtil {private static final String SET_PREFIX "…

八、后台与数据库(IVX 快速开发教程)

八、后台与数据库 在 iVX 中 数据库 作为数据存储仓库&#xff0c;通过 数据库 可以永久性存储存储数据&#xff0c;而 后台服务 起到数据传输作用&#xff0c;将 数据库 的数据传输到前台页面之中&#xff0c;页面再使用这些数据。 文章目录八、后台与数据库8.1.1 数据库添加…

Android Studio开发环境搭建准备

Android Studio 是一个Android开发环境&#xff0c;基于IntelliJ IDEA. 类似 Eclipse ADT&#xff0c;Android Studio 提供了集成的 Android 开发工具用于开发和调试。 Android Studio开发环境搭建前&#xff0c;我们需要进行安装前的准备工作&#xff0c;本篇以在Windows 7平台…

九、二手信息站点后台完成 (IVX 快速开发教程)

九、二手信息站点后台完成 了解完后台实现后&#xff0c;我们开始为该二手商品站点完成完成后台制作。 文章目录九、二手信息站点后台完成9.1.1 完成二手信息站点注册功能9.1.2 完成二手信息站点登录功能9.1.3 完成商品发布功能9.1.4 首页信息获取9.1.5 详情页内容9.1.1 完成二…

爬虫是什么?起什么作用?

【爬虫】 如果把互联网比作一张大的蜘蛛网&#xff0c;数据便是放于蜘蛛网的各个节点&#xff0c;而爬虫就是一只小蜘蛛&#xff0c;沿着网络抓取自己得猎物&#xff08;数据&#xff09;。这种解释可能更容易理解&#xff0c;官网的&#xff0c;就是下面这个。 爬虫是一种自动…

oneproxy检测主从复制同步延迟

Q:为什么要实现读写分离延迟检测&#xff1f; A:就好比你在ATM机存钱&#xff0c;你老婆收到短信后乐呵呵的拿网银APP查看&#xff0c;结果钱没过来。其实钱已经到账了&#xff0c;只是查询的ATM机节点钱还没过来。所以我们dba要监控数据&#xff0c;一旦发现钱没有复制到另一A…

.NET 分表分库动态化处理

介绍本期主角:ShardingCore 一款ef-core下高性能、轻量级针对分表分库读写分离的解决方案&#xff0c;具有零依赖、零学习成本、零业务代码入侵我不是efcore怎么办这边肯定有小伙伴要问有没有不是efcore的,我这边很确信的和你讲有并且适应所有的ADO.NET包括sqlhelperShardingCo…