概述
对 React 的基础知识作一个总结。
详述
Hello World
1 | ReactDOM.render(<h1>Hello, world!</h1>, document.getElementById('root')); |
JSX
不是新事物,而是一种语法糖,Babel 转译后调用 React.createElement() ,因此具有 JavaScript 的全部功能。
类似一些前端模板引擎的语法,JSX 中用大括号{}
来包裹 JavaScript 变量和表达式。
属性用 camelCase 命名法,例如 class-className、tabindex-tabIndex。属性值如果是字符串值直接用引号,如果是表达式用大括号。
1 | // 引用变量 |
元素
元素是构成 React 应用的最小砖块。React 元素是不可变对象。一旦被创建,你就无法更改它的子元素或者属性。一个元素就像电影的单帧:它代表了某个特定时刻的 UI。更新 UI 唯一的方式是创建一个全新的元素,并将其传入 ReactDOM.render()。
组件
组件是独立可复用的代码片段,由一个或多个元素组成,是根据 UI 需要对元素的进一步抽象封装,因此可以自由的拆分组合使用,就像使用 HTML 元素那样。形式上分为函数组件和 class 组件,一般不需要维护私有状态 state 的,推荐用函数组件。
1 | // 函数组件 |
Props 与 State
组件可以把它的 state 作为 props 向下传递到它的子组件中,而子组件不能直接修改 props,只能通过事件通知父级修改;state 是记录自身状态的私有属性,可以修改。这种数据流向是“自上而下”的,一般称为单向数据流。
props.children 可以理解为插槽。
state 修改需要注意三点:
- 不要直接修改 State,而是调用
setState()
方法; - State 的更新可能是异步的,因此不能依赖当前状态去更新下一个状态;
- State 的更新会被合并。
生命周期
组件的生命周期图谱如下:
通常在 constructor 中进行 state 等初始化工作,componentDidMount 中进行 DOM 渲染完成后的工作,componentWillUnmount 中进行资源释放工作。示例如下:
1 | class Clock extends React.Component { |
更多生命周期介绍请参考官方文档。
事件处理
React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
1 | <button onClick={activateLasers}>Activate Lasers</button> |
注意事项:
不能通过放回 false 的方式组织默认行为,而是要显式的使用 preventDefault
1 | <!-- 错误 --> |
1 | // 正确 |
回调函数中的 this 绑定问题
因为传入的回调函数在调用的时候上下文(context)已经不是该组件实例本身,所以想要 this 指向该组件实例本身,需要传入的时候显式的指定上下文。
bind 用法:
1 | class Title extends Component { |
class fields 用法(Create React App 默认启用此语法):
1 | class LoggingButton extends React.Component { |
箭头函数用法:
1 | class LoggingButton extends React.Component { |
条件渲染与列表
JSX 只是 JavaScript 的语法糖,可以完全使用 JavaScript 特性。对于列表渲染,需要在加上 key,值只要保证兄弟节点间唯一即可。
表单
受控组件
表单数据由 React 组件来管理。具体实现形式如下:
1 | class NameForm extends React.Component { |
作为受控组件,<textarea>
和 <select>
元素赋值形式做了调整,改成与 input 相同,如下:
1 |
|
注意点:
文件 input 标签为非受控组件<input type="file" />
。
设置了 value 值的受控组件是不可编辑的,若仍然可编辑,那可能是 value 值为 undefined 或 null。
非受控组件
将在高级部分讲解,官方文档。
状态提升
通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
组合 vs 继承
React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。
包含关系
概念同 Vue 的插槽
1 | // 匿名 |