React高级用法

react高级用法

    • HOC
    • HOC的实现方式
      • 1. 属性代理 (对传入组件属性上的一些操作)
      • 2. 反向继承
    • Hooks
      • 1.useState
      • 2.useEffect
      • 3.useLayoutEffect
      • 4.useRef
      • 5.useContext
      • 6.useReducer
      • 7. useMemo useCallback
      • 自定义hooks

HOC

  • 含义:就是高阶组件,组件作为参数,返回的还是组件的函数
  • 特点:
    • 纯函数
    • 入参组件无法修改
    • 无副作用
  • 使用HOC的原因或好处
    1. 实现了重复代码抽离,组件复用,逻辑复用等问题
    2. 实现条件渲染
    3. 拦截入参组件的生命周期 拦截组件的渲染的性能 日志打点

HOC的实现方式

1. 属性代理 (对传入组件属性上的一些操作)

含义:就是用组件包裹一层代理组件,在代理组件上,可以做一些,对源组件的强化操作。
代理props

function HOC(WrappedComponent){
    const newProps = {name:'kevin'};
    return props => <WrappedComponent {...props} {...newProps}/>
}
// 类组件
function HOC(WrappedComponent){
    return class extends React.Component {
        render(){
            const newProps = {name:'kevin'};
            return props => <WrappedComponent {...this.props} {...newProps}/>
        }
    }
}
  • 抽象state
    function HOC(WrappedComponent){
        return class extends React.Component {
            constructor(props){
                super(props);
                this.state = {
                    name:'kevin'
                }
                this.onChange = this.onChange.bind(this)
            }
            onChange = (e)=>{
                this.setState({
                    name:e.target.value
                })
            }
            render(){
                const newProps={
                    value:this.state.name,
                    onChange:this.onChange,
                }
                return <WrappedComponent {...this.props} {...newProps}/>
            }
        }
    }
    
  • 条件渲染
    function HOC(WrappedComponent){
        return props => (
            <div>
                {
                    props.isShow ? <WrappedComponent {...this.props} /> : <p>暂无数据展示</p>
                }
            </div>
        )
    }
    function HOC(WrappedComponent){
        return class extends React.Component {
            render(){
                const newProps = {name:'kevin'};
                return props => (
                    <div style = {{width:'200px'}}>
                        <WrappedComponent {...this.props} {...newProps}/>
                    </div>
                )
            }
        }
    }
    

2. 反向继承

含义:继承传入的组件内容,即包装后的组件继承了原始组件本身,本质上是类的继承。

const HOC = WrappedComponent => {
    return class extends WrappedComponent {
        render(){
            return super.render();
        }
    }
}
// 针对组件的生命周期进行处理
function HOC(WrappedComponent){
    const didMount = WrappedComponent.prototype.componentDidMount;
    return class extends WrappedComponent{
        async componentDidMount(){
            if(didMount){
                await didMount.apply(this);
            }
        }
        render(){
            return super.render();
        }
    }
}
  • 操作state
  function HOC(WrappedComponent){
      const didMount = WrappedComponent.prototype.componentDidMount;
      const state = WrappedComponent.prototype.state;
      return class extends WrappedComponent{
                  constructor(props){
                      super(props);
                      this.state = {
                          number:0
                      }
                  }
                  async componentDidMount(){
                      if(didMount){
                          await didMount.apply(this);
                      }
                      this.setState({
                          number:123,
                          ...state,
                      })
                  }
                  render(){
                      return super.render();
                  }
              }
  }
  • 条件渲染
const HOC = (WrappedComponent) => {
  return class extends WrappedComponent {
      render(){
          if(this.props.isShow){
              return super.render();
          }else{
              return <div>暂无数据</div>
          }
      }
  }
}
  • 修改返回的react结构
