React Hooks

一. why hooks:

React conference 2018上, React團隊指出了React社區中被廣泛關注的問題:
(1) 邏輯複用問題: react中,組件是構建應用的基本組成部分, 爲了組件更好地複用,目前存在兩種方案: 高階組件(HOC)Render props,這些方案都有不同的適用場景,但是也帶來了明顯的缺點,如組件地獄

(2)巨型組件(Giant components):組件中各種的生命週期函數,但是組件的邏輯是相似的,如componentDidMount和ComponentDidUpdate的時候都可能存在發送ajax請求 或者是相反的, 如componentDidMount和componentWillUnMount會添加/清除綁定的事件, 計時器等
在這裏插入圖片描述
(3)class component還是functional component

  • functional component簡單, 但是無法確保以後會不會添加其他的生命週期函數, 造成組件重寫,
  • class component要寫的代碼多,不夠簡練, 還要面臨 this這類煩人的問題; 難以進編譯器行優化, 不利於熱加載

1. [state, useState]

class Greeting extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'Allen'
    }
    this.handleNameChange = this.handleNameChange.bind(this);
  }
  handleNameChange(e) {
    this.setState({
      name: e.target.value
    })
  }
  
  render() {
    return (
      <Row>
       <input 
          value={this.state.name}
          onChange={this.handleNameChange}
        />
     </Row>
    )
  }
}

ReactDOM.render(
  <Greeting />, 
  document.querySelector('#root')
)

將class component換成 functional component是這樣的, 是不是簡潔了好多!

function Greeting(props) {
  const [name, setName] = React.useState('Marry')
  
  function handleNameChange(e) {
    setName(e.target.value);
  }
  
  return (
      <Row>
       <input 
          value={name}
          onChange={handleNameChange}
        />
     </Row>
    )
}

注意這裏的

 const [name, setName] = React.useState('Marry'); // resource爲值, setResource爲設置值的函數, []裏面的命名可以任意

2. useContext

const locale = React.createContext('English');

<LocaleContext.Consumer>
          {LocaleContext => (
            <Row label="Language">
              {LocaleContext}
            </Row>
          )}
          </ LocaleContext.Consumer>

使用useContext進行替換

let LocalContext = React.createContext('English')

const locale = React.useContext(LocaleContext);
<Row label="language">
        {locale}
</Row>

3.useEffect
假設現在需要體添加一個myName的div來實時顯示當前的名稱, 我們可以使用componentDidMount和componentDidUpdate的方法

this.state = {
      name: 'Allen',
      myName: '',
    }
    
   componentDidMount() {
    this.state.myName = this.state.name;
  }
  componentDidUpdate() {
    this.state.myName = this.state.name;
  }
  
<Row label="The name is :">
          <div className="name">{this.state.myName}</div>
        </Row>

使用useEffect方法

const [myName, setMyName] = React.useState('');
  
  React.useEffect(() => {
    setMyName(name);
  })

看完上面的api你可能會認爲, hooks就是爲了讓functional component具有state和lifecycle method, 實際上並不完全是,hooks的更大用處在於代碼的複用

二. hooks是如何進行代碼複用的

假設我們有這樣一個useEffect的邏輯, 接受一個resource參數, 返回一個resource array, 我們提取出一個useResource函數

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

const useResources = resource => {
  const [resources, setResources] = useState([]);
  useEffect(
    () => {
      (async resource => {
        const response = await axios.get(
          `https://jsonplaceholder.typicode.com/${resource}`
        );
        setResources(response.data);
      })(resource);
    },
    [resource]
  );
  return resources;
};

export default useResources;

引用

import React from 'react';
import useResources from './useResources';

const UserList = () => {
  const users = useResources('users');

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
};

export default UserList;

另外一個代碼複用的例子:

class App extends React.Component {
  state = { lat: null, errorMessage: '' };

  componentDidMount() {
    window.navigator.geolocation.getCurrentPosition(
      position => this.setState({ lat: position.coords.latitude }),
      err => this.setState({ errorMessage: err.message })
    );
  }

  renderContent() {
    if (this.state.errorMessage && !this.state.lat) {
      return <div>Error: {this.state.errorMessage}</div>;
    }

    if (!this.state.errorMessage && this.state.lat) {
      return <SeasonDisplay lat={this.state.lat} />;
    }

    return <Spinner message="Please accept location request" />;
  }

  render() {
    return <div className="border red">{this.renderContent()}</div>;
  }
}

獲取地理位置的函數可以單獨抽取出來useLocation.js

import { useState, useEffect } from 'react';

export default () => {
  const [lat, setLat] = useState(null);
  const [errorMessage, setErrorMessage] = useState('');

  useEffect(() => {
    window.navigator.geolocation.getCurrentPosition(
      position => setLat(position.coords.latitude),
      err => setErrorMessage(err.message)
    );
  }, []);

  return [lat, errorMessage]; //注意這裏的返回值
};

在App.js中

import useLocation from './useLocation';

const App = () => {
    const  [lat, errorMessage] = useLocation() // 一行代碼
    
    const renderContent = () => {
      if (errorMessage && !lat) {
        return <div>Error: {errorMessage}</div>;
      };
      if (!errorMessage && lat) {
        return <SeasonDisplay lat={lat} />;
      };
      return <Spinner message="Please accept location request" />;
    }
    return <div className="border red">{renderContent()}</div>;
}
``
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章