前言
当我在网上搜这个问题 函数式组件和类组件的区别 的时候,看到的都是关于大神这篇文章的复制,大家没看过的可以先看看,最主要的一个问题就是讨论就是类组件的 this 是可变的,函数组件的 props 是不可变的,但是却没看到一篇文章说为什么,都是文章中说的React 对于 this 是可变的,对于 props 是不可变的。我想说***。
我来说说原因
class 组件和类组件的渲染机制
class 是通过 new class() 创建的实例,调用 render 执行渲染,函数是直接执行渲染。
// 类组件
class App extends React.Component {
render() {
return <jsx />
}
}
new App().render();
// 函数组件
function App() {
return <jsx />
}
App();
class 组件和类组件的更新机制
- 组件的 state 变化,class 是通过 this.render() 更新的组件,在执行相关的生命周期。
- 函数是重新调用方法更新(这也是为什么函数的方法会执行多次的原因)。
props 并不是不可变
准确来说是 props 在当前作用域不可变,因为形成了闭包。而 props 本身就会变. props依赖于父组件,父组件传给子组件参数改变时候,props就已经变了。
// props 可变,点击 Change Value,你就已经看到 value 的值已经变了
function Component({ value, setValue }) {
return (
<div>
<div>{value}</div>
<div
onClick={() => {
setValue("Change Value");
}}
>
Change Value
</div>
</div>
);
}
function App() {
const [value, setValue] = useState("value");
return <Component value={value} setValue={setValue} />;
}
// props 不可变
function Component({ value, setValue }) {
const input = () => {
setTimeout(() => {
console.log("value", value);
}, 2000);
};
return (
<div>
<div>{value}</div>
<div
onClick={() => {
setValue("Change Value");
input();
}}
>
Change Value
</div>
</div>
);
}
function App() {
const [value, setValue] = useState("value");
return <Component value={value} setValue={setValue} />;
}
export default App;
原因
-
函数式组件会形成闭包,劫持 props,所以 props 不可变,
// 如上: props 并不是不可变
-
class 不会形成闭包,this 拿到的一直是最新的值。当 state 改变时,会调用 render 方法更新组件,doSomething 方法并没有形成闭包
class Child extends React.Component { render() { return ( <div onClick={() => this.props.doSomething()}>{this.props.value}</div> ); } } class App extends React.Component { constructor(props) { super(props); this.state = { value: "123" }; } doSomething = () => { this.setState({ value: "value" }); setTimeout(() => { console.log("value", this.state.value); }, 2000); }; render() { return <Child doSomething={this.doSomething} value={this.state.value} />; } }
-
class 如何形成闭包
class Child extends React.Component { render() { const props = this.props; const input = () => { console.log("pre props", props); }; console.log("cur props", this.props); return ( <div onClick={() => { this.props.doSomething(); input(); }} > Click </div> ); } } class App extends React.Component { constructor(props) { super(props); this.state = { value: "value" }; } doSomething = () => { this.setState({ value: "cur value" }); console.log("async cur value", this.state.value); setTimeout(() => { console.log("cur value", this.state.value); }, 2000); }; render() { return <Child doSomething={this.doSomething} value={this.state.value} />; } }
总结
闭包,自己看去吧