框架React

React 引入

使用create-react-app,或者配置webpack和rollup

yarn add react react-dom
import React from 'react'
import ReactDom from 'react-dom'

React、React函数组件

React.createElement('元素名', {属性名:属性值}/null, '元素内容') 

createElement函数的返回值element是一个React元素,也就是创建了一个虚拟DOM对象

函数组件相当于延迟执行createElement函数,延迟生成一个React元素。

通过DOM diff对比虚拟DOM进行局部更新 真正的DOM

JSX

就是将HTML标签 转译成JS 代码 给浏览器解析,浏览器能解析JS 却不认识HTML代码。
若在JSX 里写JS代码,需要加上{},否则解析为字符串

在线翻译工具babel online,查看组件标签 会被翻译 成什么

React 类组件和函数组件

类组件 和 函数组件
如何使用 外部数据props 和 内部数据state
如何绑定事件

类组件:

写法有固定格式,

class Son extends React.Component {
  constructor(props) { 
​    // constructor(props) 方法用于初始化
​    super(props) 
​    // 照抄
​    this.state = {  
​      // 初始内部数据state,用this指定,等于一个JSON格式的数据;这里表示初始值为n(n=0);用this.state.n可以调用
​      n: 0
​    }
   }
   // 类组件内部定义的函数,用this就可以调用,如this.add()
   add(){
​     this.setState({n: this.state.n + 1})
   }
   render(){
​     return (
     <div className='son'>
​          儿子 n: {this.state.n}
​          <button onClick={()=>this.add()}> +1</button>
​        </div>
​     )
}
}

使用props

类组件:直接读取属性

添加:在组件名上添加  变量名={数据} or "数据"  <Son VarName={"我是你爸爸"}/>
读:使用  花括号 + this.props.变量名 如  {this.props.VarName}

函数组件:直接读取函数的参数

读:函数组件会直接获取外部数据,将之变成一个对象作为形式参数的第一个参数,使用形参props即可  {props.VarName}

使用state

类组件:this.state & this.setState

初始化:在super()后面初始化,this.state = { 名: 值数据 }
读:读对象那样 this.state.名
写:使用setState() 生成一个新的对象this.setState({n: this.state.n + 1})
——最好像这样不要直接改原来的对象 this.setState(n: this.state.n + 1)

注意:setState()是异步的,倘若在某函数作用域中,会等当前作用域代码执行完毕后,再返回setState()的结果。因此setState内最好使用一个带有返回值的函数,就能避开异步困扰了。

函数组件:[n, setN] = useState() 全搞定

setN() 也不会改变n,而是生成一个新的n。

函数组件代替class组件的一点点问题

创建方式const VarName = () =>{} / function VarName() {}

没有state

React v16.8.0 推出了 Hooks API,其中的一个API useState可以解决

没有生命周期

React v16.8.0 推出了 Hooks API,其中的一个API useEffect可以解决
答面试官:这个API的是用来解决副作用的

生命周期?用useEffect(fn, [])

*模拟componentDidMount (组件第一次渲染):

useEffect(()=>{}, []) 表示函数fn只会在第一次渲染时执行,如第一次按+1按钮时fn会执行

*模拟componentDidUpdate (组件任意属性变更):

useEffect(()=>{}, [state变量名]) 表示state的变量如n,值改变时,执行fn

类组件 注意事项:

*this.state.n += 1 无效?

n会改变,但UI显示的n没变,调用setState 后UI才会变;
React不会监听state,但是Vue会监听data。

*setState 异步更新UI

推荐使用setState(函数),就能实时更新了

*最好不要this.setState(this.state)

React希望我们不要修改state(不可变数据理念)
最好生成新的state对象,如,setState({})

state里面有多个属性

如果单独更改其中一个属性,那么,

类组件:会分情况覆盖其他属性

属性值不是对象:因为this.setState({})不会创建新对象,只是更改属性值,不会覆盖其他属性
属性值是个对象:所以如果属性值也是个对象,如user={age:18, name:'feifei'},如果只单独修改user的一个属性,那就会覆盖掉另一个属性了

函数组件:会覆盖其他属性

因为setState({}),是创建新对象的意思,因此如果其他属性没有拷贝,那set之后就会消失
如果要写成对象的形式,记得用...把之前的拷贝setState({..., key:value})

总结:有覆盖的时候,就在被覆盖的那个对象里加上...state/...this.state.user,再改需要更改的属性

或者const user = Object.assign({}, this.state.user) === {...this.state.user}

React小知识:

不可变数据:

每次生成的数据一定要生成个新的(这样地址也是新的),否则React会认为还是原来那个地址,就不会触发了。
如何声明变量的类型:只要在变量后面加上 :React.类型名称,类型名称如FunctionComponent、MouseEvent、...
SVG:React早就提供了SVG的所有属性,在组件接收外部数据的类型声明里,用& React.SVGAttributes<SVGElement>即可获取
React的一个库,yarn add classnames,没有这个几乎无法写className;安装依赖yarn add --dev @types/classnames
将数据保存到本地内存:用useEffect() 先读再写,而不是先写再读!!

  1. 必考:受控组件 V.S. 非受控组件
  2. 必考:React 有哪些生命周期函数?分别有什么用?(Ajax 请求放在哪个阶段?)
  3. 必考:React 如何实现组件间通信?
  4. 必考:shouldComponentUpdate 有什么用?
  5. 必考:虚拟 DOM 是什么?
  6. 必考:什么是高阶组件?
  7. 必考 Redux 是什么?
  8. React DOM diff 的原理是什么?
  9. connect 的原理是什么?

React 生命周期函数?

数据请求放在哪个钩子里?

