美文网首页
hook注意事项

hook注意事项

作者: skoll | 来源:发表于2020-07-17 15:19 被阅读0次

每次渲染,都会走到hook里面

1 .这个里面好像是因为count值会变化,外面引用到了,所以每次都会重新渲染useCounter这个函数
2 .但是这个里面的useEffect其实只会调用一次

const count=useCounter()
//别的地方调用了这个hook

function useCounter(){
    console.log('调用了count')
//这里是每次都打印出来的
    const [count,setCount]=useState(0)

    // useEffect(()=>{
    //     setInterval(() => {
    //         console.log('useCounter',count)
    //         setCount(count + 1);
    //     }, 1000);      
    // },[])
    // 问题1:这里的count取的是初始执行这个useEffect时候的值,也就是0,所以每次加计算的都是从0开始,所以这里的值应该会一直是0
    
    // useEffect(()=>{
    //     let id=setInterval(() => {
    //         console.log('useCounter',count)
    //         setCount(count + 1);
    //     }, 1000);
    // },[count])
    // 问题2:每次重新执行,setInterval都是会重新定义,所以需要一个全局变量来保存这个东西,比如用一个ref来保存,或者使用函数模式设置count

    useEffect(()=>{
        let id=setInterval(() => {
            console.log('useCounter',count)
            setCount(c=>c+1);
        }, 1000);
        // 不需要传入依赖,只执行一次,setInterval不会重置,setCount的函数设置方式,可以实现我们的效果
    },[])

    // 或者全局挂在一个ref上面

    return [count]

}

Hook的每次调用都有一个独立的state被创建,复用的是逻辑状态,而不是state值

count仅是一个数字而已。它不是神奇的“data binding”, “watcher”, “proxy”

1 .react换了一种模型

const count = 42;
// ...
<p>You clicked {count} times</p>

2 .这个好像和我的想法一样
3 .第一次渲染的时候,拿到的count是1,第二次调用setCount,这个值变化,react再次渲染,这次count是1
4 .每一次更新状态,react会重新渲染组件,每一次渲染都会拿到独立的count,这个状态值是函数中的一个常量
5 .当我们调用setCount的时候,react会带着一个不同的count值在次调用这个组件,然后react会更新dom,保证输出和渲染一致

每一次渲染都有自己的事件处理函数,包括传入的参数

1 .我们的组件函数每次渲染都会被调用,每次调用的count都是常量,并且他被赋予了当前渲染中的状态值,所以才会有如果函数依赖外面的参数,就要把参数传入到第二个参数里面,当参数发生变化就让这个函数重新创建一遍
2 .每一次渲染都有一个“新版本”的handleClick,每一个版本的handleClick都记住了自己的event
3 .vue更像是把所有数据都存在一个地方,每次用到参数的时候都去那里找当前最新的,这个函数一旦定义好就不变了
4 .再任意一次的渲染中,props和state始终是不变的,props和state再不同的渲染中是相互独立的,所以使用到他们的任意值也都是相互独立的,他们都属于一次特定的渲染。即使事件处理中的异步函数调用“看到”的也是这次渲染中的值。也有可能不是最新的值

effect:每次渲染都有他自己的effects

1 .并不是count值在“不变”的effect中发生了改变,而是effect函数本身在每一次渲染中都不同,如果effect依赖于外部的count值,那么每一个版本的effect应该都是根据最新的count来创建的
2 .虽然effect是一个,但是每次渲染都是一个不同的函数,并且每个effect函数得到的props,或者state都来自属于他的那次特定渲染
3 .effect渲染的时间

function Counter() {
  // ...
  useEffect(
    // Effect function from first render
    () => {
      document.title = `You clicked ${0} times`;
    }
  );
  // ...
}
React: 给我状态为 0时候的UI。
你的组件:

给你需要渲染的内容: <p>You clicked 0 times</p>。
记得在渲染完了之后调用这个effect: () => { document.title = 'You clicked 0 times' }。
React: 没问题。开始更新UI,喂浏览器,我要给DOM添加一些东西。
浏览器: 酷,我已经把它绘制到屏幕上了。
React: 好的, 我现在开始运行给我的effect

