HOOKS笔记

HOOKS学习笔记

类组件与函数组件的区别

类组件可以定义自己的state,用来保存自己的内部状态,类组件有自己的生命周期,可以在对应的生命周期中完成对应的逻辑操作。在componentDidMount发送网络请求,在数据更新时可以调用componentDidUpdate生命周期,在状态发生改变只会重新执行render函数

类组件中产生的副作用需要在componentWillUmmount中清除,比如redux中手动调用subscribe

函数组件不可以,函数每次调用都会产生新的临时变量,函数组件被重新渲染时,整个函数都会被重新执行

memo的作用:类似于类组件的pureC,会对props进行浅层比较,如果发生更新就重新渲染,如果没有发生更新就不会重新渲染

hooks

需要在react中导入

使用hooks的原则

只能在函数最外层调用Hook。不要在循环、条件判断或者子函数中调用。
只能在React 的函数组件中调用Hook。不要在其他JavaScript 函数,如果需要做条件判断,则可以将判断放到hook的内部

useState

用于保存状态

  // 声明一个叫 “count” 的 state 变量。
const [count, setCount] = useState(0);
const [firends, setFirends] = useState(['kobe', 'mar']);

useState的唯一参数就是初始state,

返回值是一个数组(当前state的值,设置新的值时使用的函数)

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

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

每次更改状态做的都是替换的操作

添加用户和修改用户年龄
import React, { useState } from 'react';

export default function ComplexHookState() {
  const [friends, setFrineds] = useState(['kobe', 'lilei']);
  const [students, setStudents] = useState([
    { id: 110, name: 'why', age: 18 },
    { id: 111, name: 'kobe', age: 30 },
    { id: 112, name: 'lilei', age: 25 },
  ]);
  const [person,setPerson] = useState({name:'李四',age:20})
  const incrementAgeWithIndex = index => {
    const newStudents = [...students];
    newStudents[index].age += 1;
    setStudents(newStudents);
  };
  const addFriends = () => {
    let newFriend = [...friends, 'tom'];
    setFrineds(newFriend);
  };
  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>
      <button onClick = {() => setPerson({name:'王五',age:30})}>setPerson</button>
    </div>
  );
}
useEffect

完成类组件中生命周期的功能:比如网络请求,手动更新DOM,事件监听。useEffect接收两个参数,第二个参数为可选参数,第一个参数为回调函数(在发生更新后就执行回调函数),在完成DOM更新后执行回调。

  // 相当于 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 使用浏览器的 API 更新页面标题
    document.title = `You clicked ${count} times`;
  });

订阅与取消订阅操作

组价被渲染时自动执行useEffect,当组件被销毁是执行useEffect中的return

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 ? 'coderwhy' : '未登录'}</h2>
      <button onClick={e => setIsLogin(!isLogin)}>注册/登录</button>
      <button onClick={setLogin}>登录/注销</button>
    </div>
  );
}

useEffect中返回一个函数:effect的可选清除机制,每一个effect都可以返回一个清除函数。react会在卸载的时候执行清除操作。

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

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新

如果仅传入空数组,不传入依赖变量,则useEffect只会执行一次

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:'byj'}}>
    <ContextHookDemo/>
</UserContext.Provider>

子组件

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

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

是useState的一种替代方案,主要是在处理逻辑复杂用于拆分,或者这次修改的state需要依赖之前的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;
  }
}
userCallbcak

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

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

useMemo

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

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

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

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

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

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

返回一个对象,返回的ref对象在组件的整个生命周期保持不变。用法:引入dom元素,保存一个数据,这个对象在整个生命周期中保持不变

useRef引用DOM
import React, { useRef } from 'react';

class TestCpn extends React.Component {
  render() {
    return <h2>TestCpn</h2>;
  }
}
export default function RefHookDemo01() {
  const titleRef = useRef();
  const inputRef = useRef();
  const testRef = useRef();
  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' />
      <TestCpn ref={testRef} />
      <button onClick={changeDOM}>修改DOM</button>
    </div>
  );
}
useImperativeHandle

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

原理使用forwardRef

import React, { useRef, forwardRef } from 'react';

const Input = forwardRef((props, ref) => {
  return <input ref={ref} type="text"/>
})

export default function ForwardRefDemo() {
  const inputRef = useRef();

  return (
    <div>
      <HYInput ref={inputRef}/>
      <button onClick={e => inputRef.current.focus()}>聚焦</button>
    </div>
  )
}

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

import React, { useRef, forwardRef, useImperativeHandle } from 'react';

const HYInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
      //父组件需要其他操作则暴露对应的函数
    focus: () => {
      inputRef.current.focus();
    }
  }), [inputRef])

  return <input ref={inputRef} type="text"/>
})

export default function UseImperativeHandleHookDemo() {
  const inputRef = useRef();

  return (
    <div>
      <HYInput ref={inputRef}/>
      <button onClick={e => inputRef.current.focus()}>聚焦</button>
    </div>
  )
}

useLayoutEffect

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

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

自定义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: "why", 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>
  )
}

获取当前滚动到的位置

scrill-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>
  );
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值