const HOC = (WrappedComponent) => {
  return class extends WrappedComponent {
      render(){
          const tree = super.render();
          const newProps = {};
          if(tree?.type === 'input'){
              newProps.value = '开始自律';
          }
          const props = {
              ...tree.props,
              ...newProps,
          }
          return React.cloneElement(tree,props,tree.props.children)
      }
  }
}
  • 代码复用

       // import fetchMovieListByType from '.xxx';
       // import MovieList from './components/xxxx';
    
        class Comody extends React.Component {
            state = {
                movieList:[]
            }
            async componentDidMount(){
                const movieList = await fetchMovieListByType("Comody");
                this.setState({
                    movieList
                })
            }
            render(){
                return <MovieList data={this.data.movieList} emptyTips="empty Comody">
            }
        }
    
        class Action extends React.Component {
            state = {
                movieList:[]
            }
            async componentDidMount(){
                const movieList = await fetchMovieListByType("Action");
                this.setState({
                    movieList
                })
            }
            render(){
                return <MovieList data={this.data.movieList} emptyTips="empty Action">
            }
    
        }
    

    使用HOC

    const withFetchimgHoc = (WrappedComponent,fetchingMethod,defaultProps) => {
        return class extends React.Component {
            async componentDidMount(){
                const movieList = await fetchingMethod();
                this.setState({
                    movieList
                })
            }
            render(){
                return <WrappedComponent data={this.data.movieList} {...defaultProps} {...this.props}>
            }
        }
    }
    
    withFetchimgHoc(MovieList,fetchMovieListByType("Action"),{emptyTips:'empty Action'})
    withFetchimgHoc(MovieList,fetchMovieListByType("Comody"),{emptyTips:'empty Comody'})
    
  • 组件渲染所耗费的时间

    class Home extends React.component {
        render(){
            return <h1>Hello chongqing</h1>
        }
    }
    function withTime(wrappedComponent){
        let state,end;
        return class extends wrappedComponent {
            constructor(props){
                super(props);
                start = 0;
                end = 0;
            }
            componentWillMount(){
                super?.componentWillMount();
                start = +Date.now()
            }
            componentDidMount(){
                super?.componentDidMount();
                end = +Date.now();
                this.logger(`使用组件渲染时间:${end - start}ms`)
            }
            render(){
                return super.render();
            }
        }
    }
    

Hooks

React Hooks: https://zh-hans.react.dev/reference/react
Hooks 用于函数式组件

1.useState

const [state,setState] = useState(0);

2.useEffect

// 模拟数据交互
function getUserInfo(a){
    return new Promise((resolve) => {
        setTimeout(()=>{
            resolve({
                name:a,
                age:18,
            })
        },500)
    })
}
const Demo = ({a}) => {
    const [userMessage,setUserMessage] = useState({});
    const [number,setNumber] = useState(0);

    const div = useRef();
    const handleResize = () =>{};

    useEffect(() => {
        getUserInfo(a).then(res => {
            setUserMessage(res);
        })
        console.log(div.current);
        window.addEventListener('resize',handleResize)
        /**
         * 只有当 props -> a 和 state -> number改变的时候,useEffect副作用函数重新执行
         *  如果此时数组为空,证明函数只有在初始化的时候执行一次相当于componentDidMount 
         */
    },[a,number]) // 可以是 deep object
    
    useEffect(()=> {
        const timer = setInterval(()=>console.log(666),1000);
        window.addEventListener('resize',handleResize);
        // 此函数用于消除副作用  => 可以认为是退出组件的时候去执行
        return function () {
            clearInterval(timer);
            window.removeEventListener('resize',handleResize)
        }
    },[a])
    /*------useEffect 不能用于异步,即不能如下:------------*/ 
    useEffect(async ()=>{
        // 请求数据
        const res = await getUserInfo(payload);
    },[a,number])
    useEffect(()=>{
        // declare the async data fetching function
        const fetchData = async()=>{
            const data = await fetch('https://xxx.com');
            const json = await data.json();
        }
        // call the function
        const result = fetchData().then(console.error);
        // ❌ 无效
        setData(result);
    },[])
    /*------改进------------*/
    useEffect(()=>{
        const fetchData = async()=>{
            const data = await fetch('https://xxx.com');
            const json = await response.json();
            setData(json);
        }
        // call the function
        fetchData()
            // make sure to catch any error
            .catch(console.error)
    },[])
    // 或者
    useEffect(()=>{
        fetchData();
    },[])
    const fetchData = async()=>{}
    return (
        <div ref={div}>
            <span>{userMessage.name}</sapn>
            <span>{userMessage.age}</sapn>
            <div onClick={()=>setNumber(2)}>{number}</div>
        </div>
    )
}

