《 React 快速上手开发》
第一章 Hello World!
一个原生的简单的React应用只需要包含如下几部分
完整代码如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <!DOCTYPE html> <html> <head> <title>hello React </title> <meta charset="utf-8"> </head> <body> <div id="app"> </div>
<script src="react/build/react.js"></script>
<script src="react/build/react-dom.js"></script> <script> ReactDOM.render( React.DOM.h1(null, "Hello world!"), document.getElementById("app") ); </script> </body> </html>
|
其中的React.DOM
是一个预定义好的HTML元素集合,例如React.DOM.h1()
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| React.DOM.h1( { id: "my-heading", className: "pretty", htmlFor: "me", style: { background: "black", color: "white", fontFamily: "Verdana", } }, React.DOM.span(null, React.DOM.em(null, "Hell"), "o" ), " world!" )
|
上述方法中描述的内容都是可以通过JSX进行更方便的书写,但需要明白那些更方便的书写的本质是React.DOM.*
,而React.DOM.*
是对React.createElement()
的封装,下面的代码等价于上面的写法
1 2 3 4
| ReactDOM.render( React.createElement("span", null, "Hello"), document.getElementById("app") );
|
第二章 组件的生命周期
定义一个组件,组件中包含的数据句柄有this.props
和this.state
两个,这两个变量都应认为他们是只读的,第一个props
更类似于静态的构建,而第二个state
更类似于动态的构建,可以通过调用this.setState()
方法更改数值并触发React重新render
绘制内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| var logMixin = { _log: function(methodName, args) { console.log(this.name + '::' + methodName, args); }, componentWillUpdate: function() {this._log('componentWillUpdate', arguments);}, componentDidUpdate: function() {this._log('componentDidUpdate', arguments);}, componentWillMount: function() {this._log('componentWillMount', arguments);}, componentDidMount: function() {this._log('componentDidMount', arguments);}, componentWillUnmount: function() {this._log('componentWillUnmount', arguments);}, };
var Component = React.createClass({ name: 'componentName', mixins: [logMixin], propTypes: { name: React.PropTypes.string.isRequired, text: React.PropTypes.string, }, getDefaultProps: function () { return { text: 'ReactLearn', }; }, getInitialState: function () { return { text: this.props.text, }; }, _textChange: function (ev) { this.setState({ text: ev.target.value, }); }, componentWillUpdate: function() {this._log('componentWillUpdate', arguments);}, componentDidUpdate: function() {this._log('componentDidUpdate', arguments);}, componentWillMount: function() {this._log('componentWillMount', arguments);}, componentDidMount: function() {this._log('componentDidMount', arguments);}, componentWillUnmount: function() {this._log('componentWillUnmount', arguments);}, render: function () { return React.DOM.div(null, React.DOM.span(null, "My name is " + this.props.name), React.DOM.textarea({ value: this.state.text, onChange: this._textChange, }), React.DOM.h3(null, this.state.text.length) ); } });
|
使用一个组件
1 2 3 4 5 6 7 8 9 10
| ReactDOM.render( React.createElement(Component, {name: "Bob"}), document.getElementById("app") );
var ComponentFactory = React.createFactory(Component); ReactDOM.render( ComponentFactory(), document.getElementById("app") );
|
第三章 Excel: 一个出色的表格组件
一个非常简短但功能完整的例子,这里简单记录一下阅读过程中感觉比较重要的几个点:
- 更新数据的时候,需要先将需要更新的数据拷贝出来,更新之后,然后进行再调用
setState()
函数更新
- 如何在表格中定位和编辑数据
- 不要担心大量前端代码的重复
render()
,React会使用DOM diff算法,实现最小范围的重新渲染
第四章 JSX
JSX是一项完全独立于React的技术,但又是完全兼容的,可以简化React.DOM.*
的繁琐书写。
转译JSX
比较原始的在客户端中转义jsx,可以引入babel/browser.js
,然后对需要转义的js代码进行标识type="text/babel"
,让Babel在浏览器执行这些代码的时候进行转义。
1 2
| <script src="babel/browser.js"></script> <script type="text/babel">...</script>
|
在JSX 中使用JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| render: function() { var state = this.state; return ( <table> <thead onClick={this._sort}> <tr>{ this.props.headers.map(function(title, idx) { if (state.sortby === idx) { title += state.descending ? ' \u2191' : ' \u2193' } return <th key={idx}>{title}</th>; }) }</tr> </thead> <tbody> { this.state.data.map(function(row, idx) { return ( <tr key={idx}>{ row.map(function(cell, idx) { return <td key={idx}>{cell}</td>; }) }</tr> ); }) } </tbody> </table> ); }
|
在JSX中使用空格
JSX和HTML有很多相同之处,但是也有自己的特殊语法,简化很多操作
1 2 3 4 5 6 7 8
| ReactDOM.render( <h1> {1} {' plus '} {2} </h1>, document.getElementById('app') );
|
在JSX中使用HTML实体
需要注意编码的问题
展开属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var attr = { href: 'http://example.org', target: '_blank', }; // 比较原始的方法 return ( <a href={attr.href} target={attr.target}> Hello </a> ); // 使用展开属性 return <a {...attr}>Hello</a>;
|
JSX 比较完整的demo
累了,下次补上。
React 动手尝试教程
基础命令记录
1 2 3 4 5
| $ npx create-react-app {projectName} $ cd react-tutorial && npm start
$ npm install moment
|
配套JS组件
moment 教程
配套前端UI
布局组件
Plex 教程
flex-direction |
row | row-reverse | column | column-reverse |
排列方向 |
flex-wrap |
nowrap | wrap | wrap-reverse |
换行策略 |
flex-flow |
|
flex-direction 属性和flex-wrap 属性的简写形式 |
justify-content |
flex-start | flex-end | center | space-between | space-around |
项目在主轴上的对齐方式 |
align-items |
flex-start | flex-end | center | baseline | stretch |
项目在交叉轴上的对齐方式 |
align-content |
flex-start | flex-end | center | space-between | space-around | stretch |
多根轴线的对齐方式 |
路由组件
umi
图表组件
antV
ES6 学习
let 和 const命令
声明变量的6种方式
- var
- function
- let
- const
- import
- class
var, let 和 const 关键字
var声明的变量
1 2 3 4 5 6 7
| var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6]();
|
let声明的变量
- 只在它所在的代码块中生效
- let定义的变量,必须先定义然后才能用,否则会出错(不存在变量提升)。
- 不允许在相同的作用域内重复声明相同的变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| for (let i = 0; i < 10; i++) { } console.log(i);
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6]();
function func(arg) { let arg; } func()
function func(arg) { { let arg; } } func()
|
const声明的变量
- 是一个只读的常量,一旦读出来就不能再更改
- 声明的变量必须立即初始化,不能留到以后的赋值
- 本质是变量所指向的内存地址上保存的数据不能改变
作用域
在ES6中增加了块级作用域,可以
- 防止内层变量覆盖外层变量
- 防止局部变量泄漏成全局变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| var tmp = new Date();
function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } }
f();
var s = 'hello';
for (var i = 0; i < s.length; i++) { console.log(s[i]); }
console.log(i);
|
1 2 3 4 5 6 7 8
| function f1() { let n = 5; if (true) { let n = 10; } console.log(n); }
|
只要块区中存在let和const定义的变量,就会形成封闭作用域(被称为暂时性死区),在此之间声明的变量都会出错,即使在全局中已经有了该变量的声明
1 2 3 4 5 6 7
| var tmp = 123;
if (true) { tmp = 'abc'; let tmp; }
|
1 2 3 4 5 6 7 8 9 10
| function bar(x = y, y = 2) { return [x, y]; }
bar();
function bar(x = 2, y = x) { return [x, y]; } bar();
|
for循环的作用域说明
1 2 3 4 5 6 7
| for (let i = 0; i < 3; i++) { let i = 'abc'; console.log(i); }
|
顶层对象属性
在浏览器环境中指的是window对象,在Node中指的是global。顶层对象的属性和全局变量是等价的。
1 2 3 4 5
| window.a = 1; a
a = 2; window.a
|
var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面的规定,let命令、const命令、class命令声明的全局变量不属于顶层对象的属性。
- 全局环境中,
this
会返回顶层对象。但是,Node.js 模块中this
返回的是当前模块,ES6 模块中this
返回的是undefined
。
- 函数里面的
this
,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this
会指向顶层对象。但是,严格模式下,这时this
会返回undefined
。
- 不管是严格模式,还是普通模式,
new Function('return this')()
,总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval
、new Function
这些方法都可能无法使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
(typeof window !== 'undefined' ? window : (typeof process === 'object' && typeof require === 'function' && typeof global === 'object') ? global : this);
var getGlobal = function () { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } throw new Error('unable to locate global object'); };
|
变量的解构赋值
数组的解构赋值
基于模式匹配的思想,将等号右边的数组中对应的值赋给等号左边等价位置上的变量,如果解构不成功的话,对应值会等于undefined。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| let [foo, [[bar], baz]] = [1, [[2], 3]]; foo bar baz
let [ , , third] = ["foo", "bar", "baz"]; third
let [head, ...tail] = [1, 2, 3, 4]; head tail
let [x, y, ...z] = ['a']; x y z
let [x, y] = [1, 2, 3]; x y
let [a, [b], d] = [1, [2, 3], 4]; a b d
|
只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
1 2 3 4 5 6 7 8 9 10 11
| function* fibs() { let a = 0; let b = 1; while (true) { yield a; [a, b] = [b, a + b]; } }
let [first, second, third, fourth, fifth, sixth] = fibs(); sixth
|
解构允许指定默认值,需要注意的是 null != undefined
1 2 3 4 5
| let [foo = true] = []; foo
let [x, y = 'b'] = ['a']; let [x, y = 'b'] = ['a', undefined];
|
对象的解构赋值
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
1 2 3 4 5 6
| let { bar, foo } = { foo: 'aaa', bar: 'bbb' }; foo bar
let { baz } = { foo: 'aaa', bar: 'bbb' }; baz
|
对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。
1 2 3 4 5 6
| let { log, sin, cos } = Math;
const { log } = console; log('hello')
|
若想让变量名和属性名称不一样,则可以写成下面这样
1 2 3 4 5 6 7
| let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; baz
let obj = { first: 'hello', last: 'world' }; let { first: f, last: l } = obj; f l
|
解构同样也适用于嵌套结构的对象
1 2 3 4 5 6 7 8 9 10
| let obj = { p: [ 'Hello', { y: 'World' } ] };
let { p: [x, { y }] } = obj; x y
|
嵌套结构目标内容到变量的嵌套解构中
1 2 3 4 5 6 7
| let obj = {}; let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
obj arr
|
字符串扩展
字符串的for...of
遍历
1 2 3
| for (let i of text) { console.log(i); }
|
困了困了,以后继续看