一、函數式組件創建
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>
</>
);
}
待補充
