React中Hook学习
React中Hook学习
Hook 是 React 16.8 的新增特性。可以在编写函数式组件时使用state以及react中的其他特。
hook为了解决react中原有的问题
- 组件之间复用状态逻辑很难
- 复杂组件变得难以理解(例如组件中生命周期被拆分开来写,但是其中的代码相互关联,使得代码变得复杂)
- 类组件中,this工作方式复杂,并且在实际项目中存在难以优化的情况。
Hook使用规则
- 只能在函数最外层调用Hook。不要在循环、条件判断或者子函数中调用。
- 只能在React的函数组件中调用Hook。不要在其他JavaScript函数中调用。(还有一个地方可以调用Hook——就是自定义的Hook中)
使用linter插件来强制执行这些功能
linter插件下载地址:https://www.npmjs.com/package/eslint-plugin-react-hooks
Hook是什么
Hook是一个特殊的函数,它可以让你“钩入”React的特性。例如,useState是允许你在React函数式组件中添加state的Hook
State Hook
函数式组件使用useState来实现类组件中state状态
import React, { useState } from 'react';
export default function CountHook() {
  // 声明一个叫 “count” 的 state 变量,并且setCount为更改state变量的方法。
  // 并且只初始化一次,重新渲染时保留之前的值
  // useState()唯一的参数为初始化state的值(不一定要是对象,this.state中必须是对象形式)
  // 如果想要在state中存储两个不同的变量,只需要调用useState(0两次即可。)
  // 方括号表示js中的数组解构
  const [count, setCount] = useState(0);
  return (
    <div>
    	// 获取state中的count
      <p>You clicked {count} times</p>
			// 更新state中的count
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
类组件写法
import React, { Component } from 'react'
export default class Count extends Component {
    state = {
        count:0
    }
    render() {
        return (
            <div>
                <p>You clicked {this.state.count} times</p>
                 <button onClick={() => this.setState({ count: this.state.count + 1 })}>Click me</button>
            </div>
        )
    }
}
useEffect
在函数式组件中使用useEffect来控制副作用
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
  	// 组件跟新(第一次挂载)的时候调用
  	// 创建函数,并添加订阅
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
  
    // 组件卸载的时候调用,用于清除订阅(只有当副作用需要清除的时候才添加返回函数)
    return ()=>{
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  
  });
在类式组件中使用生命周期函数控制副作用
// 组件挂载的时候调用
componentDidMount() {
  ChatAPI.subscribeToFriendStatus(
    this.props.friend.id,
    this.handleStatusChange
  );
}
// 组件卸载的时候调用
componentWillUnmount() {
  ChatAPI.unsubscribeFromFriendStatus(
    this.props.friend.id,
    this.handleStatusChange
  );
}
// 租价更新的时候调用
handleStatusChange(status) {
  this.setState({
    isOnline: status.isOnline
  });
}
- 
传递给useEffect的函数在没词渲染中都会有所不同,正是因为这样可以在effect中获取最新的count的值,二不用担心其过期。 
- 
与 componentDidMount或componentDidUpdate 不同,使用 useEffect调度的 effect 不会阻塞浏览器更新屏幕,这让你的应用看起来响应更快。 
- 
useEffect在浏览器渲染完成后执行,useLayoutEffect在浏览器渲染前执行,因此在涉及更改布局的effect最好使用useLayoutEffect。 
- 
useEffect可以允许我们按照代码的用途分离他们, 而不是像生命周期函数那样。 
- 
useEffect中effect在每次新的effect之前,对前一个effect进行清理 
通过设定观测特定值的变化来决定是否调用effect来进行性能的优化
// 仅在 count 更改时更新
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]);
// 仅在 props.friend.id 发生变化时,重新订阅
useEffect(() => {
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
  return () => {
    ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
  };
}, [props.friend.id]); 
Hook规则
linter插件可以强制执行这些规则
- 只在最顶层使用Hook
不在循环,条件或者潜逃函数中使用Hook
- 只在React函数中调用Hook
只在React的函数组件中调用Hook,只在自定义Hook中调用其他Hook
ESLint插件使用
npm install eslint-plugin-react-hooks --save-dev
自定义Hook
提取多个组件之间重复的逻辑并复用
原:
import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
  
  //重复部分
  //--------------------------------
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
	//--------------------------------
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
import React, { useState, useEffect } from 'react';
function FriendListItem(props) {
  
  //重复部分
  //--------------------------------
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
	//--------------------------------
  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}
提取自定义Hook
使用use开头的函数
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;
}
用自定义Hook替换重复部分
function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);
  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}
在两个组件中使用相同的state并不会共享state和副作用
 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号