最近在学习 React, 并使用 React 做了一个 https://github.com/tian-cai/my-cnode (欢迎大家给我 star,issue, 一起学习讨论进步), 现就记录一下自己的 React 学习笔记.
学习资料
React 中文文档 https://doc.react-china.org/docs/hello-world.html
环境配置
React 的环境配置很麻烦, 刚上手时可以使用 React 脚手架来进行学习. 推荐 Create React App http://github.com/facebookincubator/create-react-app , 或者可以使用我自己写的一个脚手架 https://github.com/tian-cai/my-react .
Jsx 语法
简单来说, 就是可以把 html 和 js 混在一起写, 即 html 代码里面可以有 js 代码, js 代码里面可以有 html. 需要注意的是, 在 html 中遇到 js 代码, 需要加花括号, 而在 js 代码中遇到 html 代码, 需要加圆括号.
创建组件
创建组件有两种方式:
函数创建
- function Hello() {
- return <h1>Hello World</h1>;
- }
ES6 的 class
- class Hello extends React.Component {
- render() {
- return <h1>Hello World</h1>;
- }
- }
不同之处: 函数式组件没有 state, 也不能使用生命周期函数.
注意: 组件名称必须以大写字母开头. 组件的返回值只能有一个根元素.
props 与 state
props
props 是只读的, 组件绝对不能修改自己的 props
state
状态与属性十分相似, 但是状态是私有的, 完全受控于当前组件.
更新状态只有一个办法: 那就是调用 this.setState()
该方法有两种调用方式
- // 接受一个对象为参数
- this.setState({
- loading: false
- })
- // 接受一个函数为参数, 函数的第一个参数为先前的状态, 第二个参数为 props
- this.setState((prevState, props) => ({
- loading: !prevState.loading
- }))
- // 除此之外, this.setState()还接受一个可选的回调函数作为第二个参数
条件加载
React 的条件加载和 JavaScript 中的条件判断一样, 我们可以使用条件运算符 (?:), 与运算符(&&) 等来进行条件加载.
循环加载
我们一般按如下的方式进行循环加载
- const numbers = [1, 2, 3, 4, 5];
- const listItems = numbers.map((number) =>
- <li key={number.toString()}>
- {number}
- </li>
- )
- // 一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串.
- // 通常, 我们使用来自数据的 id 作为元素的 key. 当元素没有确定的 id 时, 你可以使用他的序列号索引 index 作为 key
操作表单
- class NameForm extends React.Component {
- constructor(props) {
- super(props);
- this.state = {value: ''};
- this.handleChange = this.handleChange.bind(this);
- }
- handleChange(event) {
- this.setState({value: event.target.value});
- }
- render() {
- return (
- <div>
- <label>Name:
- <input type="text" value={this.state.value} onChange={this.handleChange} />
- </label>
- </div>
- );
- }
- }
一个简单操作表单元素的例子就是这样. 但是我们会发现这样操作表单有一些小问题. 假如该表单有很多表单元素, 那么我们需要为每一个表单元素注册一个 change 事件的处理函数, 这会让组件显得很臃肿. 不过不用担心, 遇到这种情况我们依然有解决办法. 那就是使用 ref.
关于 Ref
我们可以给 DOM 元素, 类组件添加 ref 属性, 不能给函数式组件添加 ref 属性.
ref 属性接受一个回调函数, 它在组件被加载或卸载时会立即执行.
ref 属性也接受一个字符串,(不过未来可能会废弃, 推荐使用回调)
ref 在加载时回调接收了底层的 DOM 元素或已经加载的 React 实例作为参数, 在卸载时则会传入 null.
- class NameForm extends React.Component {
- constructor(props) {
- super(props);
- }
- render() {
- return (
- <div>
- <label>Name:
- <input type="text" ref={ input => this.input=input }/>
- </label>
- </div>
- );
- }
- }
- // 此时 this.input 指向 inputDOM 元素, 我们可以使用 this.input.value 得到用户的输入.
除可以操作 DOM 之外, ref 还用于触发强制动画, 处理焦点, 文本选择或媒体控制等.
不过我们应该尽量避免使用 ref.
事件处理
React 事件绑定属性的命名采用驼峰式写法.
如果采用 JSX 的语法需要传入一个函数作为事件处理函数, 而不是一个字符串.
不能使用返回 false 的方式阻止默认行为.
事件对象是一个合成对象, 所以不需要担心跨浏览器的兼容性问题.
事件处理程序会成为类的一个方法(类的方法默认是不会绑定 this 的), 所以我们需要手动绑定 this.
手动绑定 this 有两种方法, 一是在类的构造函数中使用 bind 绑定, 二是在 DOM 中使用 bind 绑定.
如果你的事件处理程序是箭头函数, 则不需要手动绑定 this.
向事件处理程序传递参数有两种方法, 一是使用箭头函数, 二是使用 bind 方法.
- <button onClick={(e) => this.confirm(id, e)}>确定</button>
- <button onClick={this.confirm.bind(this, id)}>确定</button>
事件处理程序的最后一个参数为事件对象(该事件对象是 SyntheticEvent 的实例).
如果由于某些原因, 你得使用一些底层的浏览器事件, 只需用 nativeEvent 的属性就能得到原生的事件对象.
DOM 属性
React 实现了一套与浏览器无关的 DOM 系统, 兼顾了性能和跨浏览器的兼容性.
在 React 中, 所有的 DOM 特性和属性都是小驼峰命名法命名.(aria - 和 data - 属性除外)
一些不同之处:
使用 className 属性指定一个 CSS 类.
style 属性接受一个键为小驼峰命名法命名的 javascript 对象作为值.(注意: 样式属性不会自动补齐前缀的, 浏览器前缀除了 ms 以外, 都应该以大写字母开头)
onChange 函数, 无论 form 表单何时发生变化, 这个事件都会被触发.
dangerouslySetInnerHTML 函数是替换浏览器 DOM 中的 innerHTML 接口的一个函数.
生命周期
组件的生命周期大致分为三个阶段
装配阶段(这些方法会在组件实例被创建和插入 DOM 中时被调用)
- constructor()
- componentWillMount()
- render()
- componentDidMount()
更新阶段(属性或状态的改变会触发一次更新. 当一个组件在被重渲时, 这些方法将会被调用)
- componentWillReceiveProps(nextProps)
- shouldComponentUpdate(nextProps, nextState)
- componentWillUpdate(nextProps, nextState)
- render()
- componentDidUpdate(prevProps, prevState)
卸载阶段(当一个组件被从 DOM 中移除时, 该方法被调用)
componentWillUnmount()
除此之外, 组件还有一个方法 forceUpdate(), 调用 forceUpdate()将会导致组件的 render()方法被调用, 并忽略
- shouldComponentUpdate()
- .
注意点:
若
shouldComponentUpdate()
返回 false,render()函数将不会被调用.
当为一个 React.Component 子类定义构造函数时, 你应该在任何其他的表达式之前调用 super(props). 否则, this.props 在构造函数中将是未定义, 并可能引发异常.
defaultProps 可以被定义为组件类的一个属性, 用以为类设置默认的属性.
常见问题
使用 React 开发必须使用 JSX 语法吗?
答: JSX 并不是必须的. 每一个 JSX 元素都只是
React.createElement(component, props, ...children)
的语法糖.
因此, 任何时候你用 JSX 语法写的代码也可以用普通的 JavaScript 语法写出来.
使用 React 开发必须使用 ES6 + 语法吗?
答: ES6 + 并不是必须的.
性能优化
一般做法
使用工具来分析性能瓶颈.
尝试使用优化技巧解决这些问题.
使用工具测试性能是否确实有提升.
具体实施
很大程度上, React 的性能优化就是干掉无谓的渲染.
我们可以重写
shouldComponentUpdate()
方法, 对 this.props 与 nextProps 进行比较, 对 this.state 与 nextState 进行比较, 如果有改变, 则返回 true, 否则返回 false.
组件继承 React.PureComponent.
使用
pure-render-decorator
装饰器.
使用
- react-addons-shallow-compare
- .
使用 immutable.js.
性能分析工具
- React.addons.Perf
- react-perf-tool
未完待续....
来源: http://www.jianshu.com/p/ade69fe17cd6