3.useLayoutEffect

  • 功能类似,对比一下具体执行顺序是怎样的
    • useEffect: 组件更新挂载 VDOM -> 触发真实页面DOM更新 -> 触发useEffect callback //触发所谓的第一个方法 页面闪动
    • useLayoutEffect: 组件更新挂载 VDOM -> useLayoutEffect callback -> 渲染DOM的更新 类似卡顿效果

4.useRef

作用:获取真实元素DOM标签的方式

const DemoUseRef = () => {
    const dom = useRef(null);
    const handleSubmit = () => {
        console.log(dom.current)
    }
    return (
        <div>
            <div ref={dom}>div</div>
        </div>
    )
}
// 只想存储一个值,而不触发页面的渲染、视图的更新  => 变量更新
const currentRef = useRef(1);
currentRef.current = 2;

5.useContext

作用:类似于从全局中管控一个上下文的状态

/* 用useContext方式*/
const DemoContext = () => {
   const value = useContext(Context);
   return <div>my name is {value.name}</div>
}
/* 用Context.Consumer方式 */
const DemoContext1 = () => {
   return (
       <Context.Consumer>
           {(value) => <div>my name is {value.name}</div>}
       </Context.Consumer>
   )
}
export default () => {
   return (
       <div>
           <Context.Provider value = {{name:' 二娃'}}>
               <DemoContext/>
               <DemoContext1/>
           </Context.Provider>
       </div>
   )
}

6.useReducer

const DemoUseReducer = () => {
   /* number为更新后的state值,dispatchNumber 为当前的派发函数*/
   const[number,dispatchNumber] = useReducer((state,action) => {
       const {payload,name} = action;
       /*return 的值为新的state*/
       switch(name){
           case 'a':
               return state + 1;
           case 'b':
               return state - 1;
           case 'c':
               return payload;
       }
       return state;
   },0);
   return (
       <div>
           当前值{number}
           {/*派发更新*/}
           <button onClick={() =>dispatchNumber({name:'a'})}>增加</button>
           <button onClick={() =>dispatchNumber({name:'b'})}>减少</button>
           <button onClick={() =>dispatchNumber({name:'c',payload:888})}>赋值</button>
           {/*把dispatch 和state传递给子组件*/}
           <MyChildren dispatch={dispatchNumber} State={{number}}/>
           <Context.Provider value = {{dispatchNumber , number}}>
           </Context.Provider>
       </div>
   )
}

7. useMemo useCallback

进行性能优化

useMemo(()=>{
   <div>
   list.map(i => (
       <span>{i.xxx}</span>
   ))
},[list])
  • useMemo :返回callback的运行结果 // 开发中用useMemo作为缓存的依赖项
  • useCallback : 用于缓存需要在组件中多次调用的回调函数。它接受两个参数:回调函数和依赖数组。当依赖数组中的任何一个值发生变化时,useCallback 将会返回一个新的回调函数,否则将会返回之前缓存的回调函数。返回的就是callback的函数 // 在开发中用useCallback作为缓存的一个方法,在需要时调用

自定义hooks

强调的是一种函数式编程的思维
const [] = useXXX();

import {useEffect} from 'react';
const useTitle = (title) => {
    useEffect(() => {
        document.title = title;
    },[]);
}
export default useTitle
// 在别的react组件这样去调用
import useTitle from './xxx';
const App = () => {
    useTitle("1243");
    return <div>234</div>
}

你可能感兴趣的:(React高级用法)