React基础总结

React简介

React 应用程序的组成部分: 元素和组件

元素

JSX语法介绍

我们建议使用 JSX 来编写你的 UI 组件。每个 JSX 元素都是调用 React.createElement() 的语法糖。一般来说,如果你使用了 JSX,就不再需要调用以下方法。

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
const element = <h1>Hello, world!</h1>;
JSX 是JavaScript 的语法扩展,它具有 JavaScript 的全部功能。

React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。

React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离。

React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。它还可以使 React 显示更多有用的错误和警告消息。

在 JSX 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式。例如,2 + 2,user.firstName 或 formatName(user) 都是有效的 JavaScript 表达式.下面是个简单的例子
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}

const user = {
firstName: 'Harper',
lastName: 'Perez'
};

const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);

ReactDOM.render(
element,
document.getElementById('root')
);
我们将一个js表达式插进jsx语法中,并实现了'Harper Perez'
如果是在Vue项目中,我们可以使用computed计算属性进行这样的操作

注意:我们在定义element变量的时候,使用的是()的形式。原因是:我们建议将内容包裹在括号中,虽然这样做不是强制要求的,但是这可以避免遇到自动插入分号陷阱。
jsx也是一个表达式,意味着可以进行函数渲染
1
2
3
4
5
6
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
JSX的特定属性
1
2
3
const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}></img>;
// ""和{}只能同时使用一个,对于同一属性不能同时使用这2种符号

警告:

因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。

例如,JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex

JSX 表示对象

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

以下两种示例代码完全等效:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);

-------------------------------------简化编译---------------------------------
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};

react元素不可变性

React 元素是不可变对象。一旦被创建,你就无法更改它的子元素或者属性。一个元素就像电影的单帧:它代表了某个特定时刻的 UI。

React DOM 会将元素和它的子元素与它们之前的状态进行比较,并只会进行必要的更新来使 DOM 达到预期的状态。

组件

组件也可以被定义为可被包装的函数

定义组件最简单的方式就是编写 JavaScript 函数:

1
2
3
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

该函数是一个有效的 React 组件,因为它接收唯一带有数据的 “props”(代表属性)对象与并返回一个 React 元素。这类组件被称为“函数组件”,因为它本质上就是 JavaScript 函数。

你同时还可以使用 ES6 的 class 来定义组件:

1
2
3
4
5
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}

上述两个组件在 React 里是等效的

自定义函数组件

React 元素也可以是用户自定义的组件:

1
const element = <Welcome name="Sara" />;

当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)转换为单个对象传递给组件,这个对象被称之为 “props”。

例如,这段代码会在页面上渲染 “Hello, Sara”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
// 分析步骤:
1. 我们调用ReactDom.render()函数,并传入jsx语法变量elemnnt作为参数
2. React调用Welcome组件, 并将{name: 'Sara'}作为props传入
3. Welcome组件将 jsx对象作为返回值
4. React DOM将DOM进行对比更新

注意: 组件名称必须以大写字母开头,React 会将以小写字母开头的组件视为原生 DOM 标签

所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。–类似于Vue的单向数据流,子组件不能修改父组件的传值,只能通过触发父组件的事件进行修改

​ 所以我们只能修改组件内部的数据state,它 允许 React 组件随用户操作、网络响应或者其他变化而动态更改输出内容。 —–对比Vue的data和props

正确使用state
  • 不要直接修改state—使用setState({})

    • 构造函数是唯一可以给 this.state 赋值的地方
  • state的更新可能是异步的

    • 出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用

    • 因为 this.propsthis.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。

      • 1
        2
        3
        4
        5
        6
        7
        8
        9
        // Wrong
        this.setState({
        counter: this.state.counter + this.props.increment,
        });
        要解决这个问题,可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:
        // Correct
        this.setState((state, props) => ({
        counter: state.counter + props.increment
        }));
  • state的更新会被合并

    • 当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state
    • 这就意味着:当你的state对象里面有多个值时,你多次调用setState({someKeys:xx})这里的对象合并是浅合并,setState方法保留了其他未被重置的属性,但是完全替换了someKyes
将函数组件转换为class组件

