react hooks学习总结

react hooks学习总结

react hooks优点

1:解决了class组件状态逻辑难以复用的问题
2:解决了class组件复杂难以维护的问题

  • 生命周期函数中包含了很多不相干的逻辑,比如componentDidUpdate中只要一个字段发生变化都会触发,为了优化这种场景会写很多的优化逻辑;

  • 类组件中到处都是对状态的访问和处理,导致组件难以拆分成更小的组件;

3:解决了类组件中this的问题
4:解决了函数组件中不能有自己状态的问题

常用的hooks

useState,
const [status, setStatus] = useState(initState);
当使用多个useState的时候必须保证每次他们的调用顺序是一样的;
initState可以是一个函数,用来处理initState需要经过复杂计算得到;

useEffect,

useEffect(() => {
return () => {};
}, [a, b]);
  • 第一个参数相当于class组件的componentDidMount和componentDidUpdate,return值相当于componentWillUnmount,第二个参数是一个数组,表示依赖项,只有依赖项发生改变时,第一个函数参数才会执行;
  • 每次组件重新运行effect都会清除上一个effect,组件卸载的时候也会执行清除副作用的函数;
  • 当第二个参数不传递时,每次组件重新渲染都会重新运行effect(默认是依赖所有); useEffect会在dom更新完成后才会执行;
  • useEffect的返回值要么是一个函数要么什么都不返回,不能是async函数,他的返回值是一个promise;
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";

const BlinkyRender = () => {
  const [value, setValue] = useState(0);

  useEffect(() => {
    if (value === 0) {
      setValue(10 + Math.random() * 200);
    }
  }, [value]);

  console.log("render", value);

  return (
    <div onClick={() => setValue(0)}>value: {value}</div>
  );
};

ReactDOM.render(
  <BlinkyRender />,
  document.querySelector("#root")
);

useLayoutEffect,
useLayoutEffect和useEffect函数签名一致,区别是所有的effect会在组件渲染之后浏览器绘制之前同步执行;而useEffect是异步的,不会阻塞渲染

import React, { useState, useLayoutEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";

const BlinkyRender = () => {
  const [value, setValue] = useState(0);

  useLayoutEffect(() => {
    if (value === 0) {
      setValue(10 + Math.random() * 200);
    }
  }, [value]);

  console.log("render", value);

  return (
    <div onClick={() => setValue(0)}>value: {value}</div>
  );
};

ReactDOM.render(
  <BlinkyRender />,
  document.querySelector("#root")
);

useReducer,

const [state, dispatch] = useReducer(reducer, initialArg, init);

reducer类似于redux中的reducer,

const reducer = (state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
  }
}

initialArg用来初始化state;
如果设置了第三个参数init函数,那么state的初始值会被设置为init(initArg)
dipatch是一个引用类型,会一直保持不变;
useReducer中每次取到的state都是最新的值;

useMemo,

const f2 = useMemo(() => {}, [a, b])

只要a和b的值保持不变,f2的值一直保持不变,一直是第一个入参函数的调用值,第一个入参函数一直不会执行;

useCallback,

const f1 = useCallBack(() => {}, [a, b]);

只要依赖项a和b保持不变,函数f1一直保持不变,也即是f1一直是第一个入参函数
一般用来缓存一些计算量比较大的运算,节省内存

useContext,
接收context对象(React.creatContext({})创建的对象),并返回该对象的当前值;
useContext用来获取context的值并且订阅context的变化;
使用示例

const themes = {
 light: {
   foreground: "#000000",
   background: "#eeeeee"
 },
 dark: {
   foreground: "#ffffff",
   background: "#222222"
 }
};
 
const ThemeContext = React.createContext(themes.light);
function App() {
 return (
   <ThemeContext.Provider value={themes.dark}>
     <ThemedButton />
   </ThemeContext.Provider>
 );
}
function ThemedButton() {
 const theme = useContext(ThemeContext);
 return (
   <button style={{ background: theme.background, color: theme.foreground }}>
     I am styled by theme context!
   </button>
 );
}

useRef

const refContainer =  useRef(initialValue);

refContainer保存的是一个可变的值, 在整个组件的生命周期内保持不变,是一个引用类型;
initialValue是refContainer.current初始值;
通过改变refContainer.current的值来解决一些react hooks开发过程中遇到的闭包问题;参考文章

useRef+forwardRef+useImperativeHandle

const  = useImperativeHandle(ref, createHandle, [deps]);

通过useRef+forwardRef+useImperativeHandle来控制暴露给父组件的ref值;

function Child(props, ref) {
 const inputRef = useRef();
 useImperativeHandle(ref, () => ({
   focus: () => {
     inputRef.current.focus();
   }
 }));
 return <input ref={inputRef} />;
}
Child = forwardRef(Child);
function Parent() {
 const parentRef = useRef();
 const handleClick = () => {
   parentRef.current.focus();
 }
 return (
   <div>
     <Child  ref={parentRef}/>
     <Button onClick={handleClick}>点我</Button>
   </div>
 );
}

//下面两个hooks是react-redux中提供的hooks

useSelector

import {useSelector} from 'react-redux';
const state = useSelector(state => state.someState)

useDispatch

import {useDispatch} from 'react-redux';
const dispatch = useDispatch();

自定义hook:
以use开头并且使用了其他hook

hooks使用注意事项

hooks只能在react 函数组件中以及自定义hooks中使用, 不能用在js普通函数以及类组件中;
hooks只能用在函数顶部,保证每次组件渲染时hooks的执行顺序是一样的,不能用在条件语句,循环语句以及嵌套函数中;

hooks原理简介

todo:

eslint规则校验

npm install eslint-plugin-react-hooks --save-dev
// 你的 ESLint 配置

{
 "plugins": [
   // ...
   "react-hooks"
 ],
 "rules": {
   // ...
   "react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则
   "react-hooks/exhaustive-deps": "warn" // 检查 effect 的依赖
 }
}
高阶组件Hoc,renderProps和hooks的区别?

Hoc:一个纯函数,接收一个组件并返回另一个组件;redux的connect就是通过高阶组件实现的;

withMouse(withPage(MyComponent))

缺点:组件参数容易被串改(组件本身容易被改写,组件参数统一高阶组件覆盖);包装组件参数不知道数据来源比较难调试;

const MyComponent = () => {
  return (
    <Mouse>
      {({ x, y }) => (
        <Page>
          {({ x: pageX, y: pageY }) => (
            <Connection>
              {({ api }) => {
                // yikes
              }}
            </Connection>
          )}
        </Page>
      )}
    </Mouse>
  )

renderProps: 该组件通过属性函数(render或者children)返回一个react元素实现自己的渲染逻辑;react-router是通过renderProps实现的;
缺点:容易造成嵌套地狱;

<Mouse>
 {
   (position) => {
     return <Cat position={position} />
   }
 }
</Mouse>
class Mouse extends React.PureComponent {
 ...逻辑
 return (
   this.props.children(data)
 )
}
参考文章

https://juejin.im/post/5dbbdbd5f265da4d4b5fe57d#heading-30

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值