0%

尚硅谷React笔记详解

React 基础

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
**使用jsx创建虚拟DOM
1.<script type="text/javascript" src="../js/babel.min.js"></script> -> 引入babel,用于将jsx转为js
const VDOM = (
<h1 id="title">
<span>Hello,React</span>
</h1>
)
/* 此处一定不要写引号,因为不是字符串 下面这些代码经过babel翻译为js原生代码的写法*/
babel.js的作用
1.浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
2.只要用了JSX,都要加上type="text/babel", 声明需要babel来处理

React面向组件编程:
1. 组件名必须首字母大写
2. 虚拟DOM元素只能有一个根元素
3. 虚拟DOM元素必须有结束标签

**使用js创建虚拟DOM
2.<script type="text/javascript" > //原生js
const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello,React'))//标签名 标签属性 标签内容

3.关于虚拟DOM:
1.本质是Object类型的对象(一般js对象)
2.虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。
3.虚拟DOM最终会被React转化为真实DOM,呈现在页面上。
一定注意区分:【js语句(代码)】与【js表达式】
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
下面这些都是表达式:
(1). a
(2). a+b
(3). demo(1)
(4). arr.map()
(5). function test () {}
2.语句(代码):
下面这些都是语句(代码):
(1).if(){}
(2).for(){}
(3).switch(){case:xxxx}
4.jsx语法规则:
1.定义虚拟DOM时,不要写引号。
2.标签中混入JS表达式时要用{}。
3.样式的类名指定不要用class,要用className。
4.内联样式,要用style={{key:value}}的形式去写。
5.只有一个根标签 就是说h2只能一个,如果要两个就得加一个div [div包裹很不情愿,后期有办法处理,可以通过Frangment标签.]
6.标签必须闭合
7.标签首字母
(1).若小写字母开头,则将该标签转为html中同名元素(都是小写的),若html中无该标签对应的同名元素,则报错。good会报错
(2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。GOOD
5.创建函数式组件
**函数名大写 函数必须有返回值
function MyComponent(){
console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式 禁止这种自定义的函数this指向window
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
**渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test')) //标签必须闭合<MyComponent/>
/*
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?)
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
6.创建类式组件
class MyComponent extends React.Component {
render(){
//不用写构造器 写render 返回值也必须写 继承React.Component也必须写
//render是放在哪里的? —— 组件的的原型对象上,供实例使用。
//render中的this是谁?—— 组件的实例对象 <=> MyComponent组件实例对象。
console.log('render中的this:',this);//结果MyComponent的实例对象
return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test')) //const my = new MyComponent()
/*
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
7.类式组件可以自定义方法————要用赋值语句的形式+箭头函数,否则this指向为undefined。
类中可以直接写赋值语句,就类似于在实例自身追加一个属性名
因为类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined。
函数式不知道方法只能支持赋值语句。

8.方法的定义在render外部,解构赋值是在render内部

9.严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!React不认这样的更改//this.state.isHot = !isHot //这是错误的写法

10.对标签属性进行类型、必要性的限制放到类里 如果Person有初始化状态,就这样写state = {}在这里面写就可以了。
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
}

Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
11.用函数式创建组件,由于没有实例函数因此没有this。无法使用state和refs这两个属性 但是props属性例外。
function Person (props){
const {name,age,sex} = props **** C参数全部都在props
return (
<div>你好</div>
)
}

12. 对标签属性进行类型、必要性的限制 类的关键字 static ***可以当做简写形式
static propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串 把这两个东西放进一个打括号里
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
}
13.渲染类组件标签的基本流程:
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
14. 强烈注意
* 组件中render方法中的this为组件实例对象
** 组件自定义的方法中this为undefined,如何解决?
a) 通过函数对象的bind()强制绑定this
b) 箭头函数
*** 状态数据,不能直接修改或更新
15.ref的三种形式
* 字符串形式的ref <input ref="input1"/>
const {input1} = this.refs//调用的时候要加了s
这种字符串形式的ref马上要被废弃,因为string类型的refs存在一些效率上的问题。

** 回调形式的ref <input ref={(c)=>{this.input1 = c}}
这么写的结果就是把ref当前所处的节点挂在了实例自身上,并且取了个名字叫input1
const {input1} = this//取input1就直接从实例自身取就可以了,直接写this即可

*** createRef创建ref容器·myRef = React.createRef() <input ref={this.myRef}/>
使用直接this.myRef.current.... 即可
这是最推荐的 但是也是最繁琐的 因为有多少个ref就要创建多少个myRef
React.createRef调用后可以返回一个容器,该容器可以存储**被ref所标识的节点**,该容器是“专人专用”的
ref所在节点input被放到了myRef的容器里

16.回调函数的特点: 1、你定义的函数 2、你没调用 3、这函数最终执行了
17.事件的处理;
(1).通过onXxx属性指定事件处理函数(注意大小写)
a.React使用的是自定义(合成)事件, 而不是使用的原生DOM事件(onClick) —————— 为了更好的兼容性
b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了高效
(2).通过event.target得到发生事件的DOM元素对象 ——————————不要过度使用ref
<button onClick={this.showData}>点我提示左侧的数据</button>
//展示左侧输入框的数据
showData = (event)=>{//发生事件的事件源
console.log(event.target);**输出的是<button>点我提示左侧的数据</button>
alert(this.myRef.current.value);
}
失去焦点那边可以省略ref 因为发生事件的元素正好是你操作的元素,就可以省略
点击按钮提示那个不能省略 因为给的是button加的Click事件,但是要拿input的数据

18.受控组件:输入类的DOM随着你的输入把东西维护到状态里去,等需要用的时候直接从状态里取出来
handleSubmit = (event)=>{
event.preventDefault() //阻止表单提交
const {username,password} = this.state//拿到的真正的值 下面就不用.value
alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
}
<form onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveUsername} type="text" name="username"/>
密码:<input onChange={this.savePassword} type="password" name="password"/>
<button>登录</button>
</form>
非受控组件:现用现取
const {username,password} = this //获取那两个节点
//对输入类的DOM 现用现取
alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`)
<form onSubmit={this.handleSubmit}>
用户名:<input ref={c => this.username = c} type="text" name="username"/>
密码:<input ref={c => this.password = c} type="password" name="password"/>
<button>登录</button>{/*点了登陆就触发那个表单提交*/}
</form>
19.高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
1.若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
2.若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
常见的高阶函数有:Promise、setTimeout、arr.map()等等

使用函数柯里化:不加小括号是因为把一个函数作为onChange回调,加了小括号我把这个函数返回值交给onChange回调,下面写的返回值就是 一个函数 返回的就是函数。
onChange={this.saveFormData('username')
saveFormData = (dataType)=>{ //dataTye就是传的东西
return (event)=>{
this.setState({[dataType]:event.target.value}) //函数作为onchange的回调是返回值作为回调
}
}
//onchange要的就是一个函数 现在给的就是一个函数 onchange回调执行的时候 react帮你调用然后传入event

不使用函数柯里化:onChange={event => this.saveFormData('username',event) } 直接传一个函数
//保存表单数据到状态中 同时接到dataType event
saveFormData = (dataType,event)=>{
this.setState({[dataType]:event.target.value}) //因为上面传的是一个函数,因此这里就不用返回一个函数
}

image-20211207195755851

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
20.组件生命周期理解
1. 组件从创建到死亡它会经历一些特定的阶段。
2. React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
3. 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

**挂载时**
constructor:组件构造函数,常用于初始化组件state,以及对组件内响应方法的绑定

componentWillMount:在第一次渲染前的钩子函数,也常用于初始化state,在新版生命周期中已弃用

render:组件渲染函数,返回一个jsx元素,用于显示真实DOM中的元素

componentDidMount:在组件挂载后执行,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

**更新时**
compontentWillReceiveProps:
在父组件更新时会触发此函数,在此函数中可以根据props是否变化来setState,并且在此函数中的 setState不会再次触发子组件的 render

shouldComponentUpdate:/控制组件更新的“阀门” 应不应该更新状态
在setState和compontentWillReceiveProps后会触发此函数,可以在此函数中编写相关方法判断是否继续render,相当于一个自定义 的diff函数

componentWillUpdate:组件的props或state发生改变后,render之前触发,在第一次组件挂载时不会触发此函数 ***弃用

render

componentDidUpdate:在组件的props或state更新完并执行完render后触发

**卸载时**
componentWillUnmount:在组件卸载或者销毁之前触发 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

其中componentWillMount、compontentWillReceiveProps、componentWillUpdate在新版生命周期中均已被弃用

image-20211207212028192

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
新版生命周期:
1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
1. constructor()
2. getDerivedStateFromProps
3. render()
4. componentDidMount() =====> 常用*****
一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
1. getDerivedStateFromProps
2. shouldComponentUpdate()
3. render() ******必须要用
4. getSnapshotBeforeUpdate
5. componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
1. componentWillUnmount() =====> 常用***
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

新版生命周期:中将较于旧版,增加了两个新的钩子,分别是getDerivedStateFromProps、getSnapshotBeforeUpdate,
并弃用了componentWillMount、compontentWillReceiveProps、componentWillUpdate这三个钩子

static getDerivedStateFromProps(nextProps, prevState)
若state的值在任何时候都取决于props那么可以使用getDerivedStateFromProps 横跨挂载和更新

getDerivedStateFromProps为静态函数,传入参数为nextProps、prevState。其中,nextProps为将要更新的props,prevState 为上一个状态,可根据传入的props,以及过去的state来增加限制条件,防止无用的更新

getSnapshotBeforeUpdate(prevProps, prevState)
在更新之前获取快照 在组件更新DOM前调用,可以在此DOM更新前捕获一些页面信息(例如滚动位置),此生命周期返回的值会作为参数传入 componentDidUpdate

key的作用
经典面试题:
1). react/vue中的key有什么作用?(key的内部原理是什么?)
2). 为什么遍历列表时,key最好不要用index?

