一、为什么要用React Hook

1. 官方介绍

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

2. 组件类的几个缺点

  1. 大型组件很难拆分和重构,也很难测试
    ① 业务变得复杂之后,组件之间共享状态变得频繁,此时组件将变得非常难以理解和维护,复用状态逻辑更是难上加难
    ② 如果使用redux和其中间件, 又将极大的加大项目的复杂度和体积 , 而且需要按照一套严格的标准去写组件和redux,才能保证一定的可维护和可扩展性
  2. 业务逻辑分散在组件的各个方法之中,导致重复逻辑或关联逻辑
  3. 组件类引入了复杂的编程模式,比如 render props 和高阶组件

3. 解决方案

  1. 提出思路
    React 团队希望,组件不要变成复杂的容器,最好只是数据流的管道
    ① 开发者根据需要,组合管道即可
    ② 组件的最佳写法应该是函数,而不是类
    React 早期版本也支持函数组件
    ① 但是,这种写法有重大限制,必须是纯函数,不能包含状态
    ② 也不支持生命周期方法,因此无法取代类
  2. React Hooks 诞生:React Hook 就是加强版函数组件,完全不使用"类",就能写出一个全功能的组件

二、什么是React Hook

1. 什么是React Hook

  1. Hook
    钩子

  2. React Hooks 含义
    ① 组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来
    ② React Hooks 就是那些钩子

  3. 使用React Hook
    ① 概念

    1. React 默认提供了一些常用钩子
    2. 我们也可以封装自己的钩子
    3. 所有的钩子都是为函数引入外部功能,所以 React 约定,钩子一律使用use前缀命名,便于识别
    4. 你要使用 xxx 功能,钩子就命名为 usexxx

    ② 常用钩子

    1. useState()
    2. useContext()
    3. useReducer()
    4. useEffect()
  4. 案例实操
    ① useState基本使用

    // 1. 常规写法
    // import React from 'react'
    //
    // export default class Like001 extends React.Component {//     state = {//         age: 0
    //     }
    //
    //     render() {//         return (
    //             <div>
    //                 <h2>我今年{this.state.age}岁了!</h2>
    //                 <button onClick={() => this.setState({age: this.state.age + 1})}>按钮</button>
    //             </div>
    //         );
    //     }
    // }// 2. hook使用 ——> useState
    import React, {useState} from 'react'export default () => {// 2.1 使用钩子const [age, setAge] = useState(0);const name = useState('KaiSarH')return (<div><h1>老子是{name}</h1><h2>我今年{age}岁了!</h2><button onClick={() => setAge(age + 1)}>按钮</button></div>)
    }
    

    ② useEffect基本使用

    // 1. 常规写法
    // import React from 'react'
    //
    // export default class Like001 extends React.Component {//     state = {//         count: 0
    //     }
    //
    //     componentDidMount() {//         document.title = `点击了${this.state.count}次!`
    //     }
    //
    //     componentDidUpdate(prevProps, prevState, snapshot) {//         document.title = `点击了${this.state.count}次!`
    //     }
    //
    //     render() {//         return (
    //             <div>
    //                 <h2>点击了{this.state.count}次!</h2>
    //                 <button onClick={() => this.setState({count: this.state.count + 1})}>增加</button>
    //             </div>
    //         );
    //     }
    // }// 2. hook使用 ——> useState、useEffect
    import React, {useState, useEffect} from 'react'export default () => {const [count, setCount] = useState(0);// useEffect——componentDidMount componentDidUpdate componentWillUnmountuseEffect(() => {document.title = `点击了${count}次`});return (<div><h2>点击了{count}次!</h2><button onClick={() => setCount(count + 1)}>按钮</button></div>)
    }
    

    ③ todo简单案例
    useEffect第二个参数运用

    1. []相当于生命周期函数的:componentDidMount
    2. 有第二个参数:相对于生命周期函数:componentDidMount componentDidUpdate
    3. [count]:只监听count发生改变的时候,才会触发 componentDidUpdate
      // // 1. 常规写法
      // import React from 'react'
      //
      // export default class Like003 extends React.Component {//     state = {//         count: 0,
      //         name: 'KaiSarH'
      //     }
      //
      //     componentDidMount() {//         document.title = `点击了${this.state.count}次!`
      //     }
      //
      //     componentDidUpdate(prevProps, prevState, snapshot) {//         // document.title = `点击了${this.state.count}次!`
      //         if (prevProps.count !== this.state.count) {//             document.title = `点击了${this.state.count}次!`
      //         }
      //     }
      //
      //
      //     _dealCountClick() {//         this.setState({//             count: this.state.count + 1
      //         })
      //     }
      //
      //     _dealNameClick() {//         // let name = this.state.name === 'King James' ? 'KaiSarH' : 'King James';
      //         this.setState({//             name: 'King James'
      //         })
      //     }
      //
      //     render() {//         return (
      //             <div>
      //                 <h2>点击了{this.state.count}次!</h2>
      //                 <p>{this.state.name}</p>
      //                 <button onClick={() => this._dealCountClick()}>数量</button>
      //                 <button onClick={() => this._dealNameClick()}>名字</button>
      //             </div>
      //         );
      //     }
      // }// 2. hook使用 ——> useState、useEffect
      import React, {useEffect, useState} from 'react'export default () => {const [count, setCount] = useState(0);const [name, setName] = useState('KaiSarH');/** 1. 如果不加第二个参数,默认是执行:componentDidMount componentDidUpdate* 2. 加了中括号,默认执行componentDidMount* 3. [状态]:只有状态发生改变时,才能触发componentDidUpdate* */useEffect(() => {console.log('执行了·······')document.title = `点击了${count}次`// return 中返回的相当于在componentWillUnMountreturn {}}, [count])return (<div><h2>姓名:{name}</h2><h2>次数:{count}</h2><button onClick={() => setCount(count + 1)}>加一</button><button onClick={() => setName('King James')}>名称</button></div>)
      }
      
    4. return:相当于componentWillUnmount
      // 1. 常规写法
      import React, {useState, useEffect} from 'react'
      import ReactDOM from 'react-dom'const AgeAPI = {age: 0,subscribe(callBack) {this.intervalId = setInterval(() => {console.log('定时器正在执行')this.age += 1;callBack(this.age);}, 1000);},unsubscribe() {clearInterval(this.intervalId);}
      };// class Like004 extends React.Component {//     state = {//         age: 0
      //     }
      //
      //     componentDidMount() {//         AgeAPI.subscribe((age) => {//             this.setState({//                 age
      //             })
      //         })
      //     }
      //
      //     componentWillUnmount() {//         AgeAPI.unsubscribe();
      //     }
      //
      //     render() {//         return (
      //             <div>
      //                 <h2>我是树妖,今年{this.state.age}岁了!</h2>
      //                 <button onClick={() => ReactDOM.unmountComponentAtNode(document.getElementById('root'))}>砍树</button>
      //             </div>
      //         );
      //     }
      // }
      //
      // export default Like004;const Like004 = () => {const [age, setAge] = useState(0);useEffect(() => {AgeAPI.subscribe((currentAge) => {setAge(currentAge)})// 处理副作用代码,相当于在componentWillUnmountreturn () => {AgeAPI.unsubscribe();}}, [])return (<div><h2>我是树妖{age}</h2><button onClick={() => ReactDOM.unmountComponentAtNode(document.getElementById('root'))}>砍树</button></div>)
      }export default Like004;
      

    ⑤ hook中使用网络请求

    1. 基本使用

      import React, {useEffect, useState} from 'react'
      import ajax from "../http";const Like005 = () => {const [data, setDate] = useState(null);const [loading, setLoading] = useState(true);useEffect(() => {(async () => {const response = await ajax('http://demo.itlike.com/web/xlmc/api/homeApi/categoriesdetail/lk001?itlike=87224866875667849947')setDate(response.data.data);setLoading(false);})()}, [])return (<div>{loading ? <div>正在拼命加载中</div> : data.cate[0].name}</div>)
      }
      export default Like005;
      
    2. 自己包装一个钩子
      import React, {useEffect, useState} from 'react'
      import ajax from "../http";const useAjax = (url) => {const [data, setDate] = useState(null);const [loading, setLoading] = useState(true);useEffect(() => {(async () => {const response = await ajax(url)setDate(response.data.data);setLoading(false);})()}, [])return {data, loading}
      }
      const Like005 = () => {const {data, loading} = useAjax('http://demo.itlike.com/web/xlmc/api/homeApi/categoriesdetail/lk001?itlike=87224866875667849947');return (<div>{loading ? <div>正在拼命加载中</div> : data.cate[0].name}</div>)
      }
      export default Like005;
      

    ⑥ Hook 使用规则

    1. 网址
    2. 只在最顶层使用 Hook
    3. 只在 React 函数中调用 Hook

    ⑦ Hook中处理副作用操作
    ⑧ 性能优化:对比文档前后,如果没有变化就不进行渲染

    1. React.PureComponent

      import React from 'react'
      import Other from './other'// export default class Like008 extends React.Component
      export default class Like008 extends React.PureComponent{state = {age: 0};/*componentDidMount() {setInterval(()=>{this.setState({// age: this.state.age + 1age: 100})}, 1000);}*/componentDidMount() {setInterval(()=>{this.setState({age: this.state.age + 1})}, 1000);}render() {console.log('render被调用了~~~~');return (<div><Other otherName="撩课学院"/>{this.state.age}</div>)}
      }
      
    2. React.memo

      import React from 'react'const Other = ({otherName})=>{console.log('other组件中的render被调用了');return (<h3>我叫: {otherName}</h3>)
      };// export default Other
      export default React.memo(Other);
      

    ⑨ useCallback使用

    1. 示例

      const memoizedCallback = useCallback(() => {doSomething(a, b);},[a, b],
      );
      
    2. 实操
      ① 第二个参数决定了是否允许第一个参数执行
      ② 二个参数发生变化则允许执行,否则则不允许执行
      ③ 第一个参数第一次会执行一次,之后才会判断第二个参数是否发生变化然后再执行

      /*useCallback网址: https://zh-hans.reactjs.org/docs/hooks-reference.html#usecallbackconst memoizedCallback = useCallback(() => {doSomething(a, b);},[a, b],
      );
      - 第二个参数b决定了是否允许第一个参数执行
      - 第一个参数第一次会执行, 之后会根据第二个参数的变化决定是否执行
      */
      import React, {useState, useCallback} from 'react'const Like009 = ()=>{const [age, setAge] = useState(1);const [weight, setWeight] = useState(50);function clickHandler() {setAge(age + 1);}return (<div><p>年龄: {age} 岁</p><button onClick={clickHandler}>年龄+1</button><p>体重: {weight}千克</p>{/*<button onClick={()=>{setWeight(weight + 1)}}>体重+1</button>*/}<button onClick={useCallback(()=> setWeight(weight + 1), [age])}>体重+1</button></div>)
      };export default Like009;
      

    ⑩ usereducer [网址](https://zh-hans.reactjs.org/docs/hooks-reference.html#usereducer)

    import React, {useState, useReducer} from 'react'const initialState = {count: 0
    };function reducer(state, action) {switch (action.type) {case "increment":return {count: state.count + 1};case "decrement":return {count: state.count - 1}}
    }function Counter() {const [state, dispatch] = useReducer(reducer, initialState);return (<div>计算结果: {state.count}<button onClick={()=>dispatch({type: 'increment'})}>+</button><button onClick={()=>dispatch({type: 'decrement'})}>-</button></div>)
    }export default Counter;
    

    ⑪ usecontext

    import React, {useContext} from 'react'const themes = {dark: {width: 100,height: 40,borderRadius: 10,border: 'none',color: 'green',backgroundColor: 'orange'}
    };const ThemeContext = React.createContext();function App() {return (<ThemeContext.Provider value={themes.dark}><ToolBar /></ThemeContext.Provider>)
    }function ToolBar() {return (<div><ThemedButton /></div>)
    }function ThemedButton() {const theme = useContext(ThemeContext);console.log(theme);return (<button style={theme}>点我一下</button>)
    }export default App;
    

React:Hook相关推荐

  1. React全Hook项目实战在线聊天室历程(三):加个音乐直播?

    前情提要: React全Hook项目实战在线聊天室历程(一):基本功能 React全Hook项目实战在线聊天室历程(二):引用与话题功能 正文 聊天应该有什么?背景音乐,茶与酒,零食,后两个我是没法实 ...

  2. linux钩子函数和回调函数,Linux Kernel 学习笔记10:hook函数

    (本章基于: Linux -4.4.0-37) linux 内核中有一套hook函数机制,可在不同hook点位置监控网络数据包,并执行丢弃.修改等操作.网络防火墙就是通过此机制实现的. 注册注销hoo ...

  3. 读书笔记《React:引领未来的用户界面开发框架》

    <React:引领未来的用户界面开发框架>(GitHub 附demo版) 1.Component的创建与复合 1.1 React简介 背景介绍,全书概览 1.本质上是一个状态机,它以精简的 ...

  4. React:开发者工具谷歌插件下载安装

    React:开发者工具谷歌插件 最近学习前端react主要是想大概浏览一下,这里提供尚硅谷的是视屏资料中的谷歌插件的下载. (如有侵权联系删除) 这里提供我的下载地址,其中除了插件,还有一起案例源码, ...

  5. React:Component组件

    组件允许开发者将复杂的UI页面拆分为独立可复用的代码片段,并对每个代码片段进行独立构思.React中的组件,在概念上类似于JavaScript函数,它接收任意的入参(对应当该组件的props属性),返 ...

  6. react:hash_亲爱的React:感谢信

    react:hash by Alex Vervloet 由Alex Vervloet 亲爱的React:感谢信 (Dear React: A thank you letter) Dear React, ...

  7. React:input输入框只能输入英文和特殊字符(可以自定义限制)

    React:input输入框只能输入英文和特殊字符(可以自定义限制) 直接上代码: antd3.x版本 render(){return (<Form.Item>{getFieldDecor ...

  8. react性能监控根据工具_高性能React:3个新工具可加快您的应用程序

    react性能监控根据工具 by Ben Edelstein 通过本·爱德斯坦 高性能React:3个新工具可加快您的应用程序 (High Performance React: 3 New Tools ...

  9. 开源精选:AntdFront —— React 纯 Hook 多标签微前端管理系统解决方案

    AntdFront 项目动机 使用 React 开发管理系统前端, 选择 Ant Design of React(antd)做 UI 十分常见,然而与其相关的开源项目普遍存在以下问题: 大多使用 an ...

  10. react引入多个图片_重新引入React:v16之后的每个React更新都已揭开神秘面纱。

    react引入多个图片 In this article (and accompanying book), unlike any you may have come across before, I w ...

最新文章

  1. 多次Jquery引发head.insertBefore( script, head.firstChild );
  2. java 抽象工厂工厂_java之抽象工厂
  3. 编程理论:多态,继承,和开闭原则
  4. SAP UI5的support Assistant
  5. 基于VHDL自动售邮票机设计
  6. 电脑4次连续故障音_格力空调电子膨胀阀故障判定与“E6”处理方法
  7. 基于java百货中心供应链管理系统(含源文件)
  8. linux pivot root,[mydocker]---通过例子理解chroot 和 pivot_root
  9. c++实验6—项目一
  10. 语音信号预处理1——chirp信号的生成与接收
  11. 常用的13个开源GIS软件,值得收藏!
  12. 数据结构与算法 哈希表的特点
  13. Android多媒体相关框架
  14. webrtc QOS方法一(NACK实现)
  15. Struts2详细执行流程自己总结
  16. 北京3月去哪玩 赏花踏青登山六大推荐
  17. MC官方模板的分析Day1
  18. oracle修改分区表的默认空间,Oracle数据库学习_Oracle分区表的分区占用空间为什么是8M?如何修改分区的初始空间?...
  19. 收藏本站——添加到浏览器收藏夹
  20. 天梵古法健康知识普及:足阳明胃经经穴

热门文章

  1. 56.Linux/Unix 系统编程手册(下) -- SOCKET 介绍
  2. 2.nginx 配置
  3. 17. Contoller(2)
  4. 百度地图API常规应用十功能
  5. Mysql存储过程中使用cursor
  6. [2019杭电多校第四场][hdu6621]K-th Closest Distance(主席树)
  7. 微星msi B450M+i5-8500+1060成功黑苹果
  8. Noip前的大抱佛脚----文章索引
  9. c++11 实现半同步半异步线程池
  10. jxl读数据库数据生成xls 并下载