Hook

2019-09-25  本文已影响0人  我的钱包瘪瘪的

Hook

概念和特点

  1. 概念: React16.8,没有破坏性改动, 不影响前面class的使用, 且向后兼容

  2. 特点:

  Hook 使你在无需修改组件结构的情况下复用状态逻辑(提供原生的方法共享状态, 避免props值传递或者高阶组件的嵌套地狱)

  Hook 加强开发体验, 减少使用状态管理库时所需要的额外抽象概念, 和来回切换组件的状况

  Hook 将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据)

  Hook 则拥抱了函数, class不能很好的压缩,并且会使热重载出现不稳定的情况
  1. 注意:

       1. 无需修改组件结构状态下, 复用状态逻辑
    
       2. 在函数最外层调用 Hook, 不能在循环、条件判断或者子函数 class类中调用
    
       3. 不影响原先class类的使用
    

useState

const Button = () => {
  // 多状态, 可以是值/引用类型
  const [fruits, setFruits] = useState(["banana", "apple"]);
  // 直接声明方法, 进行更改state
  return <button onClick={() => setFruits([...fruits, "Mango"])}>添加</button>;
};
// hook是闭包的方式返回state, 每次更新返回的是闭包存储的值, 而不是最新值
const [count, setCount] = useState(0);
const alterCount = () => {
  setTimeout(() => {
    alert(count);
  }, 3000);
};
return (
  <>
    <button onClick={() => setCount(count + 1)}>
      {" "}
      点击count+1 : {counter}{" "}
    </button>
    <button onClick={() => alterCount}> 获取点击发生时的count </button>
  </>
);

useRef

  1. 概念: 相比于 state, seRef 会成为纽带, 每次获得的都是最新的, 但不会引起组件更新
const domRef = useRef(0);
// 当dom节点挂载 成功时候
useEffect(() => {
  if (domRef && domRef.current) {
    domRef.current.focus();
  }
}, []);
return <input type="text" ref={domRef} />;
const didMountRef = useRef(false);
useEffect(() => {
  if (didMountRef.current) {
    console.log("首次加载");
  } else {
    didMountRef.current = true;
  }
});
// useRef实时变化, 但并不会引起dom重新变化, 对比count变化
const countRef = useRef(0);
const [count, setCount] = useState(0);
const alterCount = () => {
  setTimeout(() => {
    alert(countRef.current);
    alert(count);
  }, 3000);
};
const handleClick = () => {
  setCount(count + 1);
  countRef.current = count + 1;
};
return (
  <>
    <button onClick={handleClick}>点击{count}</button>
    <button onClick={alterCount}> 获取点击发生时的count </button>
  </>
);

EffectHook

自定义钩子

// 自定义钩子, 封装api请求
const useURLLoader = (url: string, deps: any[] = []) => {
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState(null);
  useEffect(() => {
    setLoading(true);
    axios.get(url).then(result => {
      setData(result.data);
      setLoading(false);
    });
  }, deps);
  return [data, loading];
};

// 使用自定义钩子
const Demo = () => {
  // 依赖有变化, 重新请求
  const [data, loading] = useURLLoader("/api/xxx", [show]);
};
// 自定义钩子
const useGetContentWidth = () => {
  const [size, setSize] = useState({
    width: document.body.clientWidth,
    height: document.body.clientWidth
  });

  const onResize = useCallback(() => {
    setSize({
      width: document.body.clientWidth,
      height: document.body.clientWidth
    });
  }, []);

  useEffect(() => {
    window.addEventListener("resize", onResize);
    return () => {
      window.removeEventListener("resize", onResize);
    };
  }, []);
  return size;
};
// 使用
const Demo = () => {
  const { width, height } = useGetContentWidth();
};

useCallback

  1. 概念: 缓存函数
const Demo = () => {
  const [count, setCount] = useState(0);
  // hook本质是函数, 每次需要重新生成handleClick
  // useCallback, 把函数缓存, 只有当, 依赖变化, 才重新返回
  const handleClick = useCallback(e => {
    setCount(count + 1);
  }, []);
  return <button onClick={handleClick}>变更count</botton>;
};

useMemo

  1. 概念: 缓存值, 理由与 useCallback 一致

useContext

  1. 概念: 全局数据存储
  1. context 的声明
//  context.js
const themes = {
  light: {
    color: "#000",
    background: "#eee"
  },
  dark: {
    color: "#fff",
    background: "#222"
  }
};

const ThemesContext = React.createContext({
  themes: themes.light,
  toggleTheme: () => {}
});
export { ThemesContext, themes };
  1. Provider, context 的提供者
import { ThemesContext, themes } from "./context";
const App = () => {
  const { Provider } = ThemesContext;
  const toggleTheme = () => {
    if (themeItem.color === "#fff") {
      setThemeItem(themes.light);
    } else {
      setThemeItem(themes.dark);
    }
  };
  return (
    <Provider value={
      themes: themeItem,
      toggleTheme
    }>
      <Child />
    </Provider>
  );
};
  1. Consumer, Context 的消费者
// child.js, 点击触发更改
import { ThemesContext } from "../context";
const theme = React.useContext(ThemesContext);
console.log(theme);
return <button onClick={theme.toggleTheme}>变更Context</button>;

useReducer

import React, { useState, Fragment, useEffect, useReducer } from "react";

const initialState = { count: 0 };
// 纯函数
// 接受: 前一次的state值, 还有需要做的操作
// 返回: 返回新的state值
const reducer = (state, action) => {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
};

export const Hook = () => {
  // const [state, dispatch] = useReducer(reducer, initialArg, init);
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </>
  );
};
上一篇下一篇

猜你喜欢

热点阅读