1. 虚拟DOM中key的作用:
1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。

2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】,
随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:

a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实 DOM

b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
根据数据创建新的真实DOM,随后渲染到到页面

2. 用index作为key可能会引发的问题: (this.setState({persons:[p,...persons]})这个就是破坏了顺序性操作)
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。

2. 如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。

3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
仅用于渲染列表用于展示,使用index作为key是没有问题的。

3. 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果确定只是简单的展示数据,用index也是可以的。

慢动作回放----使用index索引值作为key

初始数据:
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
初始的虚拟DOM:
<li key=0>小张---18<input type="text"/></li>
//这里的input框给小王用了 所以小张残留的信息给了小王了 因此会产生错误DOM更新,界面有问题
<li key=1>小李---19<input type="text"/></li>

更新后的数据:
{id:3,name:'小王',age:20},
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
更新数据后的虚拟DOM:
<li key=0>小王---20<input type="text"/></li>
<li key=1>小张---18<input type="text"/></li>
<li key=2>小李---19<input type="text"/></li>

-----------------------------------------------------------------

慢动作回放----使用id唯一标识作为key

初始数据:
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
初始的虚拟DOM:
<li key=1>小张---18<input type="text"/></li>
<li key=2>小李---19<input type="text"/></li>

更新后的数据:
{id:3,name:'小王',age:20},
{id:1,name:'小张',age:18},
{id:2,name:'小李',age:19},
更新数据后的虚拟DOM: 因为把小王放在第一个了 所以遍历的时候小王是第一个
<li key=3>小王---20<input type="text"/></li>
<li key=1>小张---18<input type="text"/></li>
<li key=2>小李---19<input type="text"/></li>

