React 基础

11 阅读8分钟

官方文档 react.docschina.org/docs/gettin…

一、命令行 cli

  • 安装 yarn global add create-react-app
  • 创建文件 : create-react-app 文件名
  • 开始开发 : yarn start

二、虚拟Dom

虚拟Dom:React 元素的返回值可以代表一个div,但是它并不是真正的dom 对象

所以一般把react返回的element称为 虚拟 Dom

函数组件:返回element的函数,可以代表一个div,函数可以多次执行,每次都会得到最新的虚拟div,

React会对比两个虚拟div,找出不同然后局部更新视图,这种方法依赖于 ****Dom Diff ****算法

执行顺序App()组件 -----> 执行 -----> 虚拟Dom -----> 更新Dom -----> 渲染页面 ----->useEffect

三、JSX

  • 语法:可以直接在 js 中书写 HTML 语法,如果需要插入 js 语法 需要写在 {{}}
const App = () =>(<div
    {{}}
    <button onclick={()=>{n+1;render();}}>加1</button> 
  </div>);

ReactDom.render(<App/> , document.getElementById('root'));
  • 注意 : 1. class 属性应该写成 className

2. 变量和对象要使用 { } 包起来 ,例: {变量} {{对象}}

****3. return 后的内容要使用 () 包起来

4. 条件判断和循环控制,使用 原生js 语法实现,for循环需要有 key

四,react组件

  • 书写:react元素首字母小写, 组件名 首字母大写
  • 分类:react有两种组件,函数组件 ****和 类组件
  • 元素:react元素 是构成应用的最小单位,不可改变
function Welcome(props){
  const [n,setN]=useState(0) //设置 state 变量n 并且初始值为0。
  return <h1>Hello,{props.name}</h1>
}

<Welcome name ="frank" / > //使用方法
class Welcome extends React.Component{
  constructor(){
    super()
    this.state={
      n:0
    }
  }
  render(){
    return <h1>Hello,{this.props.name}</h1>
  }
}

<Welcome name ="frank" /> //使用方法

(1)可控组件与不可控组件

  • 可控组件:表单数据由React组件管理,react中推荐使用可控组件
  • 不可控组件:表单数据由Dom节点处理

五、state

  • 类组件使用this.state 来定义,使用setState来更新值(异步更新)
  • 当组件渲染完毕后,修改state的值,不会触发重新渲染
  • 函数组件使用Hooks,state在Hooks中介绍
class Welcome extends React.Component{
  constructor(){
    super()
    this.state={n:0}
  }
}
//this.state.n 就是n的值
this.setState({this.state.n+1})

六、props

  • 定义:需要外部传递的数据,只能由父组件像子组件传递,子组件不能反向修改。
  • 使用方法:函数组件通过参数传递 (props)=>{函数体} ,类组件直接调用this.props
function App(){
  const a=10
  return(
    <div className="App">
      这里是父组件
      <Son messageForSon={a}>  // 在父组件中向子组件传递一个变量 a
    </div>
  )
}

//子组件使用方式(类组件)
this.props.messageForSon
//子组件使用方式(函数组件)
props.messageForSon

七、Hooks

Hook就是JavaScript函数。但是它有两个额外的规则:

  • 只能在函数最外层调用,不可以在循环,条件判断或者子函数中调用
  • 只能在React函数中调用Hook(或者自定义Hook中调用),不要在其他函数中调用

1. useState

  • 采用析构赋值的方式,使得useState函数中包括一个n和一个setN() ,参数为n的初始值表示数据当前的状态setN() 是一个函数,封装对 n 的操作,但是不可以部分更新n中的数据
  • setN() 并不会直接修改n 的值,修改的是n的副本,优先使用函数,引用类型采用浅比较(只比较地址),可以有多个state。对于数组对象等,修改时需要创建一个新的对象,setN异步 的并不会马上得到修改后的值
  • setN()会把对于同一个数据多次修改合并为一次,只修改最后一次。对于不同的数据也会合并起来执行一次,页面渲染
function App(){
  const [n,setN]=useState(0)
  //初始化n的值为0 ,steN()用来操作n的值
}

2. useReducer

  • 步骤:先声明一个初始值,再将所有操作都封装成一个函数,然后将它们传给 useReducer
  • 优点:对操作进行封装,可以简化HTML代码,直接调用封装好的 Api 就可以
  • 作用reducerContext 一起用可以用来代替Redux, 同样也是useState的升级版。
const initial={...} // 初始值
const reducer=(state,action)=>{
  ...
}// 对初始值的所有操作 

//函数组件
function App(){
  const[state,dispatch]=useReducer(roducer,initial)
  //传给useReducer后,会获得一个读接口(state)和一个写接口(dispatch)
  //useReducer(roducer,initial) 注意参数顺序,操作在前,值在后
}

使用useReducer代替redux

  • 将初始数据集中在store对象中
  • 将所有对数据的操作集中在reducer中
  • 创建一个context,context的初始值
  • 在组件内创建reducer的读写操作,并且将读写操作传递给context使其变为全局变量
  • 组件内读写直接调用context传递的数据即可

3. useContext

  • 使用createContext() 创建一个Context 的上下文区域,并且使用 .Provide声明作用域的范围
  • 将初始值传递给value属性,在作用域范围内的所有组件就都可以使用这个state
  • 注意:useContext的值不是响应式的,一个模块中修改并不会影响另一个模块
  • 子组件使用useContext中的 valueconst {n,setN}=useContext(c)
