有段时间,这个问题标准回答是 class 组件提供了访问更多特性的权限(好比state),随着 Hooks 发布,那就不是这样了。javascript
或许,你听过他们中哪一个性能更好这样的问题,性能取决于你的代码作了什么而不是你选择用 function 仍是class 组件。实际上这二者之间的性能差异是微不足道的,具体能够参考这个对比结果。html
在这篇文章中,咱们来看看它们二者之间最大的不一样。java
事先申明:并不对 Function 与 Classes 进行优劣对比,而仅仅是说明 react 两种模式的不一样。react
对比下面两段代码:git
Function Component:github
function ProfilePage(props) {
const showMessage = () => {
alert("Followed " + props.user);
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return <button onClick={handleClick}>Follow</button>;
}复制代码
Class Component:ide
class ProfilePage extends React.Component {
showMessage = () => {
alert("Followed " + this.props.user);
};
handleClick = () => {
setTimeout(this.showMessage, 3000);
};
render() {
return <button onClick={this.handleClick}>Follow</button>;
}复制代码
这两个组件代码都描述了同一个逻辑:点击按钮 3 秒后 alert
父级传入的用户名。经过这个 在线 Demo 完整代码,执行如下操做来讲明二者的区别:函数
咱们能够看到:性能
Class Component 展现的是修改后的值this
Function Component 展现的是修改前的值:
这个例子中function 组件展现的才是咱们指望的结果,由于我点了 follow 不但愿因父级 props变化而改变本来指望的渲染结果,为何 class 组件例子中出现这种状况?
class ProfilePage extends React.Component {
showMessage = () => {
alert("Followed " + this.props.user);
};复制代码
缘由是在 react 中 props 不可变(Immutable) 数据,可是在 react class 组件中,this 是可变的,所以 this.props
的调用会致使每次都访问最新的 props
。上面的 showMessage 是在3秒后执行,这时props是最新的。而 Function Component 不存在 this.props
的语法,所以 props
老是不可变的。
如何解决这个问题?
一种方式是在事件绑定方法中读取这个 props
,而后传递给showMessage:
class ProfilePage extends React.Component {
showMessage = (user) => {
alert('Followed ' + user);
};
handleClick = () => {
const {user} = this.props;
setTimeout(() => this.showMessage(user), 3000);
};
render() {
return <button onClick={this.handleClick}>Follow</button>;
}
}复制代码
可是这样写代码显得臃肿啰嗦,并且,若是在showMessage中要调用其余方法,这个方法又要读取 this.props.somthing
或者 this.state.someting
又要传递this.props 或者 this.state,这样就很麻烦。
另外一种方式就是在 render 函数中读取props:
class ProfilePage extends React.Component {
render() {
// Capture the props!
const props = this.props;
// Note: we are *inside render*.
// These aren't class methods.
const showMessage = () => {
alert('Followed ' + props.user);
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return <button onClick={handleClick}>Follow</button>;
}
}复制代码
这看起来很奇怪,加以简化,其实就是 function 组件。
看下面代码:
function MessageThread() {
const [message, setMessage] = useState('');
const showMessage = () => {
alert('You said: ' + message);
};
const handleSendClick = () => {
setTimeout(showMessage, 3000);
};
const handleMessageChange = (e) => {
setMessage(e.target.value);
};
return (
<>
<input value={message} onChange={handleMessageChange} />
<button onClick={handleSendClick}>Send</button>
</>
);
}复制代码
在点击 Send
按钮后,再次修改输入框的值,3 秒后的输出依然是 点击前输入框的值。这说明 Hooks 一样具备 capture value 的特性。
若是咱们想避开 capture values 的特性,就想获取最新的输入框的值怎么办?在 class 组件中,咱们只须要访问 this.props 就行,由于 this 是可变的,能读取最新的props。
这里咱们利用 useRef
能够规避 capture values 特性:
function MessageThread() {
const [message, setMessage] = useState('');
// Keep track of the latest value.
const latestMessage = useRef('');
useEffect(() => {
latestMessage.current = message;
});
const showMessage = () => {
alert('You said: ' + latestMessage.current);
};
const handleSendClick = () => {
setTimeout(showMessage, 3000);
};
const handleMessageChange = (e) => {
setMessage(e.target.value);
};
return (
<>
<input value={message} onChange={handleMessageChange} />
<button onClick={handleSendClick}>Send</button>
</>
);
}复制代码
function 组件与 class 组件最大的不一样是 function 组件可以捕获渲染的值,而 class 组件由于 react 中 this 是可变的,因此老是能获取最新的 props 。一样 hooks 和 function 组件同样具备 capture values 特性,利用useRef 能够避免 capture values 特性。