React应用(基于React脚手架)

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
1.使用脚手架开发的项目的特点: 模块化, 组件化, 工程化
2.react脚手架项目结构:
(1).index.html -------- 主页面
(2).App.js --------- App组件
(3).index.js ------- 入口文件
3.功能界面的组件化编码流程:
1. 拆分组件: 拆分界面,抽取组件
2. 实现静态组件: 使用组件实现静态页面效果
3. 实现动态组件
3.1 动态显示初始化数据
3.1.1 数据类型
3.1.2 数据名称
3.1.2 保存在哪个组件?
3.2 交互(从绑定事件监听开始
4.document.getElementById('root')//为什么能找到public里的index.html ,这是因为React底层帮忙写好的。
5.状态在哪里,操作状态的方法就在哪里。

6.常用的ajax请求库:
1. jQuery: 比较重, 如果需要另外引入不建议使用
2. axios: 轻量级, 建议使用
1) 封装XmlHttpRequest对象的ajax
2) promise风格
3) 可以用在浏览器端和node服务器端

7.SPA的理解
1. 单页Web应用(single page web application,SPA)。
2. 整个应用只有一个完整的页面。
3. 点击页面中的链接不会刷新页面,只会做页面的局部更新。
4. 数据都需要通过ajax请求获取, 并在前端异步展现。

路由

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
8.路由的理解
1. 一个路由就是一个映射关系(key:value)
2. key为路径, value可能是functioncomponent

9.路由分类
1. 后端路由:
(1) 理解: valuefunction, 用来处理客户端提交的请求。
(2) 注册路由: router.get(path, function(req, res))
(3) 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
2. 前端路由:
(1) 浏览器端路由,valuecomponent,用于展示页面内容。
(2) 注册路由: <Route path="/test" component={Test}>
(3) 工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
10.react-router-dom的理解
1. react的一个插件库。
2. 专门用来实现一个SPA应用。
3. 基于react的项目基本都会用到此库。

