zoukankan      html  css  js  c++  java
  • React Hooks简单业务场景实战(非源码解读)

     前言

    React Hooks 是React 16.7.0-alpha 版本推出的新特性。从 16.8.0 开始,React更稳定的支持了这一新特性。

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

    注意:React 16.8.0 是第一个支持 Hook 的版本。升级时,请注意更新所有的 package,包括 React DOM。React Native 将在下一个稳定版本中支持 Hook。

    如果说promise是JavaScript异步的终极解决方案,那么React Hooks从某种意义上来说,也是react状态管理的终极解决方案。

    为什么用 React Hooks?与其他状态管理方案有什么区别?

    在react hooks,react态管理方案主要有如下2种:

    这两种状态解决方案其实已经很不错,可以满足绝大多数状态共享的业务场景。 当然,像FB这样优秀的团队优秀的人总喜欢钻研,不断优化。认为这两种状态解决方案嵌套太多,很多业务逻辑可以抽象出来。不仅仅是共享状态就完事了,还得共享出处理逻辑。为了减少不必要的组件嵌套写法,实现更扁平、颗粒化的状态 + 逻辑的复用,于是便推出了 React Hooks。

    关于react hooks,具体可以多看看React Hooks官方文档,理解会更深。

    业务实战1:实现一个简单的显示隐藏弹出框

    1、基于 render-props实现:

    // 将父组建的 on状态 和toggle 事件,共享给嵌套下的子组件
    function App() {
     return (
       <Toggle initial={false}>
         {({ on, toggle }) => (
           <Button type="primary" onClick={toggle}> Open Modal </Button>
           <Modal visible={on} onOk={toggle} onCancel={toggle} />
         )}
       </Toggle>
     )
    }
    

    2、用react hooks实现

    import React, { useState } from 'react';
    
    function Example() {
      // 声明一个新的叫做 “visible” 的 state 变量
      const [visible, setVisible] = useState(false);
    
      return (
        <div>
          <Modal onClick={() => setVisible(!visible)}>
            Click me
          </Modal>
        </div>
      );
    }
    

    业务实战2: 接收传入props后立马更新自有的State状态(received passed props and updated)

    function Avatar(props) {
     const [user, setUser] = React.useState({...props.user}); // 这里仅仅是给了一个初始值,仅第一次渲染的时候生效,后续都不会再更新了。
    
     // 用useEffect,第二个参数传入一个数组字段props.user,
     // 表示每次只要传入的props.user有变化,那么就触发setUser这个操作更新状态。
     React.useEffect(() => {
         setUser(props.user);
     }, [props.user])
    
     return user.avatar ? 
            (<img src={user.avatar}/>)
           : (<p>Loading...</p>);
    }
    

    由上述例子可以看到,我们用到了useEffect这个hooks。

    Effect Hook 可以让你在函数组件中执行副作用操作

    什么叫副作用呢? 数据获取,设置订阅以及手动更改 React 组件中的 DOM 都属于副作用。

    如果实在理解不了副作用,你可以理解为,在我们在写传统的react class组件里面的生命周期钩子函数componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合中处理的相关逻辑,就是副作用。

    也就是说,任何你想在页面首次加载完(componentDidMount),后续每次更新完(componentDidUpdate),亦或者是组件卸载前(componentWillUnmount),这三个勾子中加入你自己的逻辑处理,就得用到useEffect

    业务实战3:显示后,倒计时自动隐藏(与setInterval结合)

    业务场景具体如下:实现一个倒计时30秒,每秒钟减1,然后倒计时完毕这个组件自动隐藏。

    function App() {
      const [count, setCount] = useState(30);
      useEffect(() => {
        setInterval(() => {
          setCount(count - 1);
        }, 1000);
      });
      return <div className="App">{count}</div>;
    }
    

    看看上述的写法,自己运行一下就只知道了,肯定是大错特错的。 最基本的,setInterval这个删除定时器都没有做相关处理。 其次,每次都会生成不同都setInterval实例。那么如何加以控制呢?

    来看看正确都写法,这里要用到useRef这种类型都hooks了。

    
    function App(props){
        const [visible,setVisible] = useState(false);// 初始化值为false,隐藏
        const [count,setCount] = useState(0); // 倒计时字段,初始值为0
        // 明确定时器要做什么:我们这里是每秒 -1,小于等于0的时候就自动给隐藏
        // 同时,本此的跟新跟下次的渲染更新要共享状态,记住上次更新这个count减到哪里了
        // 基于上述问题,我们可以使用如下方案:
        // 声明一个useRef对象,初始化为null
        const intervalCb = useRef(null); 
        useEffect(()=>{
          // useRef 对象有一个current属性,可以给它赋值为一个函数
          intervalCb.current = () => { 
          if(count  <= 0){
            setVisible(false);
          }else{
            setCount(count - 1);
          }    
        };   
        })
        
        // 在componentDidMount中设置一个定时器
        useEffect(()=>{
            function itvFn(){
                // 在此前,定时器的回调函数已经声明,这里可以直接调用
                intervalCb.current(); 
            }
            const itvId = window.setInterval(itvFn,1000);
            // return 一个回调函数,表示清除处理
            return () => window.clearInterval(itvId);
        },[]) // 传入要监听的对象,空数组表示只监听一次,相当于didMounted
    }
    
    return (<div className={visible}>
            {count}
        </div>)
    }
    

    关于useRef 更多的请看useRef官方文档

    业务实战4: 自定义hooks

    基于上述setInterval的业务功能实现,我们简单的来写一个自定义的hooks

    export default function useInterval(callback) {
     const savedCallback = useRef();
    
     useEffect(() => {
       savedCallback.current = callback;
     });
    
     useEffect(() => {
       function tick() {
         savedCallback.current();
       }
    
       let id = setInterval(tick, 1000);
       return () => clearInterval(id);
     }, []);
    }
    

    然后在你需要用到的地方引入:

    import useInterval from 'xx/self_hooks';
    
    function App(){
       useInterval(()=>{
           // ... 跟useEffect写法类似,目前只支持传入一个function类型的参数,如果要接收多个参数,那么在自定义hooks那里去自行处理一下。
       })
    }
    

    关于自定义hooks,更多请查看自定义hooks

    暂结

    关于react hooks 简单的使用,此篇就暂时写到这里,当然,复杂一点的,可以使用useReducer、useContext和useEffect代替Redux方案。后续我们应该单独来研究这块。 回顾一下,如何才能说我们会用react hooks 呢?

    • 第一、明白概念,干什么用的,解决哪些痛点?
    • 第二、useEffect传入几个参数?分表表示声明?useRef作用是什么?这些可以解决我们基本的业务需求。
    • 第三、useReducer、useContext 怎么替换 redux?
    • 读源码,搞清楚为什么useEffect不能卸载if嵌套中等之类的问题?

    今天先把问题抛出,后续按照这个,循序渐进的学习掌握react hooks。

  • 相关阅读:
    typedef
    心目中的编程高手
    截取包含多字节字符的字符串
    Start deltacat Audio Mix Filter
    关于编译环境和DLL的惨痛教训
    【转】自定义Extjs中Grid单元格的显示格式
    Ajax 按需 提交指定字段 以 Json Model 形式 post 到 action
    [转]Log4Net 非常完整的配置。
    【转】Ext.data.Store
    this.getColumnModel is not a function Extjs 如何解决呢? Extjs 导出 到Excel 解决方案问题
  • 原文地址:https://www.cnblogs.com/ldld/p/11069906.html
Copyright © 2011-2022 走看看