运行 () => { document.title = 'You clicked 0 times' }。

第一次渲染

// After a click, our function is called again
function Counter() {
  // ...
  useEffect(
    // Effect function from second render
    () => {
      document.title = `You clicked ${1} times`;
    }
  );
  // ...
}
你的组件: 喂 React, 把我的状态设置为1。
React: 给我状态为 1时候的UI。
你的组件:

给你需要渲染的内容: <p>You clicked 1 times</p>。
记得在渲染完了之后调用这个effect: () => { document.title = 'You clicked 1 times' }。
React: 没问题。开始更新UI,喂浏览器,我修改了DOM。
Browser: 酷,我已经将更改绘制到屏幕上了。
React: 好的, 我现在开始运行属于这次渲染的effect

运行 () => { document.title = 'You clicked 1 times' }。


// After another click, our function is called again
function Counter() {
  // ...
  useEffect(
    // Effect function from third render
    () => {
      document.title = `You clicked ${2} times`;
    }
  );
  // ..
}

1 .所有effects都会在渲染之后依次执行,概念上他只是组件输出的一部分,并且可以看到某次特定渲染的props和state
2 .于此相反的是之前的this.state.count,这种模式,只是会获取到最新的数据

effect清理上次的函数

1 .错误的认识:假设第一次渲染的时候props是{id: 10},第二次渲染的时候是{id: 20}

React 清除了 {id: 10}的effect。
React 渲染{id: 20}的UI。
React 运行{id: 20}的effect。
1 .正确的认识
React 渲染{id: 20}的UI。
浏览器绘制。我们在屏幕上看到{id: 20}的UI。
React 清除{id: 10}的effect。
React 运行{id: 20}的effect。
2 .effect的清除并不会读取最新的props,他只能读取到定义他的那次渲染的props值

1 .react会根据我们当前的props,state同步到DOM
2 .useEffect使你能够根据props和state同步react tree之外的东西
3 .react并不能区分effects的不同,所以为了避免不重复的调用,可以给useEffect一个依赖数组参数

useEffect(() => {
    document.title = 'Hello, ' + name;
  }, [name]); // Our deps
这好比你告诉React:“Hey,我知道你看不到这个函数里的东西,但我可以保证只使用了渲染中的name,别无其他。”

如果当前渲染中的这些依赖项和上一次运行这个effect的时候值一样,因为没有什么需要同步React会自动跳过这次effect:

4 .即使依赖数组中只有一个值在两次渲染中不同,也不会跳过effect的运行,会同步所有

移除依赖的常见方式

1 .让Effect自给自足,但是这种使用场景及其优先。放弃了外面修改state的权力

useEffect(() => {
    const id = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(id);
  }, [count]);

useEffect(() => {
    const id = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    return () => clearInterval(id);
  }, []);

2 .使用reducer,解耦行为和操作数据的两个过程。是当你dispatch的时候,React只是记住了action - 它会在下一次渲染中再次调用reducer。在那个时候,新的props就可以被访问到,而且reducer调用也不是在effect里。

这就是为什么我倾向认为useReducer是Hooks的“作弊模式”。它可以把更新逻辑和描述发生了什么分开。结果是,这可以帮助我移除不必需的依赖,避免不必要的effect调用。
3 .把函数移到effects里面

function SearchResults() {
  const [query, setQuery] = useState('react');

  useEffect(() => {
    function getFetchUrl() {
      return 'https://hn.algolia.com/api/v1/search?query=' + query;
    }
//这个effect依赖的函数1

    async function fetchData() {
      const result = await axios(getFetchUrl());
      setData(result.data);
    }
//这个effect以来的函数2
    fetchData();
  }, [query]); // ✅ Deps are OK

  // ...
}

4 .实在不能放到effects里面的情况

