React - Hooks

5 篇文章 0 订阅
2 篇文章 0 订阅

1.useState 定义state,修改state
2.useEffect 用于实现挂载结束,更新结束,销毁阶段
3.useContext 用与实现跨组件通信
4.useRef 用于绑定组件和元素
5.useCallback 用于函数组件优化
6.useMemo 用于函数组件优化
7.useImPerativeHandle 搭配useRef来使用,用于获取子组件中定义的方法
8.useLayoutEffect 和useEffect一致,但是它在最外层组件使用
9.useReducer 状态管理,组件复用

useState

useState保存组件状态


import React, { useState } from 'react';

const ComponentUseState = () => {
  const [num, setNum] = useState(0);
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };
  const decrement = () => {
    setCount((count) => {
      //依赖上一次的值做改变
      return count - 1;
    });
  };
  return (
    <div>
      <h2>Using useState</h2>
      Number: {num}
      <button onClick={() => setNum(num + 1)}>+</button>
      {/* set是一个函数可以直接嗲用 */}
      <button onClick={() => setNum(num - 1)}>-</button>
      <br />
      Count:{count}
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
};

export default ComponentUseState;

useEffect

useEffect可以实现组件的副作用

useEffect(希望执行的动作, [组件状态的列表]);

第二个参数用来处理useEffect调用的时机,是一个数组,数组内是组件状态的列表。

例如,想要实现每次点击计数器的同时更新网站的标题,那么useEffect的处理时机就应该是count state变化后,所以在第二个参数的列表中填入count。

useEffect(() => {
  document.title = `点击了${count}`;
}, [count]);

下文以该组件为例:

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

const App = () => {
  const [count, setCount] = useState(0);
  const [list, setList] = useState([]);

  useEffect(() => {
    document.title = `点击了${count}`;
  }, [count]);
  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => response.json())
      .then((data) => setList(data));
  }, []);

  return (
    <div>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click
      </button>
      <span>count: {count}</span>
      <div>
        {list.map((item, index) => (
          <span key={index}>{item.name}</span>
        ))}
      </div>
    </div>
  );
};

export default App;

一、useEffect模拟componentDidMount

当useEffect的第二个参数传入空列表时,相当于模拟生命周期函数componentDidMount。这个副作用仅在组件第一次挂载ui的时候调用一次。

用它来模拟组件初次挂载时,访问api、获得数据:

useEffect(() => {
 fetch("https://jsonplaceholder.typicode.com/users")
   .then((response) => response.json())
   .then((data) => setList(data));
}, []);

二、useEffect模拟componentDidUpdate

如果在使用useEffect时不带上第二个参数,就相当于模拟了生命周期函数componentDidUpdate。每次渲染结束的时候都会被调用。

如果上面的例子去掉第二参数,像下面这样:

useEffect(() => {
 fetch("https://jsonplaceholder.typicode.com/users")
   .then((response) => response.json())
   .then((data) => setList(data));
});
1.在每次渲染后被执行,调用API更新list;
2.由于list的更新,ui会再次渲染;
3.程序就陷入了死循环。

因此,要谨慎使用第二个参数为空的情形。

三、useEffect模拟componentWillUnmount

在useEffect中返回一个函数用于模拟component WillUnMount

useEffect(() => {
  let timerId = window.setInterval(() => {
    console.log(Date.now())
  }, 1000)

  // 返回一个函数用于模拟 WillUnMount
  return () => {
    window.clearInterval(timerId)
  }
}, [])

useContext

useContext主要用于函数组件之间传值的问题

App

import React, { createContext } from 'react';

import Navbar from './Navbar';
import Messages from './Messages';

export const TestContext = createContext({});

export default function App() {
  return (
    <TestContext.Provider
      value={{
        username: 'superawesome',
      }}
    >
      <div className="test">
        <Navbar />
        <Messages />
      </div>
    </TestContext.Provider>
  );
}

Navbar

import React, { useContext } from 'react';
import { TestContext } from './index';

const Navbar = () => {
  const { username } = useContext(TestContext);

  return (
    <div className="navbar">
      <p>{username}</p>
    </div>
  );
};
export default Navbar;

Messages

import React, { useContext } from 'react';
import {TestContext}  from './index'

const Messages = () => {
  const { username } = useContext(TestContext);

  return (
    <div className="messages">
      <p>1 message for {username}</p>
    </div>
  );
};
export default Messages;

useRef

useRef创建一块引用

一、取dom元素

二、非受控组件

import React, { useRef } from 'react';

const App = () => {
  const ipt = useRef();
  const handleClick = () => {
    console.log(ipt);
  };
  return (
    <>
      <h3>useRef</h3>
      <input ref={ipt} />
      <button onClick={handleClick}>获取dom</button>
    </>
  );
};


