完整笔记、Demo地址:https://github.com/EsunR/React-Study
1.用 Create React App 创建一个 React 应用
1 | npx create-react-app my-app |
2.文件结构
App.js 构建网页内容
index.js 引入内容
3.App.js
1 | import React, { Component } from 'react'; |
等价于:
1 | import React from 'react'; |
1 | import React from 'react'; |
4.idnex.js
ReactDOM.reader函数: 挂载一个 <APP />
,节点到DOM中的root
1 | ReactDOM.render(<App />, document.getElementById('root')) |
要使用JSX语法必须引入整个React
5.Fragment占位符
可以隐藏最外层标签
1 | // TodoList.js |
6.数据操作
constructor
构造函数,最优先执行
1 | // TodoList.js |
用
{this.state.KEY}
绑定状态中的数据,这种绑定,对应的值无法被改变1
2
3
4
5// TodoList.js
<div>
<input value={this.state.inputValue}/>
<button>提交</button>
</div>用
onChange
来执行某个方法:
1 | // TodoList.js |
- 以
handleInputChange
方法为入口,调用setState()
方法更改state
中的数据
1 | // TodoList.js |
this指向问题:我们用
this.[METHODS].bind(this)
能解决 [METHODS] 函数中 this 的指向问题,但是这会造成性能上的影响。更优的解决方案是在constructor
部分中添加一个this.[METHODS] = this.[METHODS].bind(this)
,这样性能就会被优化。
在新版的React中
this.setState
推荐改写为传入一个方法,这个方法返回的是一个state对象,如下:
1 | const value = e.target.value // 新版的方法会将setState方法改写为异步,所以要再此保存状态 |
7.渲染数据 (循环渲染)
this.state.[LIST].map
效果相当于 Vue 中的v-for
用{}
包住的是js语句
1 | constructor(props) { |
ES6展开运算符:
假如已定义一个数组
let arr = [1,2,3]
[...arr]
表示为[1,2,3]
我们可以对其进行操作连接赋值操作,如:
let arr2 = [...arr,4,5]
那么,
arr2
被输出后即为[1,2,3,4,5]
8.class属性的处理
用className
替代
1 | <input |
9.不转义字符串
dangerouslySetInnerHTML
取消转义内容
1 | <ul> |
10.for属性的处理
用htmlFor
替代
1 | <label htmlFor="insertArea"></label> |
11.父组件与子组件
父组件中使用子组件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 在TodoList.js中引入TodoItem.js
import TodoItem from './TodoItem'
...
<ul>
{
this.state.list.map((item, index) => {
return (
<div>
<TodoItem />
{/* 在TodoList.js中要调用TodoItem组件的位置用一个 */}
</div>
)
})
}
</ul>
...1
2
3
4
5
6
7
8// TodoItem.js
import React, { Component } from 'react';
class TodoItem extends Component {
render() {
return <div>item</div>
}
}
export default TodoItem;父组件向子组件传值:父组件以标签属性的方式,向子组件传入值。如下,父组件为子组件设置一个
content
属性,属性的值为父组件的item
的值:1
2
3
4// TodoList.js
...
<TodoItem content={item}/>
...子组件通过
this.props.[PROPS_NAME]
来接收数据1
2
3...
<div>{this.props.content}</div>
...父组件向子组件传递父组件的方法(子组件内部触发父组件的方法):
- 用属性传递的方法将函数传递给子组件,同时强行将父组件中的this传递给子组件。
1
2
3
4<!-- TodoList中调用TodoItem组件 -->
<TodoItem
+ deleteItem = {this.handleDelete.bind(this)}
/>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// TodoItem.js ...
render() {
const { index,content } = this.props
return (
<div
onClick={this.handleClick}
key={index}
>
{content}
</div>
)
}
handleClick() {
const { index, deleteItem } = this.props;
deleteItem(index);
}
// ... - 在子组件中使用父组件的方法,同时this指向没问题
12. 通过ES6语法引入props
组件的 this.props 是一个聚合属性,我们可以用ES6的解构赋值来取这些属性到一个变量中
1 | const { index } = this.props; |
13. 关于bind与this指向的问题
1 | <input |
在javascript中,类方法没有指定this,所以使用onChange触发的放法中的this为undefined。
使用bind绑定 handleInputChange 方法 this 的指向为 TodoList 类。
使用 onChange={(e) => { this.handleInputChange(e) }} (需要再此传入合成的事件e)也可以达到同样的效果
JSX在类方法方法中调用组件中的方法,如果带括号方法会在Virtual DOM渲染过 程中就执行,如:
1
onClick={this.handleDeleteItem()}
是不可行的,但是通过bind方法绑定this和参数后在渲染过程中不会立即执行,如:
1
onClick={this.handleDeleteItem.bind(this, index)}
但是假如方法已经在
constructor
中绑定了this,同时方法还需要传入参数,这时候不能直接使用1
onClick={this.handleDeleteItem(index)}
而需要通过剪头函数来传递参数,这时绑定this是非必要的:
1
onClick={() => {this.handleDeleteItem(index)}}