React 学习笔记 - 基础篇

首先声明在这里看到的很多内容都是官方文档中提到的,当然也加入了一些自己的总结

在 react 中一切都是 js,我们使用 jsx 来渲染组件
React 在渲染所有输入内容之前默认会进行转义,可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击。

JSX 表示对象

Babel 会将 JSX 转义成一个名为 React.createElement() 函数调用。

以下写法相等:

jsx
1
2
3
4
5
6
7
8
9
10
const element = (
<h1 className="greeting">
Hello, World!
h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
)
js
1
2
3
4
5
6
7
8
//React.createElement()会预先执行一些检查,以帮助你编写无错代码,实际上 创建了一个这样的对象:
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};

这些对象被称为 “React 元素”。它们描述了你希望在屏幕上看到的内容。React 通过读取这些对象,然后使用它们来构建 DOM 以及保持随时更新

所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

State 与 生命周期

对于 State 我们应该正确的使用 setState ({}) 对 State 的数据进行更新

我们不能直接修改 State

错误:this.state.comment = 'Hello';
正确:this.setState({comment: 'Hello'});

构造函数是唯一一个可以给 State 直接赋值的地方,在其他地方直接修改的时候不会更新 dom

State 的更新可能是异步的

出于性能考虑,React 可能会把多个 setState () 调用合并成一个调用
由于 this.props 和 this.state 可能会异步更新,所以不可以依赖他们的值来更新状态
解决上述问题的办法是将 setState () 的参数设置为一个函数,而不是一个对象,这个函数用上一个 state 作为第一个参数,将被应用的 props 作为第二个 参数

js
1
2
3
this.setState((state, props) => ({
counter: state.counter + props.increment
}));

State 的更新会被合并

当你调用 setState () 的时候,React 会把你提供的对象合并到当前的 state。

数据是向下传递的(自上而下、单向)

组件可以将 state 作为 props 向下传递到它的子组件中

生命周期

componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行

完整生命周期:

  • 卸载挂载过程:
    • constructor()
    • componentWillMount()
    • componentDidMount()
    • componentWillUnmount()
  • 更新过程:
    • componentWillReceiveProps(nexrProps)
    • shouldComponentUpdate(nextProps, nextState)
    • componentWillUpdate(nextProps, nextState)
    • componentDidUpdate(prevProps, prevState)
    • render()
  • React 新增生命周期(替代上述两个周期函数):
    • getDerivedStateFromProps(nextProps, prevState)
    • getSnapshotBeforeUpdate(prevProps, prevState)

事件处理

React 中事件处理与 DOM 中的区别:

React 事件的命名方式采用小驼峰,而不是纯小写

使用 JSX 语法的时候需要传入一个函数进行处理,而不是传入一个字符串

在 React 中不允许使用返回 false 的方式阻止默认行为,可以显式地使用 preventDefault, 例如:

jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//DOM:
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
//React:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}

在 javaScript 中 class 不会默认绑定 this,如果不进行手动绑定,那么当在 handleClick 中使用 this 时,this 为 undefined
手动绑定方法:

  1. function.bind(this, arguments)
  2. (e) => this.function(arguments, e)

条件渲染

在 React 中使用条件判断时可以使用 if 语句或者三目运算进行判定
可以使用 条件 && 视图 的方式进行条件判断
当需要进行条件隐藏时,可以在 render 中返回一个 null,组件就会隐藏, return null; 时不会对元素进行渲染,且并不会影响生命周期

列表与 key

  1. 渲染多个组件:

    jsx
    1
    2
    3
    4
    5
    const numbers = [1, 2, 3, 4, 5]
    const listItems = numbers.map(item => <li>{item}li>)
    ReactDOM.render(
    <ul>{listItems}</ul>, document.getElementById('root')
    );
  2. 封装成基础列表组件

    • 使用这种方式时要给每一个列表元素分配一个 key,key 在兄弟节点之间必须唯一
    • key 帮助 React 识别哪些元素改变了,迫不得已没有唯一值时可以使用索引 index 当作 key

表单

受控组件

在 HTML 中表单一般都是自己维护自己的 state。并且根据用户的输入进行更新,但是在 React 中可变状态(mutable state)都存储在 state 中,并且只能通过使用 setState () 进行更新。

我们可以把上述两种结合起来,让 React 的 state 成为唯一的数据源,这样就可以在 React 的组件中对用户输入过程中表单发生的操作进行控制,被 React 这样控制的组件叫做受控组件

  • 可以对输入组件的 value 与 React 的 state 值进行绑定,对组件的 onChange 事件进行绑定,对表单的 onSubmit 事件进行绑定
  • 文件的 input 标签,由于 value 值是只读的,所以 <input type="file"> 是一个非受控组件
  • 当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作。
    jsx
    1
    2
    3
    4
    // 这里使用了 ES6 计算属性名称的语法更新给定输入名称对应的 state 值
    this.setState({
    [name]: value
    });
    在受控组件上指定 value 的 prop 会阻止用户更改输入。如果你指定了 value,但输入仍可编辑,则可能是你意外地将 value 设置为 undefined 或 null。

当然其实 React 官方也提供了更方便的非受控组件方式,,在之后的学习中也会逐步跟进。

状态提升

状态提升在官方文档中给出的定义是:当多个组件需要反应相同的变化数据时,我们可以将共享状态提升到最近的共同父组件中去

在官方文档提供的华氏度与摄氏度即时转换的示例中,将子组件中 input 的 value 值与父组件传过来的 props 中的值进行绑定,在 input 的 onChange 事件中绑定了父组件的温度转换事件,将所有的值都传输给父组件,由父组件中定义的转换函数转换后,绑定在 state 的值中,随后再将值传输给父组件,实现了状态提升

我在这里说的可能有些复杂,具体示例可以查看官方文档下文中会有内嵌的官方文档连接

在 React 的应用中,任何的数据都应该只有一个相对应的” 唯一数据源 “

组合与继承

  • 包含关系:
    • this.props.children 可以用来获取放入标签的 dom 元素,然后直接将这些元素引入到 render 中,等同于 Vue 中的 slot 插槽
  • 特例关系:
    • 以 Dialog 为例,我们可以手动封装一个 Dialog 组件,将 title 与 message 都封装成组件属性,通过传入属性的方式进行组合复用。

React 哲学

建议查看官方描述 React 哲学

个人感觉很有帮助,会提升代码的规范意识,对编写架构都很有帮助。

总结

用了两周时间第一次学完了 React.js 的基础知识。

在学习完第一遍 React 的基础知识以后我深刻体会到了为什么 React 现在依然会是很多大厂的首选语言,从生态上来说的确时 Vue 需要用时间来填补的,但是 Vue 对比 React 在有些方面例如插槽、数据传输等方面要更加简便易操作,各有千秋,各有好坏,对于 React 我的认知还很少,还会更多的了解学习 FaceBook 对 React 的发展方向,以及了解最新的技术模式,后续也会跟进更新相关笔记