———–需要注意的是,如果是通过compoent={}的形式,需要在constructor(props)进行传递

  1. 创建一个同名的 ES6 class,并且继承于 React.Component

  2. 添加一个空的 render() 方法。

  3. 将函数体移动到 render() 方法之中。

  4. render() 方法中使用 this.props 替换 props

  5. 删除剩余的空函数声明

    1
    2
    3
    4
    5
    6
    7
    8
    // React.Component 是使用 ES6 classes 方式定义 React 组件的基类
    export default class Some extends React.Component{
    render() {
    return (
    <div>do some thing</div>
    )
    }
    }

    ———————通过以下方式将 props 传递到父类的构造函数中:

    1
    2
    3
    4
    constructor(props) {
    super(props);
    this.state = {date: new Date()};
    }

事件处理

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。—使用表达式

一般情况下,传入没有调用的函数都会丢失this指向,解决办法是使用Function.prototype.bind()或者是使用箭头函数,亦或者是class fields进行解决

函数传入参数

在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:

1
2
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

循环渲染需要带key

React 支持 key 属性。当子元素拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素

Vue的key属性也是做同样的事情,进行diffing算法运算

react.PureComponet

React.PureComponent 中的 shouldComponentUpdate() 将跳过所有子组件树的 prop 更新。因此,请确保所有子组件也都是“纯”的组件。

需要注意的小细节

  • autoFocus一定要配合tabIndexReact
  • 来使用
  • constructor要配置super使用
  • 渲染的时候要使用标签的形式进行渲染
  • 在组件内部的dom元素中添加事件

组件渲染时的this问题

react 在render({this.state.xx})拿值是可以,但是在执行函数的时候却为undefined的原因?
—因为js是单线程事件型语言,当遇到函数或者定时器等异步操作时,会先向下执行,等事件触发,或者有空闲的时候再执行异步操作–那个时候,上下文已经丢失,所以this执行就已经丢失了
———–办法就是,

  1. 在dom渲染的时候,手动绑定上下文{this.事件名.bind(this)}
  2. 使用() => {利用箭头函数的特性绑定this}

组件的基本生命周期

以类定义的组件,都有一样的生命周期

  • constructor() {}
  • componentWillMount() {} //加载前,可以进行拿取数据
  • render() {}
  • componentDidMount() {} //页面加载完成
  • if(进行更新state)————–
    • componentWillUpdate() {} // 可以进行数据的验证
    • render()
    • compoentDidUpdate() //更新完成

有一个this.forceUpdate() –强制更新DOM

shouldCompoentUpdate() {return false} —不进行更新 — 控制componentWillUpdate的执行

————————————————————特殊的——————————————————

componentWillUnmount()—-:通过非React提供的方式注册的事件,通常需要在这个方法中注销事件,以及该组件中使用的计时器,也需要在这里清除!!!

setState的作用

  1. 可以用来更新数据
  2. 会自动地调用render()

父子组件中遇到的问题

父组件调用了render方法,则子组件必定会调用render方法。子组件调用render方法,则父组件不会调用render方法

父组件向子组件传值,是将父组件的数据或者方法作为子组件的属性值进行传递

​ 子组件通过this.props.属性进行获取—(如果是通过函数的方式,则通过形参的方式进行获取)

文章目录
  1. 1. React简介
    1. 1.1. 元素
      1. 1.1.1. JSX语法介绍
        1. 1.1.1.0.0.1. jsx也是一个表达式,意味着可以进行函数渲染
        2. 1.1.1.0.0.2. JSX的特定属性
        3. 1.1.1.0.0.3. JSX 表示对象
  2. 1.1.2. react元素不可变性
  • 1.2. 组件
    1. 1.2.0.0.0.1. 自定义函数组件
    2. 1.2.0.0.0.2. 正确使用state
    3. 1.2.0.0.0.3. 将函数组件转换为class组件
  • 1.3. 事件处理
    1. 1.3.0.0.0.1. 函数传入参数
  • 1.3.1. 循环渲染需要带key
  • 2. react.PureComponet
  • 3. 需要注意的小细节
    1. 3.1.
      1. 3.1.0.1. 组件渲染时的this问题
      2. 3.1.0.2. 组件的基本生命周期
  • 3.2. setState的作用
  • 3.3. 父子组件中遇到的问题
  • |