内置组件
1. <BrowserRouter>
2. <HashRouter>
3. <Route>
4. <Redirect>
5. <Link>
6. <NavLink>
7. <Switch>

Redux

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
1.redux是什么
(1).redux是一个专门用于做状态管理的JS库(不是react插件库)。
(2).它可以用在react, angular, vue等项目中, 但基本与react配合使用。
(3).作用: 集中式管理react应用中多个组件共享的状态。

2.什么情况下需要使用redux
(1).某个组件的状态,需要让其他组件可以随时拿到(共享)。
(2).一个组件需要改变另一个组件的状态(通信)。
(3).总体原则:能不用就不用, 如果不用比较吃力才考虑使用。
3. redux的三个核心概念
(1).动作的对象
(2).包含2个属性
type:标识属性, 值为字符串, 唯一, 必要属性
data:数据属性, 值类型任意, 可选属性
(3).例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }
4.reducer
1. 用于初始化状态、加工状态。
2. 加工时,根据旧的state和action, 产生新的state的纯函数。

5.store
1. 将state、action、reducer联系在一起的对象
2. 如何得到此对象?
1) import {createStore} from 'redux'
2) import reducer from './reducers'
3) const store = createStore(reducer)
3. 此对象的功能?
1) getState(): 得到state
2) dispatch(action): 分发action, 触发reducer调用, 产生新的state
3) subscribe(listener): 注册监听, 当产生了新的state时, 自动调用

6.redux的核心API
createstore()
作用:创建包含指定reducer的store对象
7.store对象
1. 作用: redux库最核心的管理对象
2. 它内部维护着:
1) state
2) reducer
3. 核心方法:
1) getState()
2) dispatch(action)
3) subscribe(listener)
4. 具体编码:
1) store.getState()
2) store.dispatch({type:'INCREMENT', number})
3) store.subscribe(render)

8.applyMiddleware():作用:应用上基于redux的中间件(插件库)
9.combineReducers():作用:合并多个reducer函数

10.redux异步编程理解:
1. redux默认是不能进行异步处理的,
2. 某些时候应用中需要在redux中执行异步任务(ajax, 定时器)
使用异步中间件:npm install --save redux-thunk
1. 一个react插件库
2. 专门用来简化react应用中使用redux

11. react-Redux将所有组件分成两大类
1. UI组件
1) 只负责 UI 的呈现,不带有任何业务逻辑
2) 通过props接收数据(一般数据和函数)
3) 不使用任何 Redux 的 API
4) 一般保存在components文件夹下
2. 容器组件
1) 负责管理数据和业务逻辑,不负责UI的呈现
2) 使用 Redux 的 API
3) 一般保存在containers文件夹下
12.相关API
1. Provider:让所有组件都可以得到state数据
<Provider store={store}>
<App />
</Provider>

2. connect:用于包装 UI 组件生成容器组件
import { connect } from 'react-redux'
connect(mapStateToprops,mapDispatchToProps)(Counter)

3. mapStateToprops:将外部的数据(即state对象)转换为UI组件的标签属性
const mapStateToprops = function (state) {
return {
value: state
}
}
4. mapDispatchToProps:将分发action的函数转换为UI组件的标签属性

13.纯函数
1. 一类特别的函数: 只要是同样的输入(实参),必定得到同样的输出(返回)
2. 必须遵守以下一些约束
1) 不得改写参数数据
2) 不会产生任何副作用,例如网络请求,输入和输出设备
3) 不能调用Date.now()或者Math.random()等不纯的方法
3. redux的reducer函数必须是一个纯函数

14.高阶函数
1. 理解: 一类特别的函数
1) 情况1: 参数是函数
2) 情况2: 返回是函数
2. 常见的高阶函数:
1) 定时器设置函数
2) 数组的forEach()/map()/filter()/reduce()/find()/bind()
3) promise
4) react-redux中的connect函数
3. 作用: 能实现更加动态, 更加可扩展的功能

redux工作流程

image-20211208153416819

简书项目

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
1、在reducer.js文件里,不能对原始的state做修改,为了防止这一点得引入facebook团队研发出来的一个库:immutable.js

它会帮助我们生成一个immutable对象 (不可改变的)如果state是immutable对象就是不可以被改变,就不会出问题。
2、immutable这个库提供了一个fromJS方法,可以帮助我们把一个js对象转化为immutable对象,用这个方法把数据对象(js对象)