从后台获取数据一定要放在componentDidMount里面调用,因为这时候组件已经加载完了,可以保证数据加载。

React组件挂载时的生命周期,有以下4个:

constructor()
——先调用它后,组件才开始在网页上加载;作组件state初绐化工作的,不能用来加载数据
componentWillMount()
——在这方法里的代码调用setState方法不会触发重渲染,因此不能用来加载数据
render()
——调用执行完,得到虚拟DOM,不是真正的DOM节点
componentDidMount()
——组件加载完成后,再调用它。(在这方法中调用setState方法,会触发重新渲染)

什么是高阶组件?

实际就是个函数,参数是一个组件,返回值也是一个组件。比如connect。ReactRouter里的withRouter

虚拟 DOM 是什么?

虚拟节点,是一个JavaScript对象,React用来模拟DOM节点,然后渲染成真实DOM节点。

模拟:写个div标签的代码就会生成一个对象,对象有3个重要属性,tag是什么标签,props标签的属性,children标签的子节点

<div>
    <span></span>
</div>

转译:JSX为createElement函数调用

React.createElement("div",{id:"x"},
  React.createElement(...
)

渲染:

render方法,接收虚拟节点,返回真实节点

虚拟节点是文本就创建文本节点;
不是文本,就创建对象{3个属性},根据属性创建createElement

更新 UI 主要就是通过对比(DIFF)旧的虚拟 DOM 树 和新的虚拟 DOM 树的区别完成的。

React.js 相对于直接操作原生 DOM 有很大的性能优势, 很大程度上都要归功于 virtual DOM 的 batching 和 diff。batching 把所有的 DOM 操作搜集起来,一次性提交给真实的 DOM。diff 算法时间复杂度也从 标准的的 Diff 算法的 O(n^3) 降到了 O(n)。

其他优点:虚拟DOM可以跨平台

缺点:所有React事件都绑定到根元素,自动实现事件委托;如果同时用React合成事件和原生DOM事件,可能会有bug。

React 如何实现组件间通信?

父子组件:props予 父传子一个函数,通过函数回调子的值

爷孙组件:两层父子组件通信 or 使用Context API .provider予 .consumer用

任意组件:没有血缘关系,那就把数据放到最顶层的APP里,再下发到目标组件(其实就是全局状态管理)

    • Redux(react的周边工具)
    • Mobx(抄袭Vue响应式思想,自动绑定)
    • Recoil(官方的局部状态管理)
class Parent extends React.Component {
  constructor(props) {
    super(props)
    this.state = {count: 0}
  }
  setCount = () => {
    this.setState({count: this.state.count + 1})
  }
  render() {
    return (
      <div>
        <SiblingA
          count={this.state.count}
        />
        <SiblingB
          onClick={this.setCount}
        />
      </div>
    );
  }
}

Redux

  • 文档第一句,Redux 是一个JS app 的状态管理容器。
  • Redux 库核心概念
    • State 存放状态
    • Action 表示每一步对数据的改变 type动作类型+payload荷载
    • Reducer 传一个旧的State和Action,就产生个新的State
    • Dispatch 派发Action
    • Middleware
  • ReactRedux 库的核心概念
    • connect()(component) 把component和store关联起来。接受2次参数,第二次是componnet
    • mapStateToProps
    • mapDispatchToProps
  • 两个常见的中间件redux-thunk redux-promise

Redux、ReduxThunk、ReduxSaga、dva、UmiJS 的区别和联系是什么?

ReactRouter

React Router 是完整的 React 路由解决方案。

react-router-dom的常用API

  • BrowserRouter、HashRouter 顶层组件包裹子组件
  • Route 给需要渲染的组件路由匹配 `<Route exact path="/tags/:fuck">
    <Tag />
    </Route>`
  • Link 把路由放置在包裹的内容上 NavLink 匹配上当前路由的时候给已经渲染的元素添加参数
  • switch 包裹Route组件
  • redirect 设置默认路由 `<Redirect exact from="/" to="/money" />`

Route 的属性

Route用于路径的匹配,然后进行组件的渲染,对应的属性如下:

  • path 属性:用于设置匹配到的路径
  • component 属性:设置匹配到路径后,渲染的组件
  • render 属性:设置匹配到路径后,渲染的内容
  • exact 属性:开启精准匹配,只有精准匹配到完全一致的路径,才会渲染对应的组件

两种模式

BrowserRouter、HashRouter

Router中包含了对路径改变的监听,并且会将相应的路径传递给子组件

BrowserRouterhistory模式,HashRouter模式

使用两者作为最顶层组件包裹其他组件

HashRouter包裹了整应用,

通过 window.addEventListener('hashChange',callback)监听 hash值的变化,并传递给其嵌套的组件
然后通过 contextlocation数据往后代组件传递,如下:

BrowserRouter组件主要做的是通过BrowserRouter传过来的当前值,通过props传进来的pathcontext传进来的pathname进行匹配,然后决定是否执行渲染组件

import React, { Component } from 'react';
import { Provider } from './context'
// 该组件下Api提供给子组件使用
class HashRouter extends Component {
  constructor() {
    super()
    this.state = {
      location: {
        pathname: window.location.hash.slice(1) || '/'
      }
    }
  }
  // url路径变化 改变location
  componentDidMount() {
    window.location.hash = window.location.hash || '/'
    window.addEventListener('hashchange', () => {
      this.setState({
        location: {
          ...this.state.location,
          pathname: window.location.hash.slice(1) || '/'
        }
      }, () => console.log(this.state.location))
    })
  }
  render() {
    let value = {
      location: this.state.location
    }
    return (
      <Provider value={value}>
        {
          this.props.children
        }
      </Provider>
    );
  }
}
 
export default HashRouter;
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值