React-HOOKS常用知识点总结

React-HOOKS常用知识点总结.md

1、类组件与函数组件的区别

类组件:

  • 可以定义自己的state
  • 保存自己的内部状态
  • 有自己的生命周期,在对应的生命周期完成对应的逻辑操作,componentDidMount发送网络请求,数据更新时可以调用componentDidUpdate,状态发生改变会重新执行render函数
  • 副作用需要在componentWillUmmount中清楚
  • redux中需要手动调用subscribe

函数组件:

  • 不能保存自己的状态,函数每次调用都是产生新的临时变量
  • 函数组件被重新渲染时,整个函数都会被重新执行

2、HOOK使用原则

  • 只能在最外层调用HOOK
  • 不能在循环、条件判断或子函数中调用
  • 如果需要做条件判断,则需要放到HOOK的内部
  • 只能在React的函数组件调用HOOK

3、useState

作用:用于保存状态

参数:初始state,

返回值:一个数组【当前的函数值,设置新值的函数】

调用setState会做两件事情:设置新的值,组件重新渲染,根据新的值返回DOM结构

setState可以传入对象 | 函数,实现结果同于setState({})

每次调用setState都是在做替换操作

// 声明一个叫 “count” 的 state 变量。
const [count, setCount] = useState(0);
// 声明一个数组
const [firends, setFirends] = useState(['Marry', 'Cherry']);
// 添加用户和修改用户年龄
import React, { useState } from 'react';

export default function ComplexHookState() {
  const [friends, setFrineds] = useState(['Marry', 'Cherry']);
  const [students, setStudents] = useState([
    { id: 110, name: 'Marry', age: 18 },
    { id: 111, name: 'Cherry', age: 30 },
    { id: 112, name: 'Juice', age: 25 },
  ]);
  const incrementAgeWithIndex = index => {
    const newStudents = [...students];
    newStudents[index].age += 1;
    setStudents(newStudents);
  };
  const addFriends = () => {
    let newFriend = [...friends, 'Lois'];
    setFrineds(newFriend);
  };
  // 传递函数,可以拿到旧的值做更多的自定义操作
  const addFriends = () => {
    setFrineds((preValue) => {
      return [...preValue, 'Lois']
    })
  };
  return (
    <div>
      <h2>好友列表:</h2>
      <ul>
        {friends.map((item, index) => {
          return <li key={index}>{item}</li>;
        })}
      </ul>
      <button onClick={addFriends}>添加朋友</button>
      <h2>学生列表</h2>
      <ul>
        {students.map((item, index) => {
          return (
            <li key={item.id}>
              <span>
                名字: {item.name} 年龄: {item.age}
              </span>
              <button onClick={e => incrementAgeWithIndex(index)}>age+1</button>
            </li>
          );
        })}
      </ul>
    </div>
  );
}

4、useEffect

作用:类似生命周期函数,可用于网络请求、手动更新DOM、事件监听。

参数:回调函数、回调函数

函数组件中可以定义多个effect,将函数组件中同类逻辑放在同一个effect中

  // 相当于 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 使用浏览器的 API 更新页面标题
    document.title = `You clicked ${count} times`;
  });
// 组件被渲染时执行useEffect函数,组件被销毁执行useEffect中的return
// 返回一个函数:effect的可选清除机制,每一个effect都可以返回一个清除函数。react会在卸载的时候执行清除操作。
import React, { useState, useEffect } from 'react';

export default function MultiEffectHookDemo() {
  const [count, setCount] = useState(0);
  const [isLogin, setIsLogin] = useState(true);
  // 当count改变了执行当前effect
  useEffect(() => {
    console.log('修改DOM', count);
  }, [count]);

  useEffect(() => {
    console.log('订阅事件');
    return () => {
      console.log('取消订阅事件');
    };
  }, []);
  // 将isLogin作为effect依赖项,当isLogin发生改变则执行网络请求
  useEffect(() => {
    console.log('网络请求');
  }, [isLogin]);
  const setCounter = () => {
    setCount(count + 1);
  };
  const setLogin = () => {
    setIsLogin(!isLogin);
  };
  return (
    <div>
      <h2>MultiEffectHookDemo</h2>
      <h2>{count}</h2>
      <button onClick={setCounter}>+1</button>
      <h2>{isLogin ? 'admin' : '未登录'}</h2>
      <button onClick={e => setIsLogin(!isLogin)}>注册/登录</button>
      <button onClick={setLogin}>登录/注销</button>
    </div>
  );
}

