独自のReact検証ライブラリの作成:開発者エクスペリエンス(パート3)
公開: 2022-03-10この小さな一連の記事をフォローしている場合は、独自の検証ライブラリをまとめる方法を学習しました。 それはあなたがそれに投げることができるほとんどすべての挑戦を処理することができます、そしてそれはアクセシビリティの懸念にも役立ちます! その唯一の欠点は、それがうまく機能しないことです。
うん、そうだね。 開発者の観点からのユーザーエクスペリエンスは深刻に欠けています。 単語のつづりを間違えたり、APIを誤用したり、あるいは実際に何かをしたりしても、役立つ警告は表示されません。
この記事では、検証ライブラリ(またはそのためのライブラリ)の開発者エクスペリエンスを向上させる方法について説明します。
- パート1:基本
- パート2:機能
- パート3:経験
はじめに
この記事の最後の部分から、すべてのライブラリコードを独自のファイルに取り出しました。 CodeSandboxデモを見て、何から始めているかを確認してください。
便利な機能
私たちは、ライブラリをできるだけシンプルにして、最も一般的なケースで使用できるようにしたいと考えています。 その目標に向かって進む方法は、特定の機能に便利なユーティリティ関数を追加することです。
そのような機能の1つは、フォームが有効かどうか、つまり、すべてのエラーメッセージがnull
かどうかを確認することです。 これは通常、 onSubmit
ハンドラーでチェックするものですが、renderメソッドでも役立つ場合があります。 実装しましょう!
const isFormValid = useMemo( () => Object.values(errors).every(error => error === null), [errors] );
このフラグは、 onSubmit
フォームハンドラーとrenderメソッドで提供します。
- CodeSandboxデモを見る
書くことができるこれらはもっとたくさんありますが、それを読者の練習問題にしましょう。
開発の警告と不変条件
Reactの最大の機能の1つは、開発中の多くの役立つコンソール警告です。 ユーザーにも同じような品質を提供する必要があります。
まず、特定の条件が満たされない場合に、コンソールにwarning
を記録するための警告と、エラーをスローするためのinvariant
関数の2つの関数を作成します。
function warning(condition, message) { if (process.env.NODE_ENV === 'production' || condition) { return; } console.warn('useValidation: ' + message); } function invariant(condition, message) { if (process.env.NODE_ENV === 'production' || condition) { return; } throw new Error('useValidation: ' + message); }
エラーによってライブラリがクラッシュする(またはライブラリが役に立たなくなる)場合はinvariant
を使用し、悪い慣行やその他のアドバイスをwarning
します。
警告するタイミング
いつ警告するかを決めることは非常に重要です。 多すぎると、あなたはただ迷惑です。 少なすぎると、重大なバグを本番環境に出荷させることになります。 したがって、警告を賢くする必要があります。
私たちのライブラリはかなり大きな構成オブジェクトを受け入れるので、少なくとも開発中は、これを何らかの方法で検証するのが理にかなっています。 TypeScriptやFlowのような型システムを使用してそれを解決することもできますが、それはすべての通常の古いJavaScriptユーザーを除外します。
代わりに、ランタイムスキーマチェッカーを作成してみましょう。ここで、構成に正しいフィールドが含まれていることを検証し、関連する警告を出力します。
function validateConfigSchema(config) { if (process.env.NODE_ENV === 'production') { return; } if (typeof config === 'function') { config = config({}); } invariant( typeof config === 'object', `useValidation should be called with an object or a function returning an object. You passed a ${typeof config}.`, ); invariant( typeof config.fields === 'object', 'useValidation requires a `field` prop with an object containing the fields and their validators. Please refer to the documentation on usage: https://link.to/docs' ); invariant( Object.values(config.fields).every(field => typeof field === 'object'), 'useValidation requires that the `field` object only contains objects. It looks like yours isn\'t. Please refer to the documentation on usage: https://link.to/docs' ); warning( ['always', 'blur', 'submit', undefined].includes(config.showError), 'useValidation received an unsupported value in the `showError` prop. Valid values are "always", "blur" or "submit".' ) // And so on }
時間を過ごしたいのであれば、おそらくしばらくの間これを続けることができます。 そして、あなたはすべきです! これは、アプリの開発者エクスペリエンスを向上させるための優れた方法です。
ただし、これらを手で書く必要はありません。 人気のあるオブジェクトスキーマ検証ライブラリjoi
のブラウザポートがあり、非常に優れたランタイム検証チェックの作成に役立ちます。 また、前述のように、型システムは、その型システムを使用するユーザーのコンパイル時に構成エラーをキャッチするのに役立ちます。
柔軟性を考慮してください
優れた開発者エクスペリエンスは、大部分が開発者の邪魔にならないことです。 そのエクスペリエンスを改善できるいくつかの方法を見てみましょう。
競合する小道具を作成する
まず、プロップゲッターは、消費者によって誤って上書きされる可能性のある入力とフォームにいくつかのプロップを適用します。 代わりに、プロップオーバーライドオブジェクトをプロップゲッターに追加してみましょう。これにより、競合するプロップが一緒に構成されます。
getFieldProps
でこれを実装する方法は次のとおりです。
getFieldProps: (fieldName, overrides = {}) => ({ onChange: e => { const { value } = e.target; if (!config.fields[fieldName]) { return; } dispatch({ type: 'change', payload: { [fieldName]: value }, }); if (overrides.onChange) { overrides.onChange(e); } }, onBlur: e => { dispatch({ type: 'blur', payload: fieldName }); if (overrides.onBlur) { overrides.onBlur(e) } }, name: overrides.name || fieldName, value: state.values[fieldName] || '', }),
getFormProps
でも同様のアプローチに従うことができます。
プロップ掘削を回避するのに役立ちます
一部のフォームは大きく、いくつかのコンポーネントに分割されている場合があります。 消費者のドリル小道具をツリーの下に置く代わりに、コンテキストを提供する必要があります。 このようにして、下のツリーのどこにいても、カスタムフックから返すすべてのものにアクセスできます。
まず、ReactのcreateContext
メソッドを使用してValidationContextを作成しましょう。
export const ValidationContext = React.createContext({});
次に、代わりにコンテキスト内のuseValidation
フックからのすべての値を提供するコンポーネントValidationProvider
を作成しましょう。
export const ValidationProvider = props => { const context = useValidation(props.config); return ( {props.children} ); };
export const ValidationProvider = props => { const context = useValidation(props.config); return ( {props.children} ); };
export const ValidationProvider = props => { const context = useValidation(props.config); return ( {props.children} ); };
これで、 useValidation
を直接呼び出す代わりに、フォームをValidationProvider
コンポーネントでラップし、 useContext
フックを使用して検証プロップ( getFormProps
、 errors
など)にアクセスできるようになります。 次のように使用します。
Import React, { useContext } from 'react'; import { ValidationContext } from './useValidation'; function UsernameForm(props) { const { getFieldProps, errors } = useContext(ValidationContext); return ( <> <input {...getFieldProps('username')} /> {errors.username && {errors.username}></span>} </> ); }
このようにして、両方の長所を活用できます。 あなたはそれらの単純なシナリオのための単純なフックを手に入れ、そしてあなたはそれらの複雑な部品に必要な柔軟性を手に入れます。
ドキュメントが重要
自分で書いたのではないライブラリを使用しているときはいつでも、すばらしいドキュメントが大好きです。 しかし、何に焦点を当て、どこに文書化する必要がありますか?
最初のステップは、最も基本的な使用例をすぐに利用できる、わかりやすいREADMEをまとめることです。 Andrew Healeyは、優れたREADMEの書き方について素晴らしい記事を書きました。これを読むことを強くお勧めします。
人々を動かすための優れたREADMEを作成したら、ドキュメントのWebサイトを作成することをお勧めします。 ここでは、より詳細なAPIドキュメント、一般的なユースケースのレシピ、古き良きFAQを掲載できます。
ドキュメントのウェブサイトを生成するための優れたツールがあります。 私のお気に入りはFacebookのdocusaurus
です(謙虚な自慢: create-react-app
Webサイトを作成するときに使用しました)が、そこにはいくつかの良い選択肢があります。
この記事では、優れたドキュメントを作成する方法については説明しません。 そこにはいくつかの良い記事があります—「ドキュメントを書く」と呼ばれるコミュニティでさえ。 彼らはあなたが素晴らしいドキュメントを書き始める方法への素晴らしいガイドを書きました。
概要
この一連の記事を通じて、かなりまともな検証ライブラリを作成しました。 非常にシンプルなAPI、必要なときに柔軟に対応できる柔軟性、優れた開発者エクスペリエンス、そして多くの非常に優れた機能を備えています。
実装方法を段階的に説明してきましたが、独自のライブラリを作成する方法と、人々が使いたくなるようなライブラリを作成する方法について、より深く理解していただければ幸いです。
コメント欄でご意見をお聞かせください。また、行き詰まったり、理解しづらい部分があったら教えてください。 フィードバックが少しずつ入ってくるので、記事を更新するために最善を尽くします。
この記事を締めくくるには—これが最終バージョンです:
- CodeSandboxデモを見る
読んでくれてありがとう!