React官方文档笔记

JSX语法

1.基础

1
const element = <h1>Hello, world!</h1>

2.JSX中嵌入表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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')
);

  1. JSX做表达式

    1
    2
    3
    4
    5
    6
    function getGreeting(user) {
    if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
    }
    return <h1>Hello, Stranger.</h1>;
    }
  2. JSX设置属性

    1
    2
    const element = <div tabIndex="0"></div>;
    const element = <img src={user.avatarUrl}></img>;
  3. JSX包含子元素

    1
    2
    3
    4
    5
    6
    7
    const element = <img src={user.avatarUrl} />; //不包含可直接关闭
    const element = (
    <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
    </div>
    );

6.JSX会转义所有值,所以可以防止XSS

渲染元素

JSX产生的是真实的DOM
当需要更新的时候与之前进行对比,只更新变更的部分
TODO:HRM多入口,官网示例是否更新整个DOM

组件和props

组件让您将UI拆分成独立的可重复使用的部分,并单独考虑每个部分。 在概念上,组件就像JavaScript函数。他们接受任意输入(称为“props”),并返回描述应该在屏幕上显示的React元素。

功能组件和类组件

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

组件渲染

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

当React看到一个表示用户定义组件的元素时,它将JSX属性作为单个对象传递给该组件。我们称这个对象为“道具”。 例如,该代码在页面上显示“Hello,Sara”:

组件开头字母大写

组件组成

只能有一个根组件

组件提取

学会拆分组件

Props只读

纯函数,相同输入输出相同

state和生命周期

ES6的class语法,创建的类组件才有自己的state和生命周期
继承自react

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {date: new Date}
}
componentDidMount() {
//生命周期等函数
}
render() {
return (
<div>
<h2>现在是{this.state.date.toLocaleTimeString()}</h2>
</div>
)
}
}

设置state

  1. 必须调用setState

2.

  • React可以将多个setState()调用批量化为单个更新以实现性能。 因为this.props和this.state可能会异步更新,所以您不应该依靠它们的值来计算下一个状态。
  • 可以异步设置state,setState()接受回调函数,异步更新
    1
    2
    3
    4
    this.setState((prevState, props) => ({
    //在上一轮state设置完成后,再去计算设置state
    counter: prevState.counter + props.increment
    }));
  1. setState是一个浅复制操作

数据单向流

state可以作为子组件的props传递下去

事件

驼峰式事件名
不能通过返回fasle阻止默认事件,必须调用preventDefault

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

在这里,e是一个合成事件。 React根据W3C规范定义了这些合成事件,因此您不必担心跨浏览器的兼容性。请参阅SyntheticEvent参考指南了解更多信息。 当使用React时,您通常不需要调用addEventListener来在创建DOM元素之后添加监听器。而是在元素最初呈现时提供一个监听器。 当您使用ES6类定义组件时,常见的模式是将事件处理程序作为类上的方法。例如,此Toggle组件呈现一个按钮,让用户在“ON”和“OFF”状态之间切换:

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
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
//绑定this,确保函数在实例上呗吊桶
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);

函数绑定问题,因为JS的calss的机制必须在构造器中绑定一次this
一般来说onClck={this.handleClick}这样无参数的绑定事件,必须在构造器中使用绑定

或者使用实验性的语法

  1. 属性初始化语法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class LoggingButton extends React.Component {
    handleClick = () => {
    console.log('this is:', this);
    }
    render() {
    return (
    <button onClick={this.handleClick}>
    Click me
    </button>
    );
    }
    }

2.回调中使用箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures `this` is bound within handleClick
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}

这种语法的问题是每次LoggingButton渲染时都会创建一个不同的回调函数。在大多数情况下,这很好。但是,如果这个回调作为props传递给较低的组件,这些组件可能会进行额外的重新渲染。我们通常建议在构造函数中使用绑定或使用属性初始化器语法来避免这种性能问题。

条件渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);

元素变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}

从组件的render方法返回null不会影响组件生命周期方法的触发。例如,componentWillUpdate和componentDidUpdate仍将被调用

List和Key

遍历输出组件,必须带key,用来优化
键帮助React确定哪些项目已更改,添加或删除。应该给数组中的元素赋予元素一个稳定的身份:
实在不行用索引(但是项目重新排序容易造成性能低下)
key必须唯一

Forms

可控表单

不可控表单

高级指南

JSX深入

JSX

JSX只是语法糖
使用打包器,在使用JSX的时候必须将React引入
使用点.的方式,调用模块内的组件
用户组件必须大写

您不能使用通用表达式作为React元素类型。如果您想使用通用表达式来表示元素的类型,请先将其分配给大写的变量。当您要根据道具渲染不同的组件时,会出现这种情况

1
2
3
4
5
6
7
8
9
10
11
12
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story} />;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}

props in JSX

表达式

1
2
3
4
5
6
7
8
9
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
return <div>{props.number} is an {description} number</div>;
}

props默认为true

扩展运算符

1
2
3
4
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}

Children in JSX

Refs和DOM

  • 管理焦点,文本选择或媒体播放。
  • 触发强制性动画。
  • 与第三方DOM库集成。

    React支持一个可以附加到任何组件的特殊属性。 ref属性采用回调函数,并且在组件被装载或卸载之后立即执行回调。 当在HTML元素上使用ref属性时,ref回调接收底层的DOM元素作为其参数。例如,此代码使用引用回调来存储对DOM节点的引用:

    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
    class CustomTextInput extends React.Component {
    constructor(props) {
    super(props);
    this.focus = this.focus.bind(this);
    }
    focus() {
    // Explicitly focus the text input using the raw DOM API
    this.textInput.focus();
    }
    render() {
    // Use the `ref` callback to store a reference to the text input DOM
    // element in an instance field (for example, this.textInput).
    return (
    <div>
    <input
    type="text"
    ref={(input) => { this.textInput = input; }} />
    <input
    type="button"
    value="Focus the text input"
    onClick={this.focus}
    />
    </div>
    );
    }
    }

当组件挂载时,React将使用DOM元素调用ref回调,并在卸载时将其调用为null。 使用ref回调只是为了在类上设置属性是访问DOM元素的常见模式。首选的方法是在ref回调中设置属性,就像上面的例子一样。甚至有一个较短的写法:
ref = {input => this.textInput = input}

在类组件上使用Ref

1
2
3
4
5
6
7
8
9
10
11
12
class AutoFocusTextInput extends React.Component {
componentDidMount() {
this.textInput.focus();
}
render() {
return (
<CustomTextInput
ref={(input) => { this.textInput = input; }} />
);
}
}

函数组件是不能使用refs的,因为没有实例,但是在原生dom元素上可以使用
this.refs.textInput写法作废

性能优化

编译设置生产环境
chromeTimeline工具

高阶组件

一种设计模式
具体来说,高阶分量是一个获取组件并返回新组件的函数。