const C=createContext(initial) //这个c就是一个全局变量

function App(){
  const [n,setN]=useState(0)
  return(
   <c.Provide value={{n,setN}}>
   //声明作用域,该作用域内的所有组将都可以使用n和setN     
   </c.Provide>
  )
}

//子组件的使用方法,表示子组件使用的n是来自于useContext
const {n,setN}=useContext(c)

4. useEffect

  • 副作用,对环境的改变即为副作用,比如修改document.title,用途主要是在hooks中实现class组件的生命周期的功能
  • useEffect可以大概理解为afterRender,默认为每次render() 后都会运行,是一个异步的操作
  • 语法: useEffect(回调函数,array) 如果存在多个useEffect,会按出现顺序执行
//1.单纯的useEffect 会在组件渲染后执行,render()后只执行一次,第二参数为空数组
useEffect (()=>{function('组件内任意state变化就执行该函数'),[]})

//2.state任何值发生变化都执行,监听所有值,第二参数省略
useEffect (()=>{function('组件内任意state变化就执行该函数')})

//3.监控指定的值,第二参数数组为这个值
useEffect (()=>{function('组件内变量n变化就执行该函数'),[n]})
  • 清除副作用: 组件卸载时,需要副作用,比如计时器等异步的操作,可能会造成内存泄露

使用Effect函数的return返回一个清除函数(会在组件被销毁时执行)

清理副作用是一个良好的习惯。

//4.return返回的函数会在组件销毁时执行
useEffect (()=>{return function('组件内任意state变化就执行该函数')})

5.useLayoutEffect

  • useLayoutEffect和useEffect功能类似,只有执行时机不同
  • useLayoutEffect会在页面更新之前执行useEffect会在页面更新之后执行
  • useEffect优先使用, 优先渲染页面,满足用户体验

6. useMemo

React.memo函数 :

函数组件的state默认是一个数组,每次函数调用state更新时,数组地址会发生变化,props同理。引用类型地址变化会使react重新渲染所有依赖此项的子组件,有些子组件会有多余的render(),为了避免这种情况要使用memo重构子组件。使其只在props更新时执行代码,但是memo不支持监听具体的值,如果props是数组等引用类型,无法满足需求

const Child = React.memo((props)=>{}) //使用memo函数包裹的组件,仅在props值发生变化时重新渲染

useMemo主要用来做 性能优化,相比于memo函数,支持监听具体的依赖项。

  • useMemo() 支持监听值,第一个参数为 ()=>{value} ,第二个参数是依赖 [值]
// 第一个参数为回调函数,第二个参数为监控的值,只有m更新时才执行这个回调函数
const onClickChild=useMemo(()=>{
  return ()=>{fn回调函数}
},[m])

7. useCallback

  • useCallbackuseMemo作用相同,useCallback是个语法糖
useCallback(x=>log(x),[m]) //可以直接写回调函数
useMemo(()=>x=>log(x),[m])

//这两种写法等价,只是省略了()=>

8. useRef

  • useRef中声明的值发生变化,不会引发组件更新,useRef() 数据更新是同步的
  • current 对象 ****每次获取的值都是相同的(地址相同的同一个对象),只要修改就会拿得到最新的值
  • useRef声明的值可以在其他函数内部使用,该值是稳定的可变的,不会随着组件更新而变化
  • 用途:1、持久化缓存 2、获取真实DOM
const demo=useRef(0)//声明
demo.current //调用
  • 获取真实Dom元素,(由于react 元素是虚拟Dom),可以通过ref属性将useRef对象绑定到Dom 上来获取
function App(){
  const inputRef=useRef(null)
  const onFocus=()=>{
    inputRef.current.focus()
  }
  return(
    <div>
      <input type="text" ref={inputRef} /> /通过ref属性绑定
      <button onClick={onFocus}>聚焦</button>
    </div>
  )
}

9. forwardRef

  • 作用:函数组件只能接收props参数,无法接收ref,需要使用forwardRef() 来包装一下
const Button=(
  (props,ref)=>{...}
)
const Button2=forwardRef(Button)//有了这句话,Button就可以接收ref参数,不然就会报错

//简写
const Button=forwardRef(
   (props,ref)=>{ ...}
)

10 .useRef 和 useState对比

  • useState受组件更新影响,组件更新后不能第一时间获取新值(异步)
  • useRef相对独立不受组件更新影响,修改后可以第一时间获取新值,但是更新状态需要回调函数异步实现

八、自定义Hook

  • 将数据以及操作都封装在一个函数中,可以使用其他现有Hook,然后这样具有自定义功能的Hook 就是自定义Hook,需要暴露一个读接口和一个写接口,负责一点还可以包括增,删,改,查
  • 自定义Hook 加上Context,完全可以替代 Redux
  • useState 不可以在if李使用,但是可以在函数中运行,只要这个函数在函数组件里运行就行

九、Hook想法

  • useState 基础内部数据,可以通过参数传递给其他组件使用(Props)。会随着组件更新变化
  • useRef 基础数据, .current可变,但是不会引起组件更新
  • useEffect 生命周期
  • useContext ``.Provide作用域,优化Props传值,createContent创建对象
  • useMemo 性能优化,防止不必要的state更新
  • useCallback useMemo的语法糖,作用类似
  • useReducer 数据管理,替代 redux

十、Redux思想