この記事では、React Hooks と関数コンポーネントを使用して開発された 2 つの簡単な例を紹介します。 簡単なコンポーネントの例ボタン コンポーネントは、最も一般的に使用される最も単純な基本コンポーネントと考えることができます。コンポーネントを開発する場合、さまざまなシナリオに適用できるように、その基本的なスタイルがある程度変化することを期待します。 2 つ目のポイントは、以前プロジェクトに取り組んでいたときに関数コンポーネントを作成したのですが、この関数コンポーネントは非常に厳密に作成されており、基本的なメソッドをバインドする方法がなかったということです。つまり、すでに持っているメソッドや特性しか記述できません。 Button コンポーネントを記述したいと思います。onClick メソッドを記述しなくても、それに付属するデフォルトの基本メソッドを使用できるようにしたいと考えています。 最初の点については、異なる classNames ごとに異なる CSS を記述することで実装が簡単になります。 2 番目のポイントは達成するのが少し難しいです。 Button のすべてのデフォルト プロパティを再度記述することはできませんが、すべてのデフォルト プロパティをインポートできれば便利です。 実際、React はすでにこれを実現するのに役立っています。 React.ButtonHTMLAttributes<HTMLElement> には、デフォルトの Button 属性が含まれています。ただし、Button コンポーネントにカスタマイズされた部分がある可能性があるため、このインターフェースを直接使用することはできません。これにはTypescriptのクロスタイプを使用することができます NativeButtonProps = MyButtonProps & React.ButtonHTMLAttributes<HTMLElement> と入力します。 さらに、他の非カスタム関数やプロパティをインポートするには、resProps を使用する必要もあります。 以下は、Button コンポーネントの具体的な実装です。 'react' から React をインポートします 'classnames' から classNames をインポートします ButtonSize を 'large' | 'small' と入力します タイプ ButtonType = 'primary' | 'default' | 'danger' インターフェイス BaseButtonProps { クラス名?: 文字列; 無効?: ブール値; サイズ?: ボタンサイズ; btnType?: ボタンタイプ; 子?: React.ReactNode; } タイプ NativeButtonProps = BaseButtonProps & React.ButtonHTMLAttributes<HTMLElement> const ボタン: React.FC<NativeButtonProps>= (props) => { 定数{ btnタイプ、 クラス名、 無効、 サイズ、 子供たち、 //resProps は残りのすべてのプロパティを取得するために使用されます...resProps } = 小道具 // btn、btn-lg、btn-primary const クラス = classNames('btn', className, { [`btn-${btnType}`]: btnType、 [`btn-${size}`]: サイズ、 「無効」: 無効 }) 戻る ( <ボタン className={クラス} 無効={無効} {...resProps} > {子供たち} </ボタン> ) } ボタン.defaultProps = { 無効: false、 btnType: 'デフォルト' } デフォルトボタンをエクスポート 上記の方法で、カスタム Button コンポーネントで onClick メソッドを使用できます。以下は、Button コンポーネントの使用例です。 <ボタンが無効>こんにちは</ボタン> <Button btnType='primary' size='large' className="haha">こんにちは</Button> <Button btnType='danger' size='small' onClick={() => alert('haha')}>テスト</Button> 表示効果は以下のとおりです。 このコードでは、classnames という新しい npm パッケージを導入しました。具体的な使い方については、GitHub Classnames を参照してください。これを使用すると、className の拡張を簡単に実装できます。簡単な使用例は次のとおりです。 classNames('foo', 'bar'); // => 'foo bar' classNames('foo', { bar: true }); // => 'foo bar' classNames({ 'foo-bar': true }); // => 'foo-bar' classNames({ 'foo-bar': false }); // => '' classNames({ foo: true }, { bar: true }); // => 'foo bar' classNames({ foo: true, bar: true }); // => 'foo bar' // さまざまなタイプの引数が多数あります classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux' // その他の偽の値は無視されます classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1' classNames を使用すると、Button にパーソナライズされた属性を簡単に追加できます。コンポーネントの HTML 出力に hahaclassName があることがわかります。 <button class="btn haha btn-primary btn-lg">こんにちは</button> 同時に、上記のコード メソッドは、カスタム コンポーネントがデフォルトのプロパティとメソッドを使用できないという問題も解決します。 より複雑な親子コンポーネントのケース次に、関数コンポーネントを使用してメニュー機能を完成させる方法を説明します。このメニューには、水平モードと垂直モードの 2 つの機能モードが追加されます。メニューの詳細をクリックし、この詳細を子コンポーネントとして使用します。 もちろん、メニュー機能では、親コンポーネントが子コンポーネントにデータを渡す必要はありません(子コンポーネントはメニューの詳細を参照します)。親コンポーネントのデータを子コンポーネントに渡す方法を学習および実演するために、この機能を強制的に追加します。少し余計なことですが、皆様にご理解いただければ幸いです。 まず、親コンポーネントと子コンポーネントの機能説明を紹介します。 Menu は全体的な親コンポーネント、MenuItem はそれぞれの特定の小さなメニュー、SubMenu にはクリックできるドロップダウン メニューが含まれています。 次の図は、拡張後の状態を示しています。 全体的なコード構造は次のとおりです。 <メニュー defaultIndex={'0'} onSelect={(index) => {alert(index)}} mode="vertical" defaultOpenSubMenus={['2']}> <メニュー項目インデックス={'0'}> クールなリンク </メニュー項目> <メニュー項目インデックス={'1'}> クールなリンク2 </メニュー項目> <サブメニュー title="ドロップダウン"> <メニュー項目インデックス={'3'}> ドロップダウン 1 </メニュー項目> <メニュー項目インデックス={'4'}> ドロップダウン 2 </メニュー項目> </サブメニュー> <メニュー項目インデックス={'2'}> クールなリンク3 </メニュー項目> </メニュー> このコンポーネントでは、useState を使用しました。また、親コンポーネントから子コンポーネントにデータを渡すため、useContext も使用しました (親コンポーネントから子コンポーネントにデータを渡すということは、親コンポーネントのインデックス データを子コンポーネントに渡すことを意味します)。さらに、カスタム onSelect を使用して onClick 機能を実装する方法も紹介します (React ジェネリックの導入に失敗した場合や、どの React ジェネリックを導入すればよいかわからない場合は、カスタム ジェネリックを使用して状況を改善できます)。 オンセレクトの書き方後で広大なコードの海の中で onSelect を見つけるのが困難にならないように、onSelect の簡単な記述例を示します。たとえば、Menu コンポーネントでは onSelect を使用しますが、その使用方法は onClick と同じです。 <メニュー onSelect={(index) => {alert(index)}}> この特定のメニュー コンポーネントでは、onSelect メソッドは次のように記述できます。 タイプ SelectCallback = (selectedIndex: string) => void インターフェースMenuProps { onSelect?: SelectCallback; } handleClick を実装するメソッドは次のように記述できます。 const handleClick = (インデックス: 文字列) => { // onSelect はユニオン型であり、存在するかどうかは不明なので、判断する必要があります if (onSelect) { onSelect(インデックス) } } この onSelect を子コンポーネントに渡す場合は、onSelect: handleClick を使用してバインドするだけです。 (よくわからなかったかもしれませんし、私も書き方がわかりません。後ほど全体的なコード分析があるので、一緒に読んでいただくとわかりやすいかもしれません) 反応する子供具体的なコードを説明する前に、もう少し知識として知っておくべき点がいくつかあります。そのうちの 1 つが React.Children です。
React.Children を使用する必要があるのはなぜですか?これは、親コンポーネントのデータを子コンポーネントに渡す場合、子コンポーネントを 2 回走査したり、さらに処理したりする必要がある場合があるためです。ただし、サブコンポーネントが存在するかどうか、また、サブコンポーネントが 1 つ、2 つ、またはそれ以上あるかどうかは保証できません。
したがって、親子コンポーネントがある場合、子コンポーネントをさらに処理する必要がある場合は、React.Children を使用してそれらをトラバースすることができ、this.props.children の型の変更によるエラーは発生しません。 React.cloneElementReact.Children は React.cloneElement と一緒に出現することがよくあります。そのため、React.cloneElement も導入する必要があります。
たとえば、子要素に対してさらに処理を実行する必要がある場合もありますが、React 要素自体は不変であるため、さらに処理するには複製する必要があります。このメニュー コンポーネントでは、サブコンポーネントは MenuItem または SubMenu の 2 つのタイプのみになることを期待しています。他のタイプの場合、警告メッセージが報告されます。具体的には、コードは大まかに次のように記述できます。 if (displayName === 'メニュー項目' || displayName === 'サブメニュー') { // 要素をサンプルとして新しい React 要素を複製して返します。最初のパラメータは複製されたサンプルです。 return React.cloneElement(childElement, { インデックス: index.toString() }) } それ以外 { console.error("警告: メニューには MenuItem コンポーネントではない子があります") } 親コンポーネントのデータを子コンポーネントに渡す方法コンテキストは、親コンポーネントのデータを子コンポーネントに渡すために使用されます。 Context について詳しくない場合は、公式ドキュメント Context を参照してください。親コンポーネントでは、createContext を通じて Context を作成し、子コンポーネントでは、useContext を通じて Context を取得します。 インデックスデータ転送Menu コンポーネント内の親コンポーネントと子コンポーネント間のデータ転送を実装するための主な変数は index です。 最後に、完全なコードを添付します。最初は Menu 親コンポーネントです。 React をインポートし、{useState、createContext} を 'react' から取得します。 'classnames' から classNames をインポートします './menuItem' から { MenuItemProps } をインポートします。 タイプ MenuMode = 'horizontal' | 'vertical' タイプ SelectCallback = (selectedIndex: string) => void エクスポートインターフェースMenuProps { defaultIndex?: string; // どのメニューサブコンポーネントが強調表示されるのに使用されますか? className?: string; モード?: MenuMode; スタイル?: React.CSSProperties; onSelect?: SelectCallback; // サブメニューをクリックするとコールバックがトリガーされます defaultOpenSubMenus?: string[]; } // 親コンポーネントから子コンポーネントに渡されるデータ型を決定する interface IMenuContext { インデックス: 文字列; onSelect?: SelectCallback; モード?: MenuMode; defaultOpenSubMenus?: string[]; // コンテキストにデータを渡す必要がある } // 子コンポーネントに渡すコンテキストを作成する // 一般的な制約。インデックスは入力する値なので、ここにデフォルトの初期値を記述します。 export const MenuContext = createContext<IMenuContext>({index: '0'}) const メニュー: React.FC<MenuProps> = (props) => { const { className、mode、style、children、defaultIndex、onSelect、defaultOpenSubMenus} = props // アクティブ状態の MenuItem は 1 つだけなので、その状態を制御するには useState を使用します。const [ currentActive, setActive ] = useState(defaultIndex) const クラス = classNames('menu-demo', className, { 'menu-vertical': モード === 'vertical'、 'menu-horizontal': モード === 'horizontal' }) // menuItem をクリックした後にアクティブの変更を実装するために handleClick を定義します。const handleClick = (index: string) => { setActive(インデックス) // onSelect はユニオン型であり、存在するかどうかは不明なので、判断する必要があります if (onSelect) { onSelect(インデックス) } } // サブコンポーネントをクリックすると、onSelect 関数がトリガーされ、ハイライト表示が変更されます。const passingContext: IMenuContext = { // currentActive は string | undefined 型で、index は number 型なので、型 index をさらに明確にするために次の判断を行う必要があります: currentActive ? currentActive : '0', onSelect: handleClick, // コールバック関数、サブコンポーネントをクリックしたときにトリガーするかどうか mode: mode, デフォルトOpenSubMenus、 } const レンダリング子 = () => { React.Children.map(children, (child, index) => { を返します。 // child には多くの型が含まれています。スマートプロンプトを提供したい型を取得するには、型アサーション const childElement = child as React.FunctionComponentElement<MenuItemProps> を使用する必要があります。 const { displayName } = 子要素の型 if (displayName === 'メニュー項目' || displayName === 'サブメニュー') { // 要素をサンプルとして新しい React 要素を複製して返します。最初のパラメータは複製されたサンプルです。 return React.cloneElement(childElement, { インデックス: index.toString() }) } それ以外 { console.error("警告: メニューには MenuItem コンポーネントではない子があります") } }) } 戻る ( <ul className={クラス} style={スタイル}> <MenuContext.Provider 値 = {passedContext}> {レンダリング子()} </メニューコンテキスト.プロバイダー> </ul> ) } メニュー.defaultProps = { デフォルトインデックス: '0', モード: '水平'、 デフォルトのOpenSubMenus: [] } デフォルトメニューをエクスポート 次に、MenuItem サブコンポーネント: 'react' から React をインポートします 'react' から {useContext} をインポートします。 'classnames' から classNames をインポートします './menu' から { MenuContext } をインポートします。 エクスポートインターフェースMenuItemProps { インデックス: 文字列; 無効?: ブール値; クラス名?: 文字列; スタイル?: React.CSSProperties; } const メニュー項目: React.FC<MenuItemProps> = (props) => { const { インデックス、無効、クラス名、スタイル、子 } = プロパティ const コンテキスト = useContext(メニューコンテキスト) const classes = classNames('メニュー項目', className, { 'is-disabled': 無効、 // 'is-active' を強調表示する特定のロジックを実装します: context.index === index }) const ハンドルクリック = () => { // 無効にするとonSelectは使えなくなります。indexはオプションなので存在しない可能性があります。typeofを使って判断する必要があります if (context.onSelect && !disabled && (typeof index === 'string')) { コンテキスト.onSelect(インデックス) } } 戻る ( <li className={classes} style={style} onClick={handleClick}> {子供たち} </li> ) } MenuItem.displayName = 'メニュー項目' デフォルトのメニュー項目をエクスポートする 最後に、SubMenu サブコンポーネント: 'react' から React、{useContext、FunctionComponentElement、useState } をインポートします。 'classnames' から classNames をインポートします './menu' から { MenuContext } をインポートします。 './menuItem' から { MenuItemProps } をインポートします。 エクスポートインターフェース SubMenuProps { インデックス?: 文字列; タイトル: 文字列; クラス名?: 文字列 } const サブメニュー: React.FC<SubMenuProps> = ({ インデックス、タイトル、子、クラス名 }) => { const コンテキスト = useContext(メニューコンテキスト) // 次に、文字列配列のいくつかのメソッドを使用します。まず、型アサーションを作成し、文字列配列型としてアサートします。const openedSubMenus = context.defaultOpenSubMenus as Array<string> // include を使用してインデックスがあるかどうかを判断します const isOpened = (index && context.mode === 'vertical') ? openedSubMenus.includes(index) : false const [ menuOpen, setOpen ] = useState(isOpened) // isOpened は動的な値である true または false を返します。const classes = classNames('menu-item submenu-item', className, { 'is-active': context.index === インデックス }) // ドロップダウンメニューを表示または非表示にするために使用されます const handleClick = (e: React.MouseEvent) => { e.preventDefault() setOpen(!menuOpen) } タイマー: 任意 // トグルは開くか閉じるかを決定するために使用されます const handleMouse = (e: React.MouseEvent, toggle: boolean) => { タイムアウトをクリア(タイマー) e.preventDefault() タイマー = setTimeout(()=> { setOpen(トグル) }, 300) } // 三項式、垂直 const clickEvents = context.mode === 'vertical' ? { onClick: ハンドルクリック } : {} const hoverEvents = context.mode === 'horizontal' ? { onMouseEnter: (e: React.MouseEvent) => { handleMouse(e, true) }, onMouseLeave: (e: React.MouseEvent) => { handleMouse(e, false) }, } : {} // ドロップダウン メニューの内容をレンダリングするために使用されます // 2 つの値を返します。1 つ目は子、2 つ目は i で表されるインデックスです。const renderChildren = () => { const subMenuClasses = classNames('menu-submenu', { 'メニューを開いた': menuOpen }) // 次の関数は、サブメニューにのみ MenuItem が存在することを実装するために使用されます。 const childrenComponent = React.Children.map(children, (child, i) => { const childElement = 子を FunctionComponentElement<MenuItemProps> として定義します。 子要素のtype.displayNameが'メニュー項目'の場合{ React.cloneElement(childElement, { を返します。 インデックス: `${index}-${i}` }) } それ以外 { console.error("警告: SubMenu には MenuItem コンポーネントではない子があります") } }) 戻る ( <ul className={サブメニュークラス}> {子コンポーネント} </ul> ) } 戻る ( // 演算子を展開し、内部に機能を追加し、外部にホバーします <li key={index} className={classes} {...hoverEvents}> <div className="サブメニュータイトル" {...clickEvents}> {タイトル} </div> {レンダリング子()} </li> ) } サブメニュー.displayName = 'サブメニュー' デフォルトのサブメニューをエクスポート 参考文献
以上がReact Hookの使用例の詳細です。React Hookの使用についての詳細は、123WORDPRESS.COM内の他の関連記事にも注目してください! 以下もご興味があるかもしれません:
|
<<: Nginxはctxを使用してデータ共有とコンテキスト変更機能を実現します。
>>: MySQL 5.7.18 バージョンのインストール パスのカスタマイズに関する詳細なチュートリアル (バイナリ パッケージのインストール)
1. MySQL 1.1 MySQLのインストールmysql-5.5.27-winx64 ダウンロー...
パート1: 基礎1. :active や :hover などの疑似クラスとは異なり、これらはすべて疑...
プロジェクトで使用されている特殊文字とアイコンHTMLコードXML/HTML コードコンテンツをクリ...
nginx がリソース圧縮を実現する原理は、ngx_http_gzip_module モジュールを介...
1. よく使われるHTMLタグの最適化HTML は Web 編集者にとって基本的なスキルであるべきで...
序文インターネット上には、MySQL でインデックスにヒットできないさまざまな状況をまとめた記事がよ...
MySQL ページング クエリは通常、制限を通じて実装されます。 limit は 1 つまたは 2 ...
セルでは、明るい境界線の色を個別に定義できます。 > 基本構文<TD ボーダーカラーライ...
導入Dockerfile ビルドの実行は、単一のコンテナの手動操作です。マイクロサービス アーキテク...
目次1. 一般的な高階関数1.1、フィルター1.2、地図1.3、減らすHigher Order fu...
この記事では、シンプルなカレンダー効果を実現するためのjsの具体的なコードを参考までに共有します。具...
序文データベースの実際の使用では、データの書き込みや読み取りを同時に行わないことが必要な状況によく遭...
序文みなさんこんにちは。私は梁旭です。職場では、システムの起動後にスクリプトやサービスを自動的に開始...
CSS3 - 影の追加(ボックスシャドウの使用) CSS3 - div またはテキストに影を追加する...
CentOS 7 の yum ソースには、MySQL を正常にインストールするための mysql-s...