转化为immutable对象。此时header下的index文件的mapState方法里的数据已经转化为immutable类型的数据(state.header)

如果是immutable类型的数据,再进行state.header.focused这种语法是不合理的了。immutable.js里面调用state.header里的属性不能通过点focused的方式来调用,得通过点get的方法传入focused的属性来获取对应的属性。此时不会报错,但是点击的时候就会报错报错的原因在与当你派发一个action的时候,传入reducers返回的是一个普通对象,普通对象时没有get方法的 为了防止这种情况,可以使用immutable对象的set方法,immutable对象的set方法,会结合之前immutable对象的值和设置的值,返回一个全新的对象,此时没有改变原始的state
3、:借助immutable这个库避免编写改变数据里state的情况
4、获取ajax数据一般来说不会直接写在组件里,会把异步的操作放到action,或者放到redux-saga里面进行处理,这里统一使用redux-thunk,把异步操作都放至action里处理
5、redux-thunk其实就是action和store之间的中间件 其实就是对dispatch方法的升级 以前的action返回的是一个对象,现在可以返回函数
6、在public文件夹下创建一个api文件夹之后在创建headerList.json的文件输入一下数据 之后在网页访问这个链接页面就可以显示数据
原理:首先先到功能目录下看看有没有对应的路由,找不到就会去public目录下找api的headerList.json,找到后就会把文件的内容输出出来
通过这个特性,我们可以创建一些假数据,保存。模拟的数据要和后端对的数据要保持一致,就是定一下格式
7、这样写实际上还是有问题的:创建store,默认list是一个空数组,fromJS方法会将js对象转换为immuable对象,list是个数组,也会变成immuable的数组,但是调用set去改变list的时候,action.data实际上是一个普通的数组, list数组会由immuable数组变成一个普通的数组,这样的话数据类型就会变了,解决这个问题
8、至于优化觉得可以做一些性能上的优化。因为每点击一次焦点的时候就会发送一次ajax请求。实际上列表中的数据获取一次就可以了
解决问题:给``handleInputFocus(list)``传入list 然后输出list可以看出第一次请求的时候list.size是0,之后就是50,
所以控制当size为0的时候才发送请求,之后不等于0的时候就不发生了,这样就避免了每次获取焦点的时候都发一个ajax请求,从而做到性能上的调优。

9、前两周这个包刚更新过如果按之前的编码规则会使得路由组件无法显示
import Home from './Home '
老版本
<Route path=" / home" component={ Home } />
新版本
<Route path=" / home" element={ <Home/> } />
10、在public下的api定义一个接口home.json。之后在home组件下借助componentDidMount这个声明周期函数来发ajax请求去获取数据,获取了数据,(当组件挂载完毕)。就要将获取的数据取修改store里初试的数据
11、修改store里的数据也就是状态 就得使用connect的第二个参数,通过这个函数就可以定义一个方法将action派发给store,因为UI组件不能和store直接通信,只能通过容器组件。派发给store之后store就会派发给reducer。
12、因为首页的index.js都调用了connect的方法,和store做了连接,这就会产生一个问题,只要store发生了改变,那么每一个组件都会被重新渲染,也就是每个函数的render函数会被重新执行,可能有些数据发生改变了,但是那个数据和这个组件一点关系都没有,但是这个组件依然会被重新渲染,导致性能不好。提高组价性能 shouldComponentUpdata,可以在这里做性能优化的代码,判断只有与这个组件相关的数据发生改变才让render函数重新执行(重新渲染),否则return false不让render函数重新执行。
通过这种方式来避免虚拟DOM的比对,提高性能,react也考虑到了这点,如果你在每个特组件都去自己写should....太麻烦了,react内置了新的组件类型,引入PureComponent,区别就是PureComponent内在自己底层实现了should...,这样就不用我们手写收should......做性能优化。之后就是每个UI组件都替换为PureComponent
之所以项目用**PureComponent**,是因为项目的数据管理用了immuable.js的框架,它可以保证我们的数据是immuable的,这样PureComponent和immuablejs数据格式的管理相结合,使用PureComponent一点问题都没有,但是如果你在你的项目里面,没有使用immuable.js管理你的数据,那么使用PureComponen有的时候会遇到坑。(偏底层的坑)
13、当我们在react实现页面跳转的时候,我们要用到react-router-dom第三方模块,它的这种跳转是单页应用跳转,link标签要在Router里面否则会报错
万一真有土豪呢!!!