1 .组件内有几个effect使用了相同的函数,不像在每个里面都复制粘贴一遍
function SearchResults() {
  function getFetchUrl(query) {
    return 'https://hn.algolia.com/api/v1/search?query=' + query;
  }

  useEffect(() => {
    const url = getFetchUrl('react');
    // ... Fetch data and do something ...
  }, []); // 🔴 Missing dep: getFetchUrl

//没使用依赖,那么这个请求之后发生依次,之后请求路径或者参数变化的时候也不会再次请求,其实这里也不能这么说,因为其实参数已经确定了,query在这里是固定的,除非有第三个地方来修改query
  useEffect(() => {
    const url = getFetchUrl('redux');
    // ... Fetch data and do something ...
  }, []); // 🔴 Missing dep: getFetchUrl

  // ...
}

2 .如果把函数加到依赖里面呢
function SearchResults() {
  // 🔴 Re-triggers all effects on every render
  function getFetchUrl(query) {
    return 'https://hn.algolia.com/api/v1/search?query=' + query;
  }

  useEffect(() => {
    const url = getFetchUrl('react');
    // ... Fetch data and do something ...
  }, [getFetchUrl]); // 🚧 Deps are correct but they change too often

  useEffect(() => {
    const url = getFetchUrl('redux');
    // ... Fetch data and do something ...
  }, [getFetchUrl]); // 🚧 Deps are correct but they change too often

  // ...
}
//每次渲染其实函数都是新的,所以这个依赖完全是废的,其实还是每次刷新都触发effect执行,也就是请求数据


//解决方法1 :如果一个函数没有使用组件内的任何值,就把他提到组件外面定义,然后就可以自由的在effect里面使用
function getFetchUrl(query) {
  return 'https://hn.algolia.com/api/v1/search?query=' + query;
}

function SearchResults() {
  useEffect(() => {
    const url = getFetchUrl('react');
    // ... Fetch data and do something ...
  }, []); // ✅ Deps are OK

  useEffect(() => {
    const url = getFetchUrl('redux');
    // ... Fetch data and do something ...
  }, []); // ✅ Deps are OK

  // 此时不需要再设为依赖,因为他不在渲染范围内,不会被数据流影响,不会因为props,state而改变
}

//解决方法2:包装为useCallck hook
function SearchResults() {
  // ✅ Preserves identity when its own deps are the same
  const getFetchUrl = useCallback((query) => {
    return 'https://hn.algolia.com/api/v1/search?query=' + query;
  }, []);  // ✅ Callback deps are OK

  useEffect(() => {
    const url = getFetchUrl('react');
    // ... Fetch data and do something ...
  }, [getFetchUrl]); // ✅ Effect deps are OK

  useEffect(() => {
    const url = getFetchUrl('redux');
    // ... Fetch data and do something ...
  }, [getFetchUrl]); // ✅ Effect deps are OK

  // 本质上是给函数添加了一层依赖检查,只有函数依赖的参数发生变化,函数才会变化,而不是仅仅简单的去掉函数的依赖,那么effect依赖数组的检查是不是也可也以这么来??
}

相关文章

  • hook注意事项

    每次渲染,都会走到hook里面 1 .这个里面好像是因为count值会变化,外面引用到了,所以每次都会重新渲染us...

  • React Hook 注意事项

    useState old: new 其他例子 对象的useState设为[]会有问题 要设为null,在map的时...

  • 堆利用的手法:

    malloc_hook realloc_hook+free_hook free_hook unsorted_bin...

  • Thinkphp实战利用钩子使用行为扩展 (Hook)

    上午研究了几篇关于使用Hook实现钩子的实例或详细描述,总结了一些,所以打算写两个实例深入记忆。 注意事项: 注意...

  • hook原理小结

    常用的hook方式主要有导入表hook、导出表hook和inline hook三种。 一,导入表hook 首先需要...

  • 常用油猴Hook插件

    hook cookie hook 过debugger

  • react hook 状态与操作封装

    统一hook 数组hook

  • 遍历hook Dex中的类

    创建DexFile 遍历拿出所有类名 找到类对象,进行hook hook构造函数 hook方法 打印hook方法中的日志

  • frida native hook

    本篇介绍 frida 也支持hook native,本篇看下如何hook native hook native函数...

  • HOOK

    HOOK 一、HOOK概述 HOOK(钩子) 其实就是改变程序执行流程的一种技术的统称! 二、iOS中HOOK技术...

网友评论

      本文标题:hook注意事项

      本文链接:https://www.haomeiwen.com/subject/horscktx.html