React学习笔记

129 阅读10分钟

重新学习react,不是为了找工作,努力学透彻。

关于虚拟DOM:

  1. 本质是Object类型的对象(一般对象)
  2. 虚拟DOM比较“轻”,身上的属性少。因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。
  3. 虚拟DOM最终会被转化为真实DOM,呈现在页面上。

JSX语法规则:

  1. 定义虚拟DOM时,不要写引号
  2. 标签中,混入JS表达式时,要用{}。
  3. 样式的类名指定不要用class,要用className
  4. 内联样式要用style={{key:value}}的形式写
  5. 虚拟DOM必须只有一个根标签
  6. 标签必须闭合
  7. 标签首字母(1)如果小写字母开头,则将该标签转为html中同名元素,如果html中无同名元素,则报错。(2)如果大写字母开头,react就去渲染对应的组件,如果组件没有定义,则报错。

注意区分【js语句(代码)】与【js表达式】:

  1. 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方

    例如:(1)a (2)a+b (3)demo(1) (4)arr.map() (5)function test(){}

  2.  语句(代码):

例如:(1)if(){} (2)for(){} (3)switch(){}

类的总结:

  1. 类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时,才写。
  2. 如果A类继承了B类,并且A类中写了构造器,那么A类构造器中的super()是必须要调用的。
  3. 类中定义的方法都是放在了类的原型对象上,供实例去使用。

类式组件:

  1. render放在哪里的?类的原型对象上,供实例使用
  2. 执行ReactDOM.render之后发生了什么?解析组件标签,找到类组件,发现组件是用类定义的,随后new出来该类的实例,并通过该实例调用到原型链上的render方法
  3. render中的this是类组件的实例对象

组件三大核心属性:

state:

  1. 不能直接更改,状态必须通过set State进行更新,且更新是一种合并,不是替换

  2. state值是对象

  3. 组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)

  4. 组件中render方法中的this为组件实例对象

  5. 组件中自定义方法中this为undefined时如何解决?强制绑定this:bind()或者箭头函数

  6. 状态数据,不能直接修改或更新

props:

  1. 在类式组件中,构造器是否接收props,是否传递给super,取决于是否希望在构造器中通过this访问props(罕见)

react中的事件处理:

  1. 通过onXxxx属性指定事件处理函数(注意大小写)
  2. react使用的是自定义(合成)事件,而不是使用的原生DOM事件——为了更好的兼容性
  3. react中的事件是通过事件委托方式处理的(委托给组件最外层的元素)——为了高效
  4. 通过event.target得到发生事件的DOM元素对象——不要过度使用ref

高阶函数:

如果一个函数符合下面2个规范中的任何一个,那该函数是一个高阶函数。

  1. 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数
  2. 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数

常见的高阶函数:Promise、setTimeout、arr.map()

**函数的柯里化:**通过函数调用继续返回函数的方式,实现多次接受参数最后统一处理的函数编码形式

生命周期(旧):

  1. 初始化阶段:由React DOM.render()触发——初次渲染    

    1.constructor()
    2.componentWillMount()
    3.render()
    4.componentDidMount()===>常用
    一般在这个钩子中做一些初始化的事,例如:开启定时器,发送网络请求,订阅消息
    
  2. 更新阶段:由组件内部this.setState()或父组件render()触发

    1.shouldComponentUpdate()
    2.componentWillUpdate()
    3.render()
    4.componentDidUpdate()
    
  3. 卸载阶段:由ReactDOM.unmountComponentAtNode()触发

    1.componentWillUnmount()===》常用
    一般在这个钩子做一些收尾的事,例如:关闭定时器,取消订阅消息
    

生命周期(新):

  1. 初始化阶段:由React DOM.render()触发——初次渲染

    1.constructor()
    2.getDerivedStateFromprops
    3.render()
    4.componentDidmount()
    
  2. 更新阶段:由组件内部this.setState()或父组件render()触发

    1.getDerivedStateFromProps
    2.shouldComponentUpdate()
    3.render()
    4.getSnapShotBeforeUpdate()
    5.componentDidUpdate()
    
  3. 卸载阶段:由ReactDOM.unmountComponentAtNode()触发

    1.componentWillUnmount()
    

虚拟DOM中key的作用:

  1. 简单的说:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用
  2. 详细的说:当状态中的数据发生变化时,react会根据新数据生成新的虚拟DOM,随后react进行新虚拟DO M与旧虚拟DOM的diff比较,比较规则如下:
  • 旧虚拟DOM中找到了与新虚拟DOM相同的key:

(1)若虚拟DOM中内容没有变,直接使用之前的真实DOM

(2)若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

  • 旧虚拟DOM中没有找到与新虚拟DOM相同的key:

(1)根据数据创建新的真实DOM,随后渲染到页面

用index作为key可能会引发的问题:

  1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新==》界面效果没问题,但效率低
  2. 如果结构中还包含输入类的DOM:会产生错误DOM更新==〉界面有问题
  3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index是没问题的

开发中如何选择key:

  1. 最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号等
  2. 如果确定只是简单的展示数据,用index也是可以的