第二个参数:传入数组类型(性能优化),监听依赖变量改变后再执行回调函数

  • 不传:每次都会更新
  • 传入空数组:只会执行一次
  • 传入依赖变量:在依赖变量发生改变执行
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新

5、useContext

接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。

当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider>value prop 决定。

当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value

父组件

// 创建context对象 
import React, { createContext } from 'react';
export const UserContext = createContext();

<UserContext.Provider value={{name:'Jack'}}>
    <ContextHookDemo/>
</UserContext.Provider>

子组件

import React, { useContext } from 'react';
import {UserContext} from "../App"

通过user拿到父组件共享过来的数据(对应的就是父组件传递的context对象)
const user = useContext(UserContext)

6、useReducer

useState的一种替代方案,主要是在处理逻辑复杂用于拆分,或者需要依赖原来的state时使用

reducer共享的仅仅是操作函数,数据不会共享

// home.js
import React, { useReducer } from 'react';

import reducer from './reducer';

export default function Home() {
  const [state, dispatch] = useReducer(reducer, { counter: 0 });
  const addCount = () => {
    dispatch({
      type: 'increment',
    });
  };
  return (
    <div>
      <h2>Home当前计数: {state.counter}</h2>
      {/* <button onClick={e => dispatch({ type: 'increment' })}>+1</button> */}
      <button onClick={addCount}>+1</button>
      <button onClick={e => dispatch({ type: 'decrement' })}>-1</button>
    </div>
  );
}
reducer.js
export default function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, counter: state.counter + 1 };
    case 'decrement':
      return { ...state, counter: state.counter - 1 };
    default:
      return state;
  }
}

7、userCallbcak

用途:性能优化。传入一个回调函数返回执行后的函数,在依赖不改变或者没有添加依赖的情况下,返回的永远是同一个函数

使用场景:将组件中的函数传递给子组件进行回调使用时,使用useCallback对函数进行处理,useCallback直接对值进行优化

8、useMemo

用途:性能优化,返回一个memoized值(可以是对象或函数等),在依赖不改变或者没有添加依赖的情况下,返回的永远是同一个值

useMemo传入一个回调函数,返回一个值作为usememo的返回值,可以传入依赖项,当依赖项发生改变后函数才会重新执行一次

场景: 在将一个组件中的函数, 传递给子元素进行回调使用时, 使用useCallback对函数进行处理.

const increment2 = useCallback(() => {
    console.log("执行increment2函数");
    setCount(count + 1);
  }, [count]);

<Button title="btn2" increment={increment2}/>

const Button = memo((props) => {
  console.log("Button重新渲染: " + props.title);
  return <button onClick={props.increment}>Button +1</button>
});

9、useRef

返回一个ref对象,返回的ref对象在组件的整个生命周期保持不变。

作用:

  • 获取DOM对象
  • 保存不变的值
// useRef引用DOM
import React, { useRef } from 'react';

export default function RefHookDemo01() {
  const titleRef = useRef();
  const inputRef = useRef();
  // 通过ref获取到对象的dom对象并修改值
  const changeDOM = () => {
    titleRef.current.innerHTML = 'Hello World';
    inputRef.current.focus();
    console.log(testRef.current);
  };
  return (
    <div>
      <h2 ref={titleRef}>RefHookDemo01</h2>
      <input ref={inputRef} type='text' />
      <button onClick={changeDOM}>修改DOM</button>
    </div>
  );
}

Refs 转发

父组件通过ref获取子组件中DOM元素

作用:获取子组件DOM

import { useRef, forwardRef } from 'react';

const Input = forwardRef((props, ref) => {
  return <input ref={ref} type='text' />;
});
function App() {
  const inputRef = useRef();
  const clearValue = () => {
    inputRef.current.value = '';
  };
  return (
    <div>
      <Input ref={inputRef} />
      <button onClick={clearValue}>清除</button>
      <button onClick={e => inputRef.current.focus()}>聚焦</button>
    </div>
  );
}
export default App;

10、useImperativeHandle

useImperativeHandle对forwardRef做限制,限制子组件暴露过多内容给父组件

推荐:在使用forwardRef获取子组件时一起使用useImperativeHandle

childInputRef和fatherInputRef命名不影响,可以相同也可以不同

import { useRef, forwardRef, useImperativeHandle } from ‘react’;

const Input = forwardRef((props, ref) => {

const childInputRef = useRef();

useImperativeHandle(

ref,

() => ({

//父组件需要其他操作则暴露对应的函数

focus: () => {

​ childInputRef.current.focus();

},

}),

[childInputRef]

);

return <input ref={childInputRef} type=‘text’ />;

});

