1.准备

Babel 将 es6 转化成 es5 和解析 JSX 的工具(服务器端)
browser 将 es6 转化成 es5 和解析 JSX 的工具(浏览器端)

2.组件

1
var helloMessage = React.creatClass({render:function(){return ···}})

组件类的第一个字母必须大写,否则会报错,应改为HelloMessage

1
var helloMessage = React.creatClass({render:function(){return <h1></h1><p></p>}})

组件类只能包含一个顶层标签,否则也会报错。h1 和 p都是顶层标签了
如果一定要含有两层或更多的话,记得用()括起来,return (

)

1
<HelloMessage name="John" class="错的" for="错的">

添加组件的时候 class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字

3.this.props.children –这个可以 push 到[]内,调用这个[]也可以

的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。
React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。
用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var NotesList = React.createClass({
render: function () {
return (
<ol>
{React.Children.map(this.props.children, function (child) {
return <li>{child}</li>;
})}
</ol>
);
},
});

ReactDOM.render(
<NotesList>
<span>hello</span>
<span>world</span>
</NotesList>,
document.body
);

4.PropTypes

1
2
3
propTypes: {
title: React.PropTypes.string.isRequired,
}

上边这句是设置 title 属性必须为字符串,且必须存在

1
2
3
4
5
getDefaultProps : function () {
return {
title : 'Hello World'
};
},

设置属性默认值

5.获取真实的 DOM 节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var MyComponent = React.createClass({
handleClick: function () {
this.refs.myTextInput.focus(alert("haha")); //当点击之后,会弹出haha,只有当点击才会触发这个
},
render: function () {
return (
<div>
<input type="text" ref="myTextInput" />{" "}
//必须有这个ref来进行定位,并且获取这里的值
<input
type="button"
value="Focus the text input"
onClick={this.handleClick}
/>
</div>
);
},
});

所有的 DOM 操作都在虚拟 DOM 上发生,然在在反应到真实的 DOM 上,叫 DOM diff。

6.this.state

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var LikeButton = React.createClass({
getInitialState: function () {
//设定一个初始状态
return { liked: false };
},
handleClick: function (event) {
this.setState({ liked: !this.state.liked }); //修改状态
},
render: function () {
var text = this.state.liked ? "like" : "haven't liked";
return (
<p onClick={this.handleClick}>
{" "}
//onClick触发 You {text} this. Click to toggle.
</p>
);
},
});

this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性

7.表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var Input = React.createClass({
getInitialState: function () {
return { value: "Hello!" };
},
handleChange: function (event) {
this.setState({ value: event.target.value }); //当内容被改变不是初始值的时候,使用event.target.value获取现在值
},
render: function () {
var value = this.state.value; //获取从ReactDom.render()来的值
return (
<div>
<input type="text" value={value} onChange={this.handleChange} />{" "}
//onChange 触发
<p>{value}</p>
</div>
);
},
});

表单为变动的所以用 this.state 并且通过 event.target.value 读取用户输入的值

8.组件生命周期

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
var Hello = React.createClass({
getInitialState: function () {
return {
opacity: 1.0,
};
},

componentDidMount: function () {
this.timer = setInterval(
function () {
var opacity = this.state.opacity;
opacity -= 0.05;
if (opacity < 0.1) {
opacity = 1.0;
}
this.setState({
opacity: opacity,
});
}.bind(this),
100
);
},

render: function () {
return (
<div style={{ opacity: this.state.opacity }}>Hello {this.props.name}</div>
);
},
});

组件的生命周期分成三个状态:
Mounting:已插入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM
React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用did 函数在进入状态之后调用,三种状态共计五种处理函数。

componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
此外,React 还提供两种特殊状态的处理函数。
componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
执行顺序
getInitialState->componentWillMount->已经在页面显示出来了->componentDidMount

组件的 style 属性的设置方式也值得注意,不能写成

1
style = "opacity:{this.state.opacity};";

而要写成

style={ {opacity: this.state.opacity}}
这是因为 React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。

9.Ajax

harmony
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
var UserGist = React.createClass({
getInitialState: function () {
return {
username: "",
lastGistUrl: "",
};
},

componentDidMount: function () {
$.get(
this.props.source,
function (result) {
var lastGist = result[0];
if (this.isMounted()) {
//当处于挂载状态下,才能触发setState
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url,
});
}
}.bind(this)
);
},

render: function () {
return (
<div>
{this.state.username}'s last gist is
<a href={this.state.lastGistUrl}>here</a>.
</div>
);
},
});

ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
document.body
);

isMounted 只有组件还处于挂载状态下,才有 setState 从而更新视图的意义

10 嵌套组件

就是将一个组件放到另一个组件的 render 内

11 事件

如果要注册事件捕获处理程序,应该使用 Capture 事件,例如使用 onClickCapture 处理点击事件的捕获阶段,而不是 onClick
剪贴板事件
onCopy onCut onPaste
键盘事件
onKeyDown onKeyPress onKeyUp
焦点事件
onFocus onBlur
表单事件
onChange onInput onSubmit
鼠标事件
onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit
onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
onMouseMove onMouseOut onMouseOver onMouseUp
触控事件
onTouchCancel onTouchEnd onTouchMove onTouchStart
用户界面事件
onScroll
滚轮事件
onWheel

新 API

React 16.3 来了:带着全新的 Context API
聊一聊我对 React Context 的理解以及应用

