違い: 1. function コンポーネントは props オブジェクトを受け取り、react 要素を返す純粋な関数ですが、class コンポーネントは React.Component を継承し、react 要素を返すレンダー関数を作成する必要があります。 2. 関数コンポーネントにはライフサイクルと状態がありませんが、クラスコンポーネントにはライフサイクルと状態があります。
、
この記事の動作環境: Windows7 システム、Dell G3 コンピューター、react17.0.1 バージョン。
この記事では、関数コンポーネントとクラスコンポーネントの違いは何か、コーディング中にどのように選択すべきかについて説明します。
コンポーネントを定義する最も簡単な方法は、JavaScript
関数を使用することです。
import React from 'react' const Welcome = (props) => { return <h1>welcome, {props.name}</h1> } export default Welcome
この関数は、props
オブジェクトを受け取り、## を返します。 #react Elements
ES6 class 構文を使用してコンポーネントを記述することもできます。
import React from 'react' class Welcome extends React.Component { constructor(props) { super(props) } render() { return <h1>welcome, {this.props.name}</h1> } } export default Welcome
1. 構文
両者の最も明らかな違いは、構文上、関数コンポーネントが純粋関数であることです。props オブジェクトを受け取り、
react 要素を返します。クラス コンポーネントは、
React.Component を継承し、
react 要素を返す
render 関数を作成する必要があります。これにより、同じ効果が得られますが、より多くのコードが必要になります。 . .
babel7 を使用してそれぞれを翻訳してみましょう。
関数コンポーネントの翻訳結果:
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _react = _interopRequireDefault(require("react")); var Welcome = function Welcome(props) { return _react["default"].createElement("h1", null, "welcome, ", props.name); }; var _default = Welcome; exports["default"] = _default;
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _react = _interopRequireDefault(require("react")); var Welcome = /*#__PURE__*/ function (_React$Component) { (0, _inherits2["default"])(Welcome, _React$Component); function Welcome(props) { (0, _classCallCheck2["default"])(this, Welcome); return (0, _possibleConstructorReturn2["default"])(this, (0, _getPrototypeOf2["default"])(Welcome).call(this, props)); } (0, _createClass2["default"])(Welcome, [{ key: "render", value: function render() { return _react["default"].createElement("h1", null, "welcome, ", this.props.name); } }]); return Welcome; }(_react["default"].Component); var _default = Welcome; exports["default"] = _default;
ES5 に変換された後のコードがますます長くなっていることがわかりますが、これはそれらを区別する主な要素ではなく、理解するだけです。
2. 状態管理
関数コンポーネントは純粋関数であるため、関数コンポーネントでsetState()## を使用することはできません。コンポーネント #。これが、関数コンポーネントがステートレス コンポーネントと呼ばれる理由です。 コンポーネントで
を使用する必要がある場合は、クラス コンポーネントを作成するか、state
を親コンポーネントにプロモートして props を渡すことを選択できます。
オブジェクトが子コンポーネントに渡されました。
3. ライフ サイクル フック
state と同じ理由で、関数コンポーネントでライフ サイクル フックを使用することはできません。同様に、すべてのライフサイクル フックは、継承された React.Component
から取得されます。 したがって、ライフサイクルフックを使用したい場合は、クラスコンポーネントを使用する必要があります。
hooks は react16.8
バージョンに追加され、関数コンポーネントで useState
フックを使用できるようになりました。 state
、useEffect
フックを使用してライフサイクル関数を使用します。したがって、ポイント 2 と 3 は相違点ではありません。このリビジョンから、作者が機能コンポーネントをより重視していることがわかり、react
チームは、react
の後続のバージョンでは機能コンポーネントのパフォーマンスが向上すると述べています。
4. メソッドの呼び出し
SayHi が関数の場合、React
それを呼び出す必要があります: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">// 你的代码
function SayHi() {
return <p>Hello, React</p>
}
// React内部
const result = SayHi(props) // » <p>Hello, React</p></pre><div class="contentsignin">ログイン後にコピー</div></div>
がクラスの場合、React
は最初に new
演算子を使用してインスタンス化してから呼び出す必要があります。インスタンスを生成するための render
メソッド: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">// 你的代码
class SayHi extends React.Component {
render() {
return <p>Hello, React</p>
}
}
// React内部
const instance = new SayHi(props) // » SayHi {}
const result = instance.render() // » <p>Hello, React</p></pre><div class="contentsignin">ログイン後にコピー</div></div>
react が返されます。 要素、クラス コンポーネント 再レンダリングは、新しいコンポーネント インスタンスを new
し、その後 render
クラス メソッドを呼び出して react
要素を返します。クラスコンポーネント # の this## が変数
#This をレンダリングするときに値を取得します。が最大の違いですが、無視されることがよくあります。
次のコンポーネントについて考えてみましょう:function ProfilePage(props) { const showMessage = () => { alert('Followed ' + props.user); } const handleClick = () => { setTimeout(showMessage, 3000); } return ( <button>Follow</button> ) }
UserProfile
コンポーネントは非常に単純で、setTimeout## を使用する フォロー
ボタンだけです。 # ネットワークリクエストをシミュレートします。ユーザーがこのボタンをクリックすると、警告ボックスがポップアップ表示されます。 props.user
が 'Dan'
の場合、3 秒後に 'Followed Dan'
と表示されます。 これをクラスとして記述するにはどうすればよいでしょうか?素朴な翻訳は次のようになります。
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">class ProfilePage extends React.Component {
showMessage() {
alert('Followed ' + this.props.user);
}
handleClick() {
setTimeout(this.showMessage.bind(this), 3000);
}
render() {
return <button>Follow</button>
}
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
これら 2 つのコード スニペットは同等であると考えるのが一般的です。人々は、その意味に気づかずに、これらのパターン間を自由にリファクタリングすることがよくあります。
よく見てください。違いがわかりますか?
次の順序で フォロー ボタンを操作します。
最初に ## の
フォロー
前にドロップダウン選択のオプションを変更します。
関数の間に違いがあることがわかります。コンポーネントとクラスコンポーネント:函数组件:按上面所列的三个步骤操作时,当用户在3s
前更改下拉选择框的选项时,h1
的用户名会立马改变,而3s
后弹出的警告框中的用户名并不会改变
类组件:按上面所列的三个步骤操作时,当用户在3s
前更改下拉选择框的选项时,h1
中的用户名会立马改变,而3s
后弹出的警告框中的用户名也会改变
那么,为什么我们的类示例会这样表现呢?
让我们仔细看一下showMessage
类中的方法:
showMessage() { alert('Followed ' + this.props.user); }
在showMessage
方法中读取了this.props.user
(也是我们要输出的用户名称)。而React
中的props
是不可变的,但是this
是可变的,而且是一直是可变的。这也是类组件中this
的目的。React
自身会随着时间的推移对this
进行修改,以便你可以在render
函数或生命周期中读取新的版本。
因此,如果组件在请求重新渲染时,this.props
将会改变。showMessage
方法会从新的props
中读取user
。你所看到的效果也正是因为这个原因。
在React
中的组件,UI
在概念上可以理解是程序当前状态的函数,那么事件处理就是让UI
的渲染结果一部分一部分可视化输出。我们的事件处理程序属于具有特定props
和state
的特定渲染。但是,当回调超时的话,this.props
就会打破这种联系。示例中的showMessage
方法在回调时没有绑定到任何特定的渲染,因此它会丢失真正的props
。
那么我们有没有一种较好的方式可以使用正确的props
来修复render
和showMessage
回调之间的联系。我们可以在事件发生的早期,将this.props
传递给超时完成的处理程序来尝试着解决这个问题。这种解决方式属于闭包的范畴。
class ProfilePage extends React.Component { showMessage(user) { alert('Followed ' + user); } handleClick() { cosnt {user} = this.props setTimeout(this.showMessage.bind(this, user), 3000); } render() { return <button>Follow</button> } }
我们使用闭包机制将上一状态的值保存下来待showMessage
方法调用。即使this.props
发生变化,但并不改变user
这种方法虽然解决我们前面所提到的问题,但是这种方法代码会随着props
的个数增加,代码也会变得更加冗余也易于出错。如果我们也需要访问state
。如果showMessage
调用另一个方法,该方法会读取this.props.something
或this.state.something
。我们又会碰到同样的问题。所以我们必须通过this.props
作为showMessage
的参数来修复它们之间存在的问题。
但这么做会破坏类提供的特性。也令人难于记住或执行。另外,在handleClick
中内联alert
中的代码并不能解决更大的问题。我们希望以一种允许代码分解成更多方法的方式来构造代码,同时还可以读取与其相关的render
所对应的props
和state
。
或许,我们可以在类的构造函数中绑定这些方法:
class ProfilePage extends React.Component { render() { // 获取props cosnt props = this.props // 它们不是类方法 const showMessage = () => { alert('Followed ' + props.user); } const handleClick = () => { setTimeout(showMessage, 3000) } return <button>Follow</button> } }
这样一来,函数组件和类组件所达到的效果都一样了。在类组件中可以捕获渲染时的props
。效果上看上去是一样了,但看起来怪怪的。如果在类组件中的render
中定义函数而不是使用类方法,那么还有使用类的必要性?
更多编程相关知识,请访问:编程课程!!
以上がReact の関数コンポーネントとクラス コンポーネントの違いは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。