function App() {

const fatherInputRef = useRef();

return (

<div>
import { useRef, forwardRef, useImperativeHandle } from 'react';

const Input = forwardRef((props, ref) => {
  const childInputRef = useRef();
  useImperativeHandle(
    ref,
    () => ({
      //父组件需要其他操作则暴露对应的函数
      focus: () => {
        childInputRef.current.focus();
      },
    }),
    [childInputRef]
  );
  return <input ref={childInputRef} type='text' />;
});
function App() {
  const fatherInputRef = useRef();
  return (
    <div>
      <Input ref={fatherInputRef} />
      <button onClick={e => fatherInputRef.current.focus()}>聚焦</button>
    </div>
  );
}
export default App;

11、useLayoutEffect

useEffect:渲染DOM更新后执行,不会阻塞DOM的更新

useLayoutEffect:渲染的内容更新到DOM上之前更新,会阻塞DOM更新

12、自定义hook

本质上:一种函数代码逻辑的抽取。将相同的逻辑抽取到单独的函数中,自定义hook需要使用use开头

自定义hook实现:Context共享数据

// app.js
import React, { createContext } from 'react';
// 新建context对象并导出
export const UserContext = createContext();
export const TokenContext = createContext();
// 给对应的context上添加value
<UserContext.Provider value={{name: "w", age: 18}}>
        <TokenContext.Provider value="fdafdafafa">
          <CustomContextShareHook/>
        </TokenContext.Provider>
      </UserContext.Provider>
user-hook.js
// 拿到app.js中提供的值,并作为函数返回值导出
import { useContext } from "react";
import { UserContext, TokenContext } from "../App";
function useUserContext() {
  const user = useContext(UserContext);
  const token = useContext(TokenContext);
  return [user, token];
}
export default useUserContext;
context.js
// 在需要使用的组建中导入自定义hook,拿到里面提供的值
import React, { useContext } from 'react';
import useUserContext from '../hooks/user-hook';
export default function CustomContextShareHook() {
  const [user, token] = useUserContext();
  console.log(user, token);
  return (
    <div>
      <h2>CustomContextShareHook</h2>
    </div>
  )
}

获取当前滚动到的位置

// scroll-position-hook.js
import { useState, useEffect } from 'react';
function useScrollPosition() {
  const [scrollPosition, setScrollPosition] = useState(0);
  useEffect(() => {
    const handleScroll = () => {
      setScrollPosition(window.scrollY);
    }
    document.addEventListener("scroll", handleScroll);

    return () => {
      document.removeEventListener("scroll", handleScroll)
    }
  }, []);
  return scrollPosition;
}

export default useScrollPosition;
// scroll.js
import React from 'react';
import useScrollPosition from '../hooks/scroll-position-hook';

export default function CustomScrollPositionHook() {
  const position = useScrollPosition();

  return (
    <div style={{ padding: '1000px 0' }}>
      <h2 style={{ position: 'fixed', left: 0, top: 0 }}>CustomScrollPositionHook: {position}</h2>
    </div>
  );
}
// 本地存储
// 一般写法
import React, { memo, useState, useEffect } from 'react';

export default memo(function App() {
  const [name, setName] = useState(() => {
    const name = JSON.parse(window.localStorage.getItem('name'));
    return name;
  });
  useEffect(() => {
    window.localStorage.setItem('name', JSON.stringify(name));
  }, [name]);
  return (
    <div>
      <h2>{name}</h2>
      <button onClick={e => setName('wingchiehpih')}>设置name</button>
    </div>
  );
});
// 自定义hook
import {useState, useEffect} from 'react';

function useLocalStorage(key) {
  const [name, setName] = useState(() => {
    const name = JSON.parse(window.localStorage.getItem(key));
    return name;
  });

  useEffect(() => {
    window.localStorage.setItem(key, JSON.stringify(name));
  }, [name]);

  return [name, setName];
}

export default useLocalStorage;

// localstorage.js
import React from 'react';

import useLocalStorage from '../hooks/local-store-hook';

export default function CustomDataStoreHook() {
  const [name, setName] = useLocalStorage('name');

  return (
    <div>
      <h2>CustomDataStoreHook: {name}</h2>
      <button onClick={e => setName('kobe')}>设置name</button>
    </div>
  );
}

});

useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(name));
}, [name]);

return [name, setName];
}

export default useLocalStorage;

// localstorage.js
import React from ‘react’;

import useLocalStorage from ‘…/hooks/local-store-hook’;

export default function CustomDataStoreHook() {
const [name, setName] = useLocalStorage(‘name’);

return (


CustomDataStoreHook: {name}


<button onClick={e => setName(‘kobe’)}>设置name

);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值