// function App() {
//   //场景实现:获取用户进入页面修改后的count
//   const [count, setCount] = useState(0);
//   const num = useRef();
//   num.current = count;
//   useEffect(() => {
//     setTimeout(() => {
//       console.log(num);
//     }, 3000);
//   }, []);

//   const handleClick = (number) => {
//     setCount((count) => count + number);
//   };

//   return (
//     <div>
//       <p>You clicked {count} times</p>
//       <button onClick={() => handleClick(1)}>增加 count</button>
//       <button onClick={() => handleClick(-1)}>减少 count</button>
//     </div>
//   );
// }
export default App;

三、获取组件实例

import React, {
  useRef,
  useEffect,
  useImperativeHandle,
  forwardRef,
} from 'react';

// 函数组件可以接收第二个参数,是ref
function ChildInputComponent(props, ref) {
  const inputRef = useRef(null);
  const a = 123;
  useImperativeHandle(ref, () => ({ input: inputRef.current, a }));
  return (
    <>
      <div>{a}</div>
      <input type="text" name="child input" ref={inputRef} />
    </>
  );
}
//类组件中如果需要使用ref获取组件实例,需要用React.forwardRef将组件包上;
const ChildInput = forwardRef(ChildInputComponent);

function App() {
  const inputRef = useRef(null);
  useEffect(() => {
    console.log(inputRef);
  }, []);
  return (
    <div>
      <ChildInput ref={inputRef} />
    </div>
  );
}
export default App;

useCallback

// import React, { Component, PureComponent } from 'react';

// //因为父组件render,子组件也render,所以使用PureComponent防止子组件重新渲染
// class Child extends PureComponent {
//   render() {
//     console.log('child render');
//     return <div>child</div>;
//   }
// }

// class App extends Component {
//   state = {
//     count: 5,
//   };

//   obj = { fontSize: 20 };

//   handleClick = () => {
//     this.setState({ count: 5 });
//   };

//   render() {
//     return (
//       <>
//         <h3>useCallback</h3>
//         <Child />
//         <p>{this.state.count}</p>
//         <button onClick={this.handleClick}>+</button>
//       </>
//     );
//   }
// }

// export default App;


import React, { useState, memo, useCallback } from 'react';

// memo是一个高阶组件,作用和PureComponent完全相同,用于函数组件
const Child = memo(({ fn }) => {
  console.log('child render');
  return (
    <div>
      child
      {fn()}
    </div>
  );
});

const App = () => {
  const [count, set_count] = useState(5);
  const handleClick = () => {
    set_count((count) => count + 1);
  };
  // useCallback是缓存函数, 需要和memo高阶组件一起用
  // 作用就是将里面第一个参数的那个函数缓存起来
  // 避免子组件的重新渲染
  // 当这个函数要作为自定义事件往子组件里传的时候就要用

  // 第二个参数是依赖数组
  const fn = useCallback(() => {
    console.log(count);
  }, []);
  return (
    <>
      <h3>useCallback</h3>
      <Child fn={fn} />
      <p>{count}</p>
      <button onClick={handleClick}>+</button>
    </>
  );
};

export default App;

useMemo

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

const App = () => {
  const [count, set_count] = useState(1);
  const [num, set_num] = useState(10);

  const fn = () => {
    set_count((count) => count + 1);
  };
  const fn2 = () => {
    set_num((num) => num + 1);
  };

  // useMemo也是用于函数缓存, 语法和useCallback一模一样

  // useCallback缓存的是整个函数,useMemo缓存的是函数的返回值
  // useMemo跟vue的计算属性是一样的
  const sum = useMemo(() => {
    console.log(123);
    let s = 0;
    for (let i = 0; i < count * 100; i++) {
      s += i;
    }
    return s;
  }, [count]);

  return (
    <>
      <h3>useMemo</h3>
      <p>{count}</p>
      <button onClick={fn}>btn</button>
      <p>{sum}</p>
      <p>{num}</p>
      <button onClick={fn2}>btn</button>
    </>
  );
};

export default App;

useReducer

useReducer主要处理状态更新的逻辑,并且脱离UI,可以复用

import React, { useReducer } from 'react';

//定义初始值
const initState = { count: 0 };
//state的处理函数
const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + action.payload };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
};
export default function App() {
  //第一个参数satte的处理函数,第二个参数state初始值
  //返回最新的state和dispatch函数
  let [state, dispatch] = useReducer(reducer, initState);
  return (
    <>
      <button onClick={() => dispatch({ type: 'increment', payload: 1 })}>
        +
      </button>
      <span>{state.count}</span>
      <button onClick={() => dispatch({ type: 'decrement', payload: 1 })}>
        -
      </button>
    </>
  );
}
  • 如果你的state是一个数组或者对象
  • 如果你的state变化很复杂,经常一个操作需要修改很多state
  • 如果你希望构建自动化测试用例来保证程序的稳定性
  • 如果你需要在深层子组件里面去修改一些状态
  • 如果你用应用程序比较大,希望UI和业务能够分开维护
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值