12.常用方法

通过要寻找某个节点

Html

1
<h2 ref="tip"></h2>

Js

1
ReactDOM.findDomNode(this.refs.tip);

获取节点的属性值

1
<ImgFigure data="nodeData" /> //ImgFigure是一个组件名

调用

1
<img src={this.props.data}>

更新状态

1
2
3
this.setState({
//更新状态的对象
});

两个组件间互动

控制组件

1
<ImgFigure arrange={this.state.imgsArrangeArr[i]} />

被控组件

1
2
3
4
5
6
7
8
9
var styleObj = {};
//如果props属性中制定了这张图片的位置,则使用
if(this.props.arrange.pos) {
styleObj = this.props.arrange.pos;
}
//直接调用对象
return(
<img style={styleObj}>
)

参考文献:
React
React 是怎样炼成的

13 React-router -路由

1
2
3
4
// 近似于 <Link to={path} state={null}/>
history.pushState(null, path);
// 近似于 <Redirect from={currentPath} to={nextPath}/>
history.replaceState(null, nextPath);

参考文献:
React-router
React-router

14 Redux -状态容器

安装

1
2
3
npm install --save redux
npm install --save react-redux // React 绑定库
npm install --save-dev redux-devtools //开发者工具

关系展示

模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const createStore = (reducer) => {
let state;
let listeners = [];

const getState = () => state;

const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};

const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
}
};

dispatch({});

return { getState, dispatch, subscribe };
};

例子

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
import { createStore } from 'redux';

/**
* 这是一个 reducer,形式为 (state, action) => state 的纯函数。
* 描述了 action 如何把 state 转变成下一个 state。
*
* state 的形式取决于你,可以是基本类型、数组、对象、
* 甚至是 Immutable.js 生成的数据结构。惟一的要点是
* 当 state 变化时需要返回全新的对象,而不是修改传入的参数。
*
* 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)
* 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。
*/
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}

// 创建 Redux store 来存放应用的状态。
// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter);

// 可以手动订阅更新,也可以事件绑定到视图层。
store.subscribe(() =>
console.log(store.getState())
);

// 改变内部 state 惟一方法是 dispatch 一个 action。
// action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1

15 React-Redux

容器组件(Smart/Container Components)—用 Redux
展示组件(Dumb/Presentational Components)—用 React 的 props 就可以


index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import 'core-js/fn/object/assign';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/Main';
import {createStore} from 'redux';
import {Provider} from 'react-redux';
import todoApp from 'stores/reducers.js';

export let store = createStore(todoApp);

// Render the main component into the dom
ReactDOM.render(
<Provider store = {store}>
<App />
</Provider>,
document.getElementById('app')
);

Main.js

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
require('normalize.css/normalize.css');
require('styles/App.css');

import React from 'react';
import {connect} from 'react-redux';
import {store} from '../index'
import {changeStyle} from '../actions/actions.js'

import yeomanImage from '../images/yeoman.png'
//let yeomanImage = require('../images/yeoman.png');

class AppComponent extends React.Component {
constructor(props) {
super(props);
}
handleClick(e){
store.dispatch(changeStyle()) //这个changeStyle是从actions引进的,action其实就是用来修改状态的
}
render() {
//从组件的props属性中导入actions里的方法和变量
const {dispatch,propsStyle} = this.props;

return (
<div className="index">
<img src={yeomanImage} alt="Yeoman Generator" />
{propsStyle}

<div onClick={this.handleClick.bind(this)}>Please edi to get started!</div>
</div>
);
}
}

function select(state) {
return {
//将我们需要的state中的数据绑定到props上
propsStyle:state.propsStyle
}
}

export default connect(select)(AppComponent);
//export default AppComponent;

actions.js

1
2
3
4
5
6
7
export const change = 'change';

export function changeStyle(text) {
return {type:change,
text:text
}
}

reducers.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import {combineReducers} from 'redux';
import {change} from '../actions/actions.js'

function propsStyle(state=0,action) {
switch (action.type){
case change:
return state +1
default: //必须有
return state
}

}
const todoApp = combineReducers({
propsStyle //这个属性名propsStyle必须和函数propsStyle同名 表示通过这个函数处理后的state的值为state.propsStyle connect会将state.propsStyle赋值到props
})
export default todoApp;

参考文献:
解读 redux 工作原理
Redux
史上最全的 Redux 源码分析

Mobx

mobx——rudex 的简单替代品;
awesome-mobx

注意+优质代码

1.将 this 遍历绑定到方法上

harmony
1
2
3
4
5
6
7
8
9
10
11
class A extends React.Component {
constructor() {
super(...arguments);
for (let i in this) {
const method = this[i];
if (method instanceof Function) {
this[i] = this[i].bind(this);
}
}
}
}

其他方法参考

Next

中文教程
渲染子组件的几种方法

通过 Next 搭建集 Next+React+Koa+Mongo 的脚手架

1.先启动 mongo

1
mongod.exe

Ant Design Pro

001-ant design pro 页面加载原理及过程,@connect 装饰器

单向数据流

reducer– 合并所有,并且挂载到prop上,会有独立的namespace

dispatch(action名字)
createAction相当于commit
reducer 相当于 mutations

其中Vuex中有mapState, mapGetters, mapActions, mapMutations方法

vuex里mapState,mapGetters使用详解

← Prev Next →