react hooks 学习

react hooks 学习

一. React Hooks是什么?
React Hooks 是 React 16.8 引入的新特性,允许我们在不使用 Class 的前提下使用 state 和其他特性,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。

二. React Hooks解决的问题是?
状态共享,避免嵌套。用于解决长时间使用和维护react过程中常遇到的问题。
1.难以重用和共享组件中的与状态相关的逻辑。
2.逻辑复杂的组件难以开发与维护,当我们的组件需要处理多个互不相关的 local state 时,每个生命周期函数中可能会包含着各种互不相关的逻辑在里面。
3.类组件中的this增加学习成本,类组件在基于现有工具的优化上存在些许问题。
4.由于业务变动,函数组件不得不改为类组件等等。

三. 常见的hooks
1.useState状态钩子
useState()用于为函数组件引入状态(state)。纯函数不能有状态,所以把状态放在钩子里面。
原本写法

export default class Button extends Component {
  constructor() {
    super();
    this.state = { buttonText: "Click me, please" };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(() => {
      return { buttonText: "Thanks, been clicked!" };
    });
  }
  render() {
    const { buttonText } = this.state;
    return <button onClick={this.handleClick}>{buttonText}</button>;
  }
}

hooks写法

export default function Button() {
  const [buttonText, setButtonText] = useState("Click me, please");

  function handleClick() {
    return setButtonText("Thanks, been clicked!");
  }

  return <button onClick={handleClick}>{buttonText}</button>;
}

使用:
首先引入useState,然后声明一个叫 “buttonText” 的 state 变量,读取 buttonText,最后setButtonText修改。

注意事项:

  1. 在函数组件中,没有 this,所以不能分配或读取 this.state。直接在组件中调用 useState Hook,调用 useState 方法的时候会定义一个 “state 变量”,它与 class 里面的 this.state 提供的功能完全相同。一般来说,在函数退出后变量就会”消失”,而 state 中的变量会被 React 保留。
  2. useState()函数返回一个数组,数组的第一个成员是一个变量(buttonText),指向状态的当前值。第二个成员是一个函数,用来更新状态,约定是set前缀加上状态的变量名(setButtonText)

2.useEffect():副作用钩子
useEffect()用来引入具有副作用的操作,最常见的就是向服务器请求数据。代替componentDidMount 和 componentDidUpdate。


const Person = ({ personId }) => {
  const [loading, setLoading] = useState(true);
  const [person, setPerson] = useState({});

  useEffect(() => {
    setLoading(true);
    fetch(`https://swapi.co/api/people/${personId}/`)
      .then(response => response.json())
      .then(data => {
        setPerson(data);
        setLoading(false);
      });
  }, [personId]);

  if (loading === true) {
    return <p>Loading ...</p>;
  }

  return (
    <div>
      <p>You're viewing: {person.name}</p>
      <p>Height: {person.height}</p>
      <p>Mass: {person.mass}</p>
    </div>
  );
};

function App() {
  const [show, setShow] = useState("1");

  return (
    <div className="App">
      <Person personId={show} />
      <div>
        Show:
        <button onClick={() => setShow("1")}>Luke</button>
        <button onClick={() => setShow("2")}>C-3PO</button>
      </div>
    </div>
  );
}

使用方式:
useEffect()接受两个参数。第一个参数是一个函数(剪头函数),异步操作的代码放在里面。第二个参数是一个数组,用于给出 Effect 的依赖项([personId]),只要这个数组发生变化,useEffect()就会执行。第二个参数可以省略,这时每次组件渲染时,就会执行useEffect()。


function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

解绑副作用:
effect 中返回一个函数是effect 可选的清除机制。每个 effect 都可以返回一个清除函数。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。React 会在组件卸载的时候执行清除操作。effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 effect 之前对上一个 effect 进行清除。

3.useContext():共享状态钩子
用于在组件之间共享状态

const AppContext = React.createContext({});

const Navbar = () => {
  const { username } = useContext(AppContext)

  return (
    <div className="navbar">
      <p>AwesomeSite</p>
      <p>{username}</p>
    </div>
  )
}

const Messages = () => {
  const { username } = useContext(AppContext)

  return (
    <div className="messages">
      <h1>Messages</h1>
      <p>1 message for {username}</p>
      <p className="message">useContext is awesome!</p>
    </div>
  )
}

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

使用方式:
首先引入useContext,然后使用 React Context API,在组件外部建立一个 Context(AppContext),AppContext.Provider提供了的 Context 对象能被子组件共享,useContext()钩子函数用来引入 Context 对象,从中获取username属性。

4.useReducer():action 钩子
useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。
在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优化,因为可以向子组件传递 dispatch 而不是回调函数 。

//const initialState = {count: 0};
function init(initialCount) {
  return {count: initialCount};
}

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    case 'reset':
      return init(action.payload);
    default:
      throw new Error();
  }
}

function Counter({initialCount}) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  return (
    <>
      Count: {state.count}
      <button
        onClick={() => dispatch({type: 'reset', payload: initialCount})}>
        Reset
      </button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

useReducer(reducer, initialArg, init)第一个是名字,第二个是初始值,第三个是惰性初始化(将 init 函数作为 useReducer 的第三个参数传入,这样初始 state 将被设置为 init(initialArg)。
这么做可以将用于计算 state 的逻辑提取到 reducer 外部,这也为将来对重置 state 的 action 做处理提供了便利),第三个参数可以不写,那就需要第二个参数有初始值。
使用方式:

useReducer声明初始值,dispatch调用reducer。

5.自定义的 Hook
自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook。

import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;

function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

使用方式:
useFriendStatu()是一个自定义的 Hook,直接引用传值就行。

注意事项:

  1. 自定义 Hook 必须以 “use” 开头。
  2. 在两个组件中使用相同的 Hook 不会共享 state 。
  3. 每次调用 Hook,它都会获取独立的 state。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值