React Hooks 学习笔记

- useEffect 

接受两个参数:

  • 第一个参数是函数(这里叫effect函数),它的作用是,在页面渲染后执行这个函数。因此你可以把ajax请求等放在这里执行;
  • 第二个参数是一个数组,这里注意:
参数情况          效果               注意
不传 每次渲染后都执行清理或者执行effect 这可能会导致性能问题,比如两次渲染的数据完全一样
传空数组 只运行一次的 effect(仅在组件挂载和卸载时执行) 这就告诉 React 你的 effect 不依赖于 props 或 state 中的任何值,所以它永远都不需要重复执行
传[count] React 将对前一次渲染的count和后一次渲染的count进行比较。若相等React 会跳过这个 effect 实现了性能的优化

 

 

 

 

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState({});

  useEffect(() => {
   setCount({test:"count是一个对象,使得页面死循环"})
  },[count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

 

上面例子中之所以造成页面的死循环,是因为在JavaScript中,{} === {}结果是false,{a:1} === {a:1}同样,由此造成了react以为两个值不同,就一直的渲染最终页面死循环。

- lodash.debounce

useEffect中的debounce和setInterval中的debounce有点不同: useEffect中的debounce 因为状态发生的改变,所以之前的debounce就不是之前的debounce了,

而是最新的debounce,所以一定会执行 但setInterval中的debounce 还是同一个debounce,所以不会执行

- useMemo和useCallback

众所周知,react中,性能的优化点在于:

  1. 调用setState,就会触发组件的重新渲染,无论前后的state是否不同
  2. 父组件更新,子组件也会自动的更新, (无论是state变化还是修改 redux中的数据)

基于上面的两点,我们通常的解决方案是:使用immutable进行比较,在不相等的时候调用setState;在shouldComponentUpdate中判断前后的props和state,如果没有变化,则返回false来阻止更新。

在hooks出来之后,我们能够使用function的形式来创建包含内部state的组件。但是,使用function的形式,失去了上面的shouldComponentUpdate,我们无法通过判断前后状态来决定是否更新。而且,在函数组件中,react不再区分mount和update两个状态,这意味着函数组件的每一次调用都会执行其内部的所有逻辑,那么会带来较大的性能损耗。因此useMemo 和useCallback就是解决性能问题的杀手锏。

 

useMemo和useCallback都会在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行;并且这两个hooks都返回缓存的值,useMemo返回缓存的变量,useCallback返回缓存的函数。

 

useEffect地第二个参数中,只需将参数使其包裹起来后,就可以利用引用地址来减少重复渲染了

 

import React, {useState, useMemo, memo, useCallback } from 'react';
import ReactDOM from 'react-dom';
import './App.css';

let Child = ({data, handleClick}) => {
  // 父组件更新, 子组件即使没变化也更新
  console.log('%c让我康康 Child Render', 'border-radius:3px;background:#000;color:#f6e387;padding: 2px 5px');
  return (
    <button onClick={handleClick}>
      {data.number}
    </button>
  )
}

Child = memo(Child);
// let memoData = {num:10};
// let onClick = () => {
// }
debugger
function App() {
  console.log('%c让我康康 App Render', 'border-radius:3px;background:#000;color:#f6e387;padding: 2px 5px', );
  const [name, setName] = React.useState('Jack');
  const [number, setNumber] = React.useState(0);
  let memoData = useMemo(() => ({number}),[number]);
  let onClick = useCallback(() => setNumber(number + 1),[number] );

  return (
    <div className="App">
      <h1>{name}</h1>
      <input type="text" onChange={(e)=>{setName(e.target.value)} } />
      <Child  data={memoData}  handleClick={onClick} />
    </div>
  )
}


function render() {
  ReactDOM.render(
    <App />,
    document.getElementById('root')
  )
}
render();

 

 

 

1.userContext的使用

使用场景, 组件之间需要共享状态

父组件

import React, { useState } from 'react';
import Child from './child.js'
import Child2 from './child2.js'
import CountContext from './common'

function Example(){
    const [count , setCount ] = useState(666)
    return(
        <div>
            <div>
                <p>you click {count -666 } times</p>
                <button onClick={()=>{setCount(count+1)}}>click me</button>
                <CountContext.Provider value ={count}>
                    <Child/>
                    <Child2/>
                </CountContext.Provider>
            </div>
        </div>
    )
}

export default Example

子组件1

import React, { useContext } from 'react';
import CountContext from './common'

function Child(){
    let count = useContext(CountContext)
    return(<h2>儿子1:{count}</h2>)
}

export default Child

子组件2

import React, { useContext } from 'react';
import CountContext from './common'

function Child(){
    let count = useContext(CountContext)
    return(<h2>儿子2:{count}</h2>)
}

export default Child

公共组件

import  {createContext } from 'react';
const CountContext = createContext(80);
export default CountContext

 

 

 

效果

 

 

二、父子传值

父组件

  <ConfirmModal
     attribution={attribution}
     location={props.location}
     func={confirmClose}
     onFinish={() => {
       confirmClose();
       setFinish(true);
     }}
     agent_id={
       props.location.query.agent_id
        ? props.location.query.agent_id
       : ''
      }
     values={values}
     number={number}
     products={screen.products}
 />

子组件

export default ({location, values, products, number = { price: 0 }, func, onFinish, attribution, agent_id}) => {

//触发父组件函数

//写入默认值 相当于 this.setState
useState(() => {
//写入邮箱默认值
if (values.email === undefined || values.email === '') {
values.email = values.select_number + '@189.cn';
}
//写入宽带安装地址默认值
if (values.broadband_address && values.broadband_address.length > 0) {
values.broadband_address = attribution + values.broadband_address;
}
//写入承保地址默认值
if (
values.gift_address === undefined ||
(values.gift_address === '' &&
product.gifts.find((item) => item.id === values.gift_id)
.need_address)
) {
values.gift_address = values.detail_address;
}
});
 
onFinish && onFinish();  //可传值
}

 

3.卸载时清除定时器

 const time = React.useRef(null)
useEffect(() => {
        return() => {
       clearIntervel(time.current)
      } 
});

4.根据某个值的修改 触发其他函数

//只要value值变化了 , 就会触发getList()函数
useEffect(() => { getList() }, [value]);

使用useCallback和useMemo时, 要注意函数形式

如果是函数形式, 参数变成行参了, 就不需要在依赖项加上变量了

useCallback(() => setOpen(!open), [open]);
// 可以写成
useCallback(() => setOpen((open) => !open), []);

 

如果写成函数, 会被依赖项忽略掉

  const funcB = useCallback(() => {
    setOpen(!open);
  }, [open]);

  useEffect(() => {
    console.log('funcB :>> ', funcB);
  }, [funcB]);

// =>

    const funcA = () => setOpen(!open);
    const funcB = funcA;

    useEffect(() => {
      console.log('funcB :>> ', funcB);
    }, [funcB]);
 

 

 

 

5. 卸载React应用

import { unmountComponentAtNode } from 'react-dom';

const domNode = document.getElementById('root');
render(<App />, domNode);

unmountComponentAtNode(domNode);

// React 18
root.unmount().

遇到的BUG

1.使用create-react-app 创建应用的时候

指令create-react-app 不存在 ,使用npx create-react-app 即可

2.使用antd-design 组件Button时 报错

 

 

 经检查,发现是antd版本没跟上react更新导致

解决方法 降低react和react-dom 版本为16.12.0 ,  antd版本降为4.4.2

posted @ 2020-08-07 11:17  一路向北√  阅读(215)  评论(0编辑  收藏  举报

web应用开发&研究 -

业精于勤而荒于嬉。

工作,使我快乐。


Font Awesome | Respond.js | Bootstrap中文网