react

React

前言

​ 使用 React的原因:react在进行渲染时,相比于原生html和js来说,效率更高,因为其是对单个组件进行重新渲染,而不是刷新整个页面。

1. React安装

​ 如果想要针对性的使用 react “全家桶”的某些工具或者库,则需要了解每一个工具的作用和下载方式。不像 jQuery,引用到 html 标签里就可以使用,React的使用需要很多工具的配合。因此,对于初学者来说,上手 React 最简便的方式是使用官网推荐的 React 项目构建工具“create-react-app”,通过使用该工具,即可一步完成所有的配置细节,并安装好需要的依赖。

​ 使用 React 所必须的环境是:node.js 和 npm ,其中 npm 在安装node.js 时被同步安装,因此只需要安装 node.js 即可。

​ 安装好 node.js 和 npm 环境之后,打开命令行,输入:

1
npm install -g create-react-app

​ 通过这条指令,我们的计算机上安装了 create-react-app 的命令,课用它来进行 React 项目的搭建:

1
create-react-app hello-world

​ 等待整个“hello-world”项目安装完成即可。安装完成后,使用命令行进入“hello-world”工程文件夹,使用

1
npm start

即可看到效果。

可能遇到的问题

image-20201113080045290

解决方法:

·管理员身份运行 Powershell

·输入set-ExecutionPolicy RemoteSigned,把权限改权限为A

image-20201113080201233

·输入get-ExecutionPolicy,如果此时显示RemotePolicy,即可以正常安装了,重新create即可。

2. JSX

​ JSX即一种可以转换为 Javascript 对象的语法,类似于在 Javascript 里面写 html 标签。

​ DOM元素本身就是一个 Js 对象,包含三个维度的信息:标签类型、属性、子元素,一下引用胡子小书的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
tag: 'div',
attrs: { className: 'box', id: 'content'},
children: [
{
tag: 'div',
arrts: { className: 'title' },
children: ['Hello']
},
{
tag: 'button',
attrs: null,
children: ['Click']
}
]
}

以上的 Javascript 对象代码和以下的 Html 代码所表示的信息是一样的:

1
2
3
4
<div class='box' id='content'>
<div class='title'>Hello</div>
<button>Click</button>
</div>

ReactDOM.render 的作用就是将 JSX 表示的信息构建出真正的 DOM 元素,并放在页面上进行展示。

因此,React 里的 JSX 经历的转换关系为:

​ JSX -> (Babel编译) -> JavaScript 对象 -> (ReactDom.render) -> DOM 元素

3. Render

只要写react.js,就要引入React 和 React.js 的组件父类 Component ,引入以后才能使用 render。使用 render 的时候,必须要返回一个 JSX 元素,有且只有一个,即外层需要有一个

​ JSX 可以插入 JavaScript 表达式,表达式必须写在 {} 里面:

1
2
3
4
5
6
7
render(){
return (
<div>
<p>this is a {1+1} B boy !</p>
</div>
)
}

​ 在 JSX 中不能使用 JavaScript 的关键字给标签加属性,如 class 关键字等,应使用 JSX 的语法,使用如 “className” 等

​ JSX 的 {} 里面也可以放 JSX ,比如通过条件判断语句,返回不同的 JSX。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
renderFunc(word_ac,word_ne){
const flag = false
if (flag){
return word_ne
}
else{
return wrod_ac
}
}

render(){
return(
<div>
)
}

注:自定义的组件使用大写字母作为开头,以和普通的 html 标签作为区分。

4. 事件逻辑处理

4.1 事件监听

​ 与传统 JavaScript 语法不同,React 中使用 onXXX 的形式进行事件绑定,如 “ onClick = {this. handleClick} ”,但是 onXXX 事件绑定只能用在普通标签上,不能用在组件标签上。

4.2 setState & state

​ 当调用 setState 的时候,状态并不会立即改变,React 的机制会将 state 更改后的对象放在一个队列里,之后才会触发组件的状态刷新。

​ 如果想要立即使用 setState 后的状态数据,可以使用函数作为参数,如下:

1
2
3
4
5
6
7
8
handleClick(){
this.setState((prevState)=>{
return {name:"zhangsan"}
})
this.setState((prevState)=>{
return {name:prevState + "'s father"}
})
}

使用函数作为参数,即可利用上一次 setState 的值进行后续操作。

4.3 props

​ 使用原因:使得需要被传入props的组件具有更好的灵活性(通过传入不同的 props ,显示不同的页面或完成不同的响应)

