ホームページ >ウェブフロントエンド >フロントエンドQ&A >React が関数コンポーネントを推奨する理由
理由: 1. 関数コンポーネントの構文が短くてシンプルなので、開発、理解、テストが容易になります; 2. クラス コンポーネントでこれを過度に使用すると、ロジック全体が混乱して見えるようになります; 3. フック 関数関数コンポーネントのみをサポートします; 4. React チームは、不要なチェックやメモリ リークを回避するために、関数コンポーネントのさらなる最適化を行いました; 5. 関数コンポーネントはインスタンスを作成してレンダリングする必要がないため、関数コンポーネントのパフォーマンス消費が低くなります。返された要素を反応させ、すべての中間量を直接破棄します。
#このチュートリアルの動作環境: Windows7 システム、react18 バージョン、Dell G3 コンピューター。
React フレームワークを使用して開発する場合、コンポーネントを作成する方法には関数を使用する方法とクラスを使用する方法がありますが、現在は関数コンポーネントを使用することが多くなっています。以下では、例を使用して機能コンポーネントとクラスコンポーネントの違いを分析し、機能コンポーネントを使用する理由 (利点) をまとめます。
関数コンポーネントとクラス コンポーネントは、JSX を異なる方法で処理します。名前のように、関数コンポーネントは純粋な Javascript 関数であり、直接 JSX を返します。 ; クラス コンポーネントは、React.Component
を拡張し、JSX を返す render メソッドを実装する Javascript クラスです。以下は例です:
import React from "react";
const FunctionalComponent = () => {
return <h1>Hello, world</h1>;
};
上記は、ES6 アロー関数の形式で関数コンポーネントを定義し、関数本体は直接 JSX を返します。アロー関数に慣れていない場合は、次の形式でアロー関数を記述することもできます。
import React from "react";
function FunctionalComponent() {
return <h1>Hello, world</h1>;
}
2 つの記述方法は同じです。
次に、クラス コンポーネントを定義する方法を見てみましょう。まず React.Component
を拡張し、次に render メソッドで JSX を返す必要があります。次のコード スニペットを参照してください。詳細:
import React, { Component } from "react";
class ClassComponent extends Component {
render() {
return <h1>Hello, world</h1>;
}}
上記では、ES6 の構造化代入構文を使用してモジュールをインポートしています。構造化代入構文に慣れていない場合は、次の形式で記述することもできます。
import React from "react";
class ClassComponent extends React.Component {
render() {
return <h1>Hello, world</h1>;
}
}
データをコンポーネントに渡す必要がある場合、次のような小道具を使用します。 as<FunctionalComponent name="Shiori" />
、name はコンポーネントの props 属性です。ここにはさらに多くの属性を含めることができます。 FunctionalComponent コンポーネントの関数形式は次のように定義されます。
const FunctionalComponent = ({ name }) => {
return <h1>Hello, {name}</h1>;
};
または、構造化代入を使用しないでください
const FunctionalComponent = (props) => {
return <h1>Hello, {props.name}</h1>;
};
このように、name 属性を取得するには、props.name
を使用する必要があります。
次に、クラス コンポーネントが props をどのように使用するかを見てみましょう。
class ClassComponent extends React.Component {
render() {
const { name } = this.props;
return <h1>Hello, { name }</h1>;
}}
クラス コンポーネントでは、this
を使用して props を取得する必要があります。 , その後、構造化代入を使用して name
属性を取得できます。
React プロジェクトでは、必然的に状態変数を処理する必要があります。クラスコンポーネントは最近まで状態の処理をサポートしていませんでしたが、React バージョン 16.8 からは関数コンポーネントがフックメソッド useState
をサポートするようになり、関数コンポーネントで状態変数を簡単に使用できるようになりました。以下では、カウンターカウンターの例を使用して、それらの違いを説明します。
const FunctionalComponent = () => {
const [count, setCount] = React.useState(0);
return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count + 1)}>Click</button>
</div>
);};
ここでは useState
フックが使用されており、初期状態をパラメータとして指定します。この場合、カウンターは 0 から始まるため、count に初期値 0 を与えます。
state の初期値は、JavaScript で許可されている限り、null、文字列、オブジェクト オブジェクトなどのさまざまなデータ型をサポートします。 =
の左側では、構造化代入の形式を使用して、現在の状態変数と変数を更新するセッター関数、つまり count
を含む useState の戻り値を受け取ります。および setCount
。
class ClassComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>count: {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click
</button>
</div>
);
}}
与函数组件大同小异,首先我们要理解React.Component
的构造函数constructor
,react的官方文档对constructor的定义如下:
“The constructor for a React component is called before it is mounted. When implementing the constructor for a React.Component subclass, you should call super(props) before any other statement. Otherwise, this.props will be undefined in the constructor, which can lead to bugs.”
翻译一下,
React组件的constructor方法会在组件完全加载完成之前调用。在constructor方法中,你需要在第一行调用super(props),否则会报this.props是undefined的错误。
如果在类组件中,你没有实现constructor方法并调用super(props),那么所有的状态变量都将是undefined。所以,别忘记先定义constructor方法,在constructor方法中,我们需要给this.state一个初始值,像上面的代码那样。然后我们可以在JSX中使用this.state.count
来获取count的值,setter的使用也是类似的。
这里先定义一个onClick
方法,后面会用到,
onClick={() =>
this.setState((state) => {
return { count: state.count + 1 };
})}
这里注意setState()方法接收的是个箭头函数,而箭头函数的参数是state和props,props是可选的,这里没用到就没写。
React的组件在它整个的渲染的过程中,有它的生命周期。如果你之前一直使用类组件,刚刚接触函数组件,你可能会疑惑,为什么在函数组件中没有componentDidMount()
这类的生命周期方法?但是别急,有其他的钩子函数可以使用。
类组件的生命周期函数componentDidMount
会在首次渲染完成之后调用。首次渲染完成之前会调用componentWillMount
,但是这个方法在新版本的React中不推荐使用了。
在函数组件中,我们使用useEffect
钩子函数来处理生命周期内的事件,像下面这样,
const FunctionalComponent = () => {
React.useEffect(() => {
console.log("Hello");
}, []);
return <h1>Hello, World</h1>;};
useEffect
有两个参数,第一个是箭头函数,第二个是[]
,[]
里面是变化的state(s)
。什么意思呢?就是[]
中的状态变化了,箭头函数会被调用。如果像现在这样写个[]
,那箭头函数只会在组件第一次渲染之后调用一次,其功能类似下面类组件的componentDidMount
。
class ClassComponent extends React.Component {
componentDidMount() {
console.log("Hello");
}
render() {
return <h1>Hello, World</h1>;
}}
const FunctionalComponent = () => {
React.useEffect(() => {
return () => {
console.log("Bye");
};
}, []);
return <h1>Bye, World</h1>;};
这里注意return的也是一个箭头函数,这个函数就是在卸载阶段执行的。当你需要执行一些卸载操作,可以放在这里,比如你可以把clearInterval放在这里,避免内存泄漏。使用useEffect钩子函数的最大好处就是可以把加载函数和卸载函数放在一个同一个地方。这里对比一下类组件的写法:
class ClassComponent extends React.Component {
componentWillUnmount() {
console.log("Bye");
}
render() {
return <h1>Bye, World</h1>;
}}
函数组件和类组件各有优缺点,但函数组件相比类组件的优势:
函数组件语法更短、更简单,这使得它更容易开发、理解和测试;而类组件也会因大量使用 this而让人感到困惑
类组件过多的使用this
让整个逻辑看起来很混乱;
React团队主推的React hooks功能也只支持函数组件;
注:React团队也在努力将hooks功能引入类组件,所以没必要将现有的类组件都改写成函数组件;
类组件的性能消耗比较大,因为类组件需要创建类组件的实例,而且不能销毁。
函数式组件性能消耗小,因为函数式组件不需要创建实例,渲染的时候就执行一下,得到返回的react元素后就直接把中间量全部都销毁。
以上がReact が関数コンポーネントを推奨する理由の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。