一、函數式組件創建
function HelloComponent(props, /* context */) { return <div>Hello {props.name}</div> } ReactDOM.render(<HelloComponent name="Sebastian" />,document.getElementById("mountNode"))
這里我們可以知道該組件中並沒有自己的狀態,但實際開發中往往需要內部的狀態實現一系列的交互和展示功能.所以我們用class創建組件更多一點.但是,純函數的組件式創建更符合react的思想,於是為了解決狀態問題,完善的函數式組件創建模式出現:react-hook
首先需要明確的一點是,hook中沒有this指針,所以相關的api都需要改變才.
二、常用HOOK API
結合class式組件進行對比
1.組件申明
class:
export default class Text extends React.Component {}
Hook
const Text = {} export default Text
2.state
(1)初始化
class
constructor(props) { super(props); this.state = { name: '小明',
age:1 }; }
Hook
const [name, setName] = useState(0);
const [age, setAge] = useState(1);
//name:變量名 初始值是useState()里面額值,相當於name=0,同時又申明了一個函數setName並使其具有監聽name變化然后更新視圖的功能
//setName:傳一個新的name值,並更新至視圖層.可以是一個具有返回值的函數
(2)獲取state值
class
this.state.name
this.state.age
Hook
const [name, setName] = useState('小明'); const [age, setAge] = useState(1); useState('小明')//獲取name,自動忽略參數 useState(1)//獲取age,自動忽略參數
(3)修改state值
class
this.setState({age:18})
//實際上是修改的this.state的里面的元素
Hook
setAge(18) //傳入一個新的age值,自動渲染至視圖層.不同於setState(),只能一次設置一個特定變量.
3.props
用法差不多,只不過hook不用初始化,直接將參數拿來用.
4.生命周期
class
componentWillMount //在渲染前調用,在客戶端也在服務端。 componentDidMount : //在第一次渲染后調用,只在客戶端。之后組件已經生成了對應的DOM結構,可以通過this.getDOMNode()來進行訪問。 如果你想和其他JavaScript框架一起使用,可以在這個方法中調用setTimeout, setInterval或者發送AJAX請求等操作(防止異步操作阻塞UI)。 componentWillReceiveProps //在組件接收到一個新的 prop (更新后)時被調用。這個方法在初始化render時不會被調用。 shouldComponentUpdate //返回一個布爾值。在組件接收到新的props或者state時被調用。在初始化時或者使用forceUpdate時不被調用。 可以在你確認不需要更新組件時使用。 componentWillUpdate//在組件接收到新的props或者state但還沒有render時被調用。在初始化時不會被調用。 componentDidUpdate //在組件完成更新后立即調用。在初始化時不會被調用。 componentWillUnmount//在組件從 DOM 中移除之前立刻被調用。
Hook
生命周期的實質就是回調函數,只不過用不同的生命周期表示不同階段的回調函數.目前Hook只有一個回調函數useEffect(),但是在多個階段觸發
import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); useEffect(() => { // 如果你熟悉 React class 的生命周期函數,你可以把useEffect
Hook 看做componentDidMount
,componentDidUpdate
和componentWillUnmount
這三個函數的組合。 document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
另外,useEffect()還可以手動設置依賴項,它可以接收兩個參數,第一個是函數,第二個是依賴項(數組),第二個參數給的話就依據依賴項時候更改決定是否調用,不給就類似上面的用法.
import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; },[count]); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> );
5.comtext
具體的需求就是組件之間的的狀態共享,比如兄弟之間、爺孫之間,跨組件的狀態共享.解決了參數需要逐層往下傳遞的麻煩.
class
// Context 可以讓我們無須明確地傳遍每一個組件,就能將值深入傳遞進組件樹。 // 為當前的 theme 創建一個 context(“light”為默認值)。 const ThemeContext = React.createContext('light'); class App extends React.Component { render() { // 使用一個 Provider 來將當前的 theme 傳遞給以下的組件樹。 // 無論多深,任何組件都能讀取這個值。 // 在這個例子中,我們將 “dark” 作為當前的值傳遞下去。 return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } } // 中間的組件再也不必指明往下傳遞 theme 了。 function Toolbar(props) { return ( <div> <ThemedButton /> </div> ); } class ThemedButton extends React.Component { // 指定 contextType 讀取當前的 theme context。 // React 會往上找到最近的 theme Provider,然后使用它的值。 // 在這個例子中,當前的 theme 值為 “dark”。 static contextType = ThemeContext; render() { return <Button theme={this.context} />; } }
Hook
const themes = { light: { foreground: "#000000", background: "#eeeeee" }, dark: { foreground: "#ffffff", background: "#222222" } }; const ThemeContext = React.createContext(themes.light); function App() { return ( <ThemeContext.Provider value={themes.dark}> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar(props) { return ( <div> <ThemedButton /> </div> ); } function ThemedButton() { const theme = useContext(ThemeContext); //由於沒有了this,所以我們需要用這個api來獲取context,然后使用.其他的用法一樣 return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); }
6.ref
這里主要針對,ref綁定字符串這種形式的使用.回調函數的用法是一樣的,其根本原因還是Hook並沒有"this.refs"這種獲取ref的方式
class
<input ref="input" /> let inputEl = this.refs.input;//這里拿到對應的ref,然后處理相關邏輯
Hook
function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { // `current` 指向已掛載到 DOM 上的文本輸入元素 inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }
7.reducer
class
this.props.dispatch({type:'/api'})
Hook
const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </> ); }
待補充