​ props 的传入:在作为标签使用组件的时候把 props 放在标签属性中,props 属性会自动生成键值对对象,不仅能传递字符串、数字、对象、数族,也可以传递函数:

1
2
3
4
5
6
7
8
9
10
11
class Button extends Component {
render () {
return (
<div>
<GoodButton
groups={{Good:'可以', Bad: '不行'}}
onClick={() => console.log('Clicking now!')}/>
</div>
)
}
}

在 GoodButton 内部即可使用传入的 onClick 函数

defaultProps:默认配置

​ 对 props 中的各种属性进行初始配置,如果没有 props 传进来,就使用默认 defaultProps ,如果有props 传进来,则使用新传进来的 props

注:props 一旦传进组件就无法改变,即不能:

1
this.props.name='balabala'

​ 设计原因是为了保证渲染的确定性,如果传进来的 props 都可以改变,则组件的形态和响应会变得不可预测。

​ 但仍然存在改变 props 的解决方案:通过主动重新渲染组件的形式,把新的 props 传入组件即可,即,如果想改变子组件的 props,就使用 setState 改变父组件的 state 值,然后再把新的 props 传到子组件里即可。

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
class Fu extends Component{
constructor(){
super()
this.state = {
atrr1_zi:2,
attr2_zi:5,
}
}

handleClick(){
this.setState({
atrr1_zi:4,
attr2_zi:10,
})
}

render(){
return(
<div>
<Zi attr1_zi={this.state.attr1_zi}
attr2_zi={this.state.attr2_zi}/>
<div>
<button onClick = {this.handleClick.bind(this)}>
修改子组件的 props 属性值
</button>
</div>
</div>
)
}
}

5. 渲染列表数据

​ 由于 JSX 里面可以放任何形式的表达式,因此也可以放存放 JSX 的数组,如:

1
2
3
4
5
6
7
8
9
10
11
render(){
return(
<div>
{[
<span>a </span>
<span>b </span>
<span>c </span>
]}
</div>
)
}

但这种方法进行渲染代码编写量大,最好还是使用循环或者其他方法进行列表数据的渲染,因此。解决方法如下:

(1)循环渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const names = [
{name:'xiao ma'},
{name:'xiao li'},
{name:'xiao yang'}
]
class Boys extends Component{
render(){
const nameArrays = []
for (let name of names){
nameArrays.push(
<div>
<div>姓名:{names.name}</div>
</div>
)
}
return(
<div>{nameArrays}</div>
)
}
}
ReactDOM.render(
<Boys />,
document.getElementById('root')
)

(2)map渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Boys extends Component{
render(){
return(
<div>
{names.map((name)=>{
return(
<div>
<div>姓名:{name.name}</div>
</div>
)
})}
</div>
)
}
}

6. 状态提升

​ 把某组件与其他组件需要进行共享的状态 state ,存放在距离他们最近的公共父节点进行存储,然后通过 props 向子组件进行状态的传递。

​ 当某个状态被多个组件依赖(显示同样的数据或者相关数据)或者影响(状态随着其他组件的改变而改变)的时候,要进行状态提升。

7. 挂载(看作initial,从无到有)

​ 挂载:React.js 对组件进行渲染,并构造相应的 DOM 元素并把它加载到页面 。

注:setState 只能在已经挂载或者正在挂载的组件上进行调用,否则会报错。

8. 更新(看作change,1–>anything)

​ 通过 setState 导致 React.js 需要重新渲染

9. ref 和 React.js 中的 DOM 操作

​ react.js 提供了一系列 onXXX 函数用来处理事件监听,所以不需要手动调用 DOM 的 API ,原本对 DOM 进行操作时需要对 DOM 本身进行操作,例如调用 jQuery 进行事件监听或者页面的重新渲染等。但 React.js 并不能满足所有的 DOM 操作,所以仍需要对 DOM 进行操作,即使用 ref 属性进行挂载

附:this 和 e.target 的区别:

​ js中事件是会冒泡的,所以this是可以变化的,但event.target不会变化,它永远是直接接受事件的目标DOM元素。this 和 e.target 都是DOM对象。

​ React 中的方法,不是通过调用对象的方法来运行的,而是直接通过函数名,因此,如果再调用函数时,函数内部需要使用到 this,则获取不到当前组件。解决方法:再调用函数时使用 bind (this) 将函数0。和组件绑定,即可访问到 this 组件。