聊聊函數(shù)式組件與類組件有何不同
前言
React 中最關鍵的知識點就是組件,在 React 16.8 之前(還沒有 Hooks 前),我們的應用大多寫成 Class 組件,因為 Class 組件有生命周期,能控制狀態(tài)(state)。但函數(shù)式組件只能默默站在后面,說自己是木偶組件(也叫無狀態(tài)組件),傳來 props,展示UI
以下文字都基于有了 Hooks 后
正文
函數(shù)式組件和類組件之間是否有什么根本上的區(qū)別?
函數(shù)式組件捕獲渲染時的值
具體可以看這篇文章:函數(shù)式組件與類組件有何不同?
因為在 React 中 props 是不可變(immutable)的,它們永遠不會改變。然而,this 是可變(mutable)的
事實上,這就是類組件 this 存在的意義。React 本身會隨著時間的推移而改變,以便你可以在渲染方法以及生命周期方法中得到最新的實例
函數(shù)式組件會捕獲當前狀態(tài)下的值,如果你使用定時器改變當前值的狀態(tài),那函數(shù)式組件顯示的還是原來的值,而不是最新值。而類組件會一直獲取最新值
只要一渲染,函數(shù)式組件就會捕獲當前的值。而類組件即使渲染了,但是它的 this 會指向最新的實例
類組件
可以看線上Demo
class ClassDemo extends React.Component {
state = {
value: ""
};
showMessage = () => {
alert("最新值為 " + this.state.value);
};
handleMessageChange = (e) => {
this.setState({ value: e.target.value });
};
handleClick = () => {
setTimeout(this.showMessage, 3000);
};
render() {
return (
<div>
<input value={this.state.value} onChange={this.handleMessageChange} />
<button onClick={this.handleClick}>點擊</button>
</div>
);
}
}
這樣的結果是點擊后獲取到最新的值,而不是 3 秒前的值。為什么?因為 this 可變,3 秒之后執(zhí)行 alert("最新值為 " + this.state.value)。 this.state.value 指向最新的值
如果類組件如果想保存原來的值該怎么做?
一、調用事件之前讀取this.props
可以看線上Demo
showMessage = (value) => {
alert("最新值為 " + value);
};
handleClick = () => {
const { value } = this.state;
setTimeout(() => this.showMessage(value), 3000);
};
可以解決,但點擊時獲取到當前的 user,再傳遞給 this.showMessage,這樣,即使 3 秒之后也是原來的值
缺點:每次都要從 this.props 中拿值,如果數(shù)據(jù)一多,寫起來不符合人性
二、在構造函數(shù)中綁定方法
可以看線上Demo
constructor(props) {
super(props);
this.showMessage = this.showMessage.bind(this);
this.handleClick = this.handleClick.bind(this);
}
這個方法解決不了問題。我們的問題是我們從 this.props 中讀取數(shù)據(jù)太遲了—— 讀取時已經不是我們所需要使用的上下文
三、利用閉包
把方法寫進 render 中,這樣每次渲染時就能捕獲住當時所用的 props 或者 state
可以看線上Demo
class ClassDemo extends React.Component {
state = {
value: ""
};
render() {
const { value } = this.state;
const showMessage = () => {
alert("最新值為 " + value);
};
const handleMessageChange = (e) => {
this.setState({ value: e.target.value });
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return (
<div>
<input value={this.state.value} onChange={handleMessageChange} />
<button onClick={handleClick}>點擊</button>
</div>
);
}
}
但是這個方法很蠢,這個寫法和函數(shù)式組件有什么區(qū)別呢?還不如用函數(shù)式組件呢
函數(shù)式組件如果想保存最新的值呢
使用 useRef 保存最新的值,讓組件獲得最新的值
function MyComponent() {
const ref = useRef(null);
}
首先,ref 與實例都扮演同樣的角色,ref 對象是一個有 current 屬性的一個容器
上次的例子我們用函數(shù)式組件就可以這樣寫:
const FunctionDemo = () => {
const [value, setValue] = useState("");
const refValue = useRef("");
const showMessage = () => {
alert("最新值為 " + refValue.current);
};
const handleMessageChange = (e) => {
setValue(e.target.value);
refValue.current = e.target.value;
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return (
<div>
<input value={value} onChange={handleMessageChange} />
<button onClick={handleClick}>點擊</button>
</div>
);
};
可以看線上Demo
這里筆者提出兩個疑問:
- 為什么 ref 能保存住最新的值?
- 為什么函數(shù)式組件會捕獲,類組件不會呢?