vscode中的react插件:

rcc类式组件 rfc函数式组件

在终端中停止运行:control+c

功能界面的组件化编码流程:

  1. 拆分组件:拆分界面,抽取组件
  2. 实现静态组件:使用组件实现静态页面效果
  3. 实现动态组件:
  • 动态显示初始化数据:
  1. 数据类型
  2. 数据名称
  3. 保存在哪个组件
  • 交互(从绑定事件监听开始)

todolist案件知识点:

  1. 拆分组件、实现静态组件
  2. 动态初始化列表,如何确定将数据放在哪个组件的state中?
  • 某个组件使用:放在组件自身的state中
  • 某些组件使用:放在他们共同的父组件state中(状态提升)

3. 关于父子组件通信

  • 父组件给子组件传递数据:通过props传递
  • 子组件给父组件传递数据:通过props传递,要求父提前给子传递一个函数

4. 注意defaultChecked和checked的区别

5. 状态在哪里,操作状态的方法就在哪里

react脚手架配置代理总结:

## 方法一

> 在package.json中追加如下配置

```json"proxy":"http://localhost:5000"```

说明:

1. 优点:配置简单,前端请求资源时可以不加任何前缀。

2. 缺点:不能配置多个代理。

3. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)

## 方法二

1. 第一步:创建代理配置文件

```   在src下创建配置文件:src/setupProxy.js   ```

2. 编写setupProxy.js配置具体代理规则:

```js

const proxy = require('http-proxy-middleware')

module.exports = function(app) {

app.use(

proxy('/api1', { //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)

target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)

changeOrigin: true, //控制服务器接收到的请求头中host字段的值

/*

changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000

changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000

changeOrigin默认值为false,但我们一般将changeOrigin值设为true

*/

pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)

}),

proxy('/api2', {

target: 'http://localhost:5001',

changeOrigin: true,

pathRewrite: {'^/api2': ''}

})

)

}

```

说明:

1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。

2. 缺点:配置繁琐,前端请求资源时必须加前缀。

github搜索案例相关知识点

  1. 设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办

  2. ES6知识点:解构赋值+重命名

    let obj = {a:{b:1}}
    const {a}=obj//传统的解构赋值
    const {a:{b}}=obj//连续解构赋值
    const {a:{b:value}} = obj//连续的解构赋值+重命名
    

  3.  消息订阅与发布机制

  • 先订阅,再发布
  • 适用于任意组件间的通信
  • 要在组件的componentWillUnmount中取消订阅

  4.  fetch发送请求(关注分离的设计思想)

SPA的理解:

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

路由的基本使用:

  1. 明确好界面中的导航区、展示区

  2. 导航区的a标签改为link标签

    Demo
  3. 展示区写Route标签进行路径的匹配

    <Route path='/xxx' component={Demo} />
    
  4. 的最外层包裹了一个或

路由组件和一般组件的区别:

  1. 写法不同

  2.  一般组件:<Demo/>  
     路由组件:<Route path='/about' component={About}/>
     
    

  2.  存放位置不同

一般组件:component
路由组件:pages

  3.  接收到的props不同:

一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性

NavLink与封装NavLink:

  1. NavLink可以实现路由的连接的高亮,通过activeClassName指定样式名
  2. 标签体内容是一个特殊的标签属性
  3. 通过this.props.children可以获取标签体内容

Switch的使用:

  1. 正常情况下,path和component是一一对应关系
  2. Switch可以提高路由匹配效率(单一匹配)

解决多级路径刷新页面样式丢失的问题:

  1. public/index.html 中引入样式时不写./ 写/(常用)

  2. public/index.html 中引入样式时不写./写%PUBLIC_URL%(常用)

  3. 使用HashRouter

路由的严格匹配与模糊匹配:

  1. 默认使用的是模糊匹配(输入的路径必须包含要匹配的路径,且顺序要一致)

  2. 开启严格匹配:

嵌套路由:

  1. 注册子路由时要写上父路由的path值
  2. 路由的匹配时按照注册路由的顺序进行的

路由组件传递params参数:

  1. 路由链接(携带参数):<Link to='demo/test/tom/18'>详情</Link>
  2. 注册路由(声明接收):<Route path='demo/test/:name/:age' component={Test}/>
  3. 接收参数:const {id,name} = this.props.match.params

路由组件传递search参数:

  1. 路由链接(携带参数):<Link to='demo/test?name=tome&age=18'>详情</Link>
  2. 注册路由(无需声明,正常注册即可):<Route path='demo/test' component={test}/>
  3. 接收参数:const {search} = this.props.location
  4. 获取到的search是urlencoded编码字符串,需要借助querystring解析

路由组件传递state参数:

  1. 路由链接(携带参数):<Link to={{path:'/demo/test',state:{name:'tom',age:18}}}'>详情</Link>
  2. 注册路由(无需声明,正常注册即可):<Route path='demo/test' component={test}/>
  3. 接收参数:const {name,age} = this.props.location.state
  4. 刷新也可以保留住参数