登录/注册

React Hooks

用户头像管理员82阅读

React v16.8中官方推出了Hooks,该方案会取代大部分的类组件主要解决了函数组件无法使用状态的问题

React Hooks

在官方为我们提供的Hook中,主要解决的就是使用状态和生命周期的问题

useState

在原来的函数组件中我们只可以做静态展示内容无法实现双向绑定的交互:

export default function Component() {
  return (
    <>
      <div>我是一个函数组件</div>
    </>
  );
}

因此官方提供了useState钩子

import React, { useState } from "react";
export default function Component() {
  const [state, setstate] = useState(0);
  function add() {
    let num = state + 1;
    setstate(num);
  }
  return (
    <>
      <div>我是一个函数组件</div>
      <div>现在的数字是:{state}</div>
      <button onClick={add}>点我加一</button>
    </>
  );
}

对于const定义的数组大多是人还是比较陌生的,这就是官方所给的hooks,数组中第一个参数为设置的值,第二个参数是修改这个值的函数,正向add函数中的那样setState中的参数就是要修改后的值useState函数中的0就是默认的值,当然也相当于类组件中的getDerivedStateFromProps生命周期可以在useState函数中直接使用props传来的值

React通过是否同一块内存来判断state是否修改,对于我们需要使用深拷贝来修改数组或者对象内容:

对象:

<Input
  value={data.name}
  onChange={e =/>
  setData(_data =>(<span style="white-space: pre-wrap;">{ ..._data ,</span><span style="white-space: pre-wrap;">name: e.target.value</span><span style="white-space: pre-wrap;">}</span><span style="white-space: pre-wrap;">)</span><span style="white-space: pre-wrap;">)</span>  }
/>

数组:

<Input
  value={data.name}
  onChange={e =/>
  setData(_data => {
   //处理数组,创建一个newArray数组返回
    return [...newArray];
   })
  }
/>

useEffect

接下来还是生命周期问题官方提供useEffect函数来解决

useEffect(() => {

    
})

这个函数相当于每次更新都是使用

useEffect(() => {

    
},[])

如果加了这个就只在组件挂载后使用了,可能有人会疑惑第二个参数为啥是一个空数组呢?

这个就行相当于vue中的watch函数

useEffect(() => {

    
},[state])

这样的话就相当于监听state,每次state变化了就会执行函数

除此之外还提供了组件销毁的生命周期

useEffect(() => {
   console.log("组件创建");
    return () => {
     console.log("组件销毁");
   };
}, []);

此方法需要在函数中在返回一个函数可以与组件创建生命周期写在一个函数中,当然了看这个函数的名字就可以知道这个函数是执行一些副作用的,而不是完全当做生命周期或者watch函数使用的,

useMemo

这个Api相当于Vue中的computed,也算是React中的计算属性,因为hooks中状态的改变会被react认为组件需要重新渲染,使用useMemo告诉react只有依赖项变了这才是一个新的函数需要渲染

使用方法:

const articleData = useMemo(() => data, [data]);

一共有两个参数第一个是函数有一个返回值返回的是最终的计算结果,第二个和useEffect的数组差不多,是一个依赖项,只要数组中的元素有变化就会重新计算参数函数,useMemo的返回值为计算结果

useRef

在React函数组件中我们可以使用useRef来保存变量和获取DOM(相当于类组件中的createRef)

和createRef相同在我们我们定义的ref也是一个对象,由于react的更新机制不同于Vue,所以react组件中的普通变量在创建后不会被修改,导致了我们无法保存变量,所以官方创建了useRef作为保存变量的函数,也可以用于获取DOM

let ref=useRef(0)//{current:0}

这样我们就定义了一个ref来存储变量,修改这个变量也是通过修改current

例如:ref.current=1

let dom=ref(null)
return(
  <div ref={dom}>我是一个被useRef选中的div标签</div>
)

这样的话我们通过获取dom的current属性就可以直接拿到被选中的标签了

useContext

这个Hooks主要用于组件传值不同于props这个Hooks是通过引入使用的所有不会对组件层级有限制

1.我们需要先定义useContext

const Count= createContext(0)

2.使用定义的context包裹需要接收值的组件将要传递的数据通过value传递

<Count.Provider value={data}>
 <Route/>
 <Route/>
</Count.Provider>

3.使用Context

function child() {
  let data = useContext(Count);
  return <div>{data}</div>;
}

!!:如果是跨JSX文件使用在步骤1 时需要将createContext创建在最外层导出使用时导入

useReducer

这个Hooks主要是可以配合上文的useContext来实现状态管理类似(redux/vuex)

useReducer也是有两个参数,第一个参数是进行状态设置,第二个是默认状态,也就是初始值

1.创建useReducer

const [value, setValue] = useReducer((state, action) => {
  value = action;
}, 0);

state为被操作值

action为操作时传来的值

value是计算后的响应式值

setValue是重新计算:setValue(params) //参数为useReducer中的action

2.修改结果

setValue(value+1)

如果我们这样触发那么所有使用到value变量的地方都会加1

!!:我们可以将这两个Hooks结合到一起实现状态管理,与其他状态管理相同主要操作也是发布/订阅,由useReducer进行数据保存和修改,后由useContext来进行发布

useCallback

这个Hooks相当于一个节流函数

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

他返回的相当于一个事件,第二个参数也是依赖项,通常用于事件执行,他的出现一部分原因和useMemo类似,只有在依赖项变了react才会认为他是一个新的函数,同时只有传递了依赖项在函数体中才可以获取到最新的变量

useLayoutEffect

类似于useEffect,不过他和useEffect的加载时机不同,useEffect实在DOM节点挂载后触发,useLayoutEffect实在浏览器渲染ReactNode前进行触发

useImperativeHandle

这个主要用于父组件调用子组件的方法,子组件向外暴露方法时使用,具体可以看这篇文章:React父组件调用子组件的方法

useInsertionEffect

基本等同于useEffect,官方说明使用于CSS-in-JS作者,开发时没用过

React 18

useId

这个Hooks主要是作为生成Key来使用,原因是React框架SSR时使用很多自定义的ID生成方法会倒是server和client的Key不符
<div key={useId()}>demo</div>

useDeferredValue

18出的Hooks主要是设置响应式变量的加载顺序的,使用这个函数包裹一个useState的变量,在修改时使用useDeferredValue定义的状态会放在后面执行,降低响应时的权重
const deferredValue = useDeferredValue(value);

useTransition

这个基本于useDeferredValue差不多,在startTransition中修改变量将降低权重默认为非紧急执行,不在优先执行,isPending是一个布尔值,表示是否在等待修改中,这个两个个Hooks主要用于性能优化
官方Demo:
function App() {
  const [isPending, startTransition] = useTransition();
  const [count, setCount] = useState(0);
  
  function handleClick() {
    startTransition(() => {
      setCount(c => c + 1);
    })
  }

  return (
    <div>
      {isPending && <Spinner />}
      <button onClick={handleClick}>{count}</button>
    </div>
  );
}

总结:

  1. Hooks提高了工作效率,并且让组件更加简单
  2. 并且可以自行解决状态管理问题不需要依赖第三方
  3. 部分函数可以集成到一个Hooks中更加方便抽离

当然很多hooks只是作为性能优化出现的,个人理解是react官方的“屎山堆屎”行为,在开发中一定要按照项目需求来选择框架,不要迷信某个框架所谓的高级感。

Preview
登录后评论