私は、ロジックをサービス/ファクトリに抽出し、それらをコントローラで使用できる角度のある世界から来ています。
Reactアプリケーションで同じことを実現する方法を理解しようとしています。
ユーザーのパスワード入力を検証するコンポーネントがあるとしましょう(それは強さです)。ロジックはかなり複雑なので、コンポーネント自体に記述したくありません。
このロジックはどこに書くべきですか?フラックスを使用している場合、店舗で?または、より良いオプションはありますか?
最初の答えは、現在のコンテナとプレゼンターのパラダイムを反映していません。
パスワードの検証など、何かを行う必要がある場合は、それを実行する関数がある可能性があります。その関数を小道具として再利用可能なビューに渡すことになります。
したがって、それを行う正しい方法は、その関数をプロパティとして持つValidatorContainerを記述し、フォームをその中にラップして、適切な小道具を子に渡すことです。ビューに関しては、バリデータコンテナがビューをラップし、ビューがコンテナロジックを消費します。
検証はすべてコンテナーのプロパティで実行できますが、サードパーティのバリデーターまたは任意の単純な検証サービスを使用している場合は、サービスをコンテナーコンポーネントのプロパティとして使用し、コンテナーのメソッドで使用できます。私はこれを安らかなコンポーネントに対して行いましたが、非常にうまく機能します。
もう少し構成が必要な場合は、プロバイダー/コンシューマーモデルを使用できます。プロバイダーは、最上位のアプリケーションオブジェクト(マウントするオブジェクト)の近くとその下をラップし、プロバイダーの一部または最上位レイヤーで構成されたプロパティをコンテキストAPIに提供する高レベルのコンポーネントです。次に、コンテキストを消費するようにコンテナ要素を設定します。
親子コンテキストの関係は、互いに近くにある必要はありません。子が何らかの方法で子孫になっている必要があります。ReduxストアとReactRouterはこのように機能します。私はそれを使用して、残りのコンテナーにルートの残りのコンテキストを提供しました(独自のコンテキストを提供しない場合)。
(注:コンテキストAPIはドキュメントで実験的なものとしてマークされていますが、それを使用しているものを考えると、これ以上ではないと思います)。
//An example of a Provider component, takes a preconfigured restful.js
//object and makes it available anywhere in the application
export default class RestfulProvider extends React.Component {
constructor(props){
super(props);
if(!("restful" in props)){
throw Error("Restful service must be provided");
}
}
getChildContext(){
return {
api: this.props.restful
};
}
render() {
return this.props.children;
}
}
RestfulProvider.childContextTypes = {
api: React.PropTypes.object
};
私が試したことはありませんが、使用されていることがわかっている別の方法は、ミドルウェアをReduxと組み合わせて使用することです。サービスオブジェクトは、アプリケーションの外部、または少なくともreduxストアよりも高い位置で定義します。ストアの作成中に、サービスをミドルウェアに注入すると、ミドルウェアがサービスに影響を与えるすべてのアクションを処理します。
このようにして、restful.jsオブジェクトをミドルウェアに挿入し、コンテナーメソッドを独立したアクションに置き換えることができます。フォームビューレイヤーにアクションを提供するためにコンテナーコンポーネントが必要ですが、connect()とmapDispatchToPropsでカバーできます。
新しいv4react-router-reduxは、このメソッドを使用して、たとえば履歴の状態に影響を与えます。
//Example middleware from react-router-redux
//History is our service here and actions change it.
import { CALL_HISTORY_METHOD } from './actions'
/**
* This middleware captures CALL_HISTORY_METHOD actions to redirect to the
* provided history object. This will prevent these actions from reaching your
* reducer or any middleware that comes after this one.
*/
export default function routerMiddleware(history) {
return () => next => action => {
if (action.type !== CALL_HISTORY_METHOD) {
return next(action)
}
const { payload: { method, args } } = action
history[method](...args)
}
}
Angularサービスが、コンテキストに依存しない一連のメソッドを提供する単なるオブジェクトであることに気付くと、問題は非常に単純になります。それをより複雑に見せているのは、AngularDIメカニズムだけです。DIは、インスタンスの作成と保守を処理するので便利ですが、実際には必要ありません。
axiosという名前の人気のあるAJAXライブラリ(おそらく聞いたことがあるでしょう)を考えてみましょう。
import axios from "axios";
axios.post(...);
サービスとして動作しませんか?これは、特定のロジックを担当する一連のメソッドを提供し、メインコードから独立しています。
あなたの例のケースは、入力を検証するための分離されたメソッドのセットを作成することに関するものでした(たとえば、パスワードの強度をチェックする)。私にとって明らかにアンチパターンであるコンポーネント内にこれらのメソッドを配置することを提案する人もいました。検証にXHRバックエンド呼び出しの作成と処理、または複雑な計算が含まれる場合はどうなりますか?このロジックをマウスクリックハンドラーやその他のUI固有のものと組み合わせますか?ナンセンス。コンテナ/ HOCアプローチでも同じです。値に数字が含まれているかどうかをチェックするメソッドを追加するためだけにコンポーネントをラップしますか?いい加減にして。
「ValidationService.js」という名前の新しいファイルを作成し、次のように整理します。
const ValidationService = {
firstValidationMethod: function(value) {
//inspect the value
},
secondValidationMethod: function(value) {
//inspect the value
}
};
export default ValidationService;
次に、コンポーネントで:
import ValidationService from "./services/ValidationService.js";
...
//inside the component
yourInputChangeHandler(event) {
if(!ValidationService.firstValidationMethod(event.target.value) {
//show a validation warning
return false;
}
//proceed
}
このサービスはどこからでもご利用いただけます。検証ルールが変更された場合は、ValidationService.jsファイルのみに焦点を当てる必要があります。
他のサービスに依存する、より複雑なサービスが必要になる場合があります。この場合、サービスファイルは静的オブジェクトではなくクラスコンストラクターを返す可能性があるため、コンポーネントで自分でオブジェクトのインスタンスを作成できます。また、アプリケーション全体で使用されているサービスオブジェクトのインスタンスが常に1つだけであることを確認するために、単純なシングルトンを実装することを検討することもできます。
複数のコンポーネント間で共有するフォーマットロジックが必要でした。Angular開発者としても、当然サービスに傾倒していました。
別のファイルに入れてロジックを共有しました
function format(input) {
//convert input to output
return output;
}
module.exports = {
format: format
};
モジュールとしてインポートしました
import formatter from '../services/formatter.service';
//then in component
render() {
return formatter.format(this.props.data);
}
Reactの目的は、論理的に結合する必要があるものをより適切に結合することであることに注意してください。複雑な「パスワードの検証」方法を設計している場合、どこで結合する必要がありますか?
ユーザーが新しいパスワードを入力する必要があるたびに、それを使用する必要があります。これは、登録画面、「パスワードを忘れた」画面、管理者の「別のユーザーのパスワードをリセット」画面などに表示されます。
ただし、いずれの場合も、常に何らかのテキスト入力フィールドに関連付けられます。だからそれはそれが結合されるべき場所です。
入力フィールドと関連する検証ロジックのみで構成される非常に小さなReactコンポーネントを作成します。パスワード入力が必要な可能性のあるすべてのフォームにそのコンポーネントを入力します。
これは基本的にロジックのサービス/ファクトリを持つのと同じ結果ですが、入力に直接結合しています。したがって、関数は永続的に結合されているため、検証入力を探す場所を関数に指示する必要はありません。
私もAngular.jsエリアから来ましたが、React.jsのサービスとファクトリーはもっとシンプルです。
プレーンな関数またはクラス、コールバックスタイル、および私のようなイベントMobxを使用できます:)
// Here we have Service class > dont forget that in JS class is Function
class HttpService {
constructor() {
this.data = "Hello data from HttpService";
this.getData = this.getData.bind(this);
}
getData() {
return this.data;
}
}
// Making Instance of class > it's object now
const http = new HttpService();
// Here is React Class extended By React
class ReactApp extends React.Component {
state = {
data: ""
};
componentDidMount() {
const data = http.getData();
this.setState({
data: data
});
}
render() {
return <div>{this.state.data}</div>;
}
}
ReactDOM.render(<ReactApp />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
</body>
</html>
ここに簡単な例があります:
同じ状況:複数のAngularプロジェクトを実行してReactに移行したが、DIを介してサービスを提供する簡単な方法がないことは、欠けている部分のように思われる(サービスの詳細は別として)。
コンテキストとES7デコレータを使用して、近づけることができます。
https://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/
これらの人はそれをさらに一歩進めたようです/別の方向に:
http://blog.wolksoftware.com/dependency-injection-in-react-powered-inversifyjs
まだ穀物に逆らって働いているような気がします。主要なReactプロジェクトに着手してから、6か月後にこの回答を再検討します。
編集:6か月後、Reactの経験を積んで戻ってきました。ロジックの性質を考慮してください。
再利用のためにHOCに手を伸ばす人もいますが、私にとっては、上記はほとんどすべてのユースケースをカバーしています。また、アヒルを使用して状態管理をスケーリングし、懸念事項を分離して状態UI中心にすることを検討してください。
私もAngularの出身で、Reactを試しています。現時点では、推奨される(?)方法の1つは、高次コンポーネントを使用しているようです。
高階コンポーネント(HOC)は、コンポーネントロジックを再利用するためのReactの高度な手法です。HOC自体はReactAPIの一部ではありません。それらは、Reactの構成的性質から生まれるパターンです。
あなたが持っていると言うinput
とtextarea
と同様に同じ検証ロジックを適用します:
const Input = (props) => (
<input type="text"
style={props.style}
onChange={props.onChange} />
)
const TextArea = (props) => (
<textarea rows="3"
style={props.style}
onChange={props.onChange} >
</textarea>
)
次に、ラップされたコンポーネントの検証とスタイル設定を行うHOCを記述します。
function withValidator(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props)
this.validateAndStyle = this.validateAndStyle.bind(this)
this.state = {
style: {}
}
}
validateAndStyle(e) {
const value = e.target.value
const valid = value && value.length > 3 // shared logic here
const style = valid ? {} : { border: '2px solid red' }
console.log(value, valid)
this.setState({
style: style
})
}
render() {
return <WrappedComponent
onChange={this.validateAndStyle}
style={this.state.style}
{...this.props} />
}
}
}
これらのHOCは、同じ検証動作を共有します。
const InputWithValidator = withValidator(Input)
const TextAreaWithValidator = withValidator(TextArea)
render((
<div>
<InputWithValidator />
<TextAreaWithValidator />
</div>
), document.getElementById('root'));
簡単なデモを作成しました。
編集:別のデモでは、小道具を使用して関数の配列を渡し、次HOC
のような複数の検証関数で構成されるロジックを共有できるようにします。
<InputWithValidator validators={[validator1,validator2]} />
<TextAreaWithValidator validators={[validator1,validator2]} />
Edit2:React 16.8+は、ロジックを共有するためのもう1つの優れた方法であるフックという新機能を提供します。
const Input = (props) => {
const inputValidation = useInputValidation()
return (
<input type="text"
{...inputValidation} />
)
}
function useInputValidation() {
const [value, setValue] = useState('')
const [style, setStyle] = useState({})
function handleChange(e) {
const value = e.target.value
setValue(value)
const valid = value && value.length > 3 // shared logic here
const style = valid ? {} : { border: '2px solid red' }
console.log(value, valid)
setStyle(style)
}
return {
value,
style,
onChange: handleChange
}
}
https://stackblitz.com/edit/react-shared-validation-logic-using-hook?file=index.js
Angular2 +でも、サービスはAngularに限定されません。
サービスは単なるヘルパー関数のコレクションです...
そして、それらを作成してアプリケーション全体で再利用する方法はたくさんあります...
1)以下のように、jsファイルからエクスポートされるすべての分離された関数にすることができます。
export const firstFunction = () => {
return "firstFunction";
}
export const secondFunction = () => {
return "secondFunction";
}
//etc
2)関数のコレクションで次のようなファクトリメソッドを使用することもできます... ES6では、関数コンストラクタではなくクラスにすることができます。
class myService {
constructor() {
this._data = null;
}
setMyService(data) {
this._data = data;
}
getMyService() {
return this._data;
}
}
この場合、新しいキーでインスタンスを作成する必要があります...
const myServiceInstance = new myService();
また、この場合、各インスタンスには独自のライフがあるため、共有する場合は注意してください。その場合は、必要なインスタンスのみをエクスポートする必要があります...
3)関数とユーティリティが共有されない場合は、Reactコンポーネントに配置することもできます。この場合は、reactコンポーネントの関数と同じです。
class Greeting extends React.Component {
getName() {
return "Alireza Dezfoolian";
}
render() {
return <h1>Hello, {this.getName()}</h1>;
}
}
4)物事を処理する別の方法は、Reduxを使用することです。これは一時的なストアなので、Reactアプリケーションにある場合は、使用する多くのゲッターセッター関数で役立ちます...それは大きなストアのようなものですそれはあなたの状態を追跡し、それをあなたのコンポーネント間で共有することができるので、私たちがサービスで使用するゲッターセッターのものの多くの苦痛を取り除くことができます...
DRYコードを実行し、コードを再利用可能で読みやすくするために使用する必要があるものを繰り返さないことは常に良いことですが、項目4で説明したように、ReactアプリでAngularの方法に従おうとしないでください。Reduxを使用すると、サービスとあなたはアイテム1のようないくつかの再利用可能なヘルパー機能のためにそれらを使用することを制限します...
私はあなたと同じブーツを履いています。あなたが言及した場合、私は入力検証UIコンポーネントをReactコンポーネントとして実装します。
私は、検証ロジック自体の実装を結合してはならないことに同意します。したがって、私はそれを別のJSモジュールに入れます。
つまり、結合してはならないロジックの場合は、別のファイルでJSモジュール/クラスを使用し、require / importを使用してコンポーネントを「サービス」から分離します。
これにより、2つの依存性注入と単体テストを個別に行うことができます。
または、クラス継承「http」をReactコンポーネントに挿入できます
小道具オブジェクトを介して。
更新:
ReactDOM.render(<ReactApp data={app} />, document.getElementById('root'));
次のようにReactコンポーネントReactAppを編集するだけです。
class ReactApp extends React.Component {
state = {
data: ''
}
render(){
return (
<div>
{this.props.data.getData()}
</div>
)
}
}
私が遭遇した再利用可能なロジックで最もよく使用されるパターンは、フックを作成するか、utilsファイルを作成することです。それはあなたが何を達成したいかによります。
hooks/useForm.js
フォームデータを検証する場合と同様に、useForm.jsという名前のカスタムフックを作成してフォームデータを提供すると、次の2つの内容を含むオブジェクトが返されます。
Object: {
value,
error,
}
あなたが進歩するにつれて、あなたは間違いなくそれからより多くのものを返すことができます。
utils/URL.js
別の例としては、URLから情報を抽出し、関数を含むutilsファイルを作成して、必要に応じてインポートする場合があります。
export function getURLParam(p) {
...
}
特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。
ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。
ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。
画像クレジット:Richard Mackney / Flickrトラベリングライトは必需品だけを運ぶことを意味するかもしれませんが、デバイスを補充する方法がない外出先では、接続を維持するのが難しくなる可能性があります。それはあなたがすべての生き物の快適さやクールなガジェットを捨てる必要があるという意味ではありません、ただあなたがいくつかのより小さなものを手に入れる必要があるということです、そしておそらくあなた自身をジュースに保つためにいくつかの、例えば非正統的な充電装置を使うでしょう。
ニューヨーク州スプリンググレンにある放棄されたホモワックロッジのボーリング場。キャッツキル南部のこの地域は、ニューヨーク市からのユダヤ人の行楽客に人気があることから、かつてはボルシチベルトとして知られていました。
ブルックリンスレートブルックリンスレートのマグカップとコースターの賞賛をすでに歌っており、それらの食器製品も同様に堅実です。ブルックリンスレートは、さまざまなサイズとテクスチャのスレートの完全な採石場を販売しています。一部のオプションは赤でも利用できます。上で見ることができるように、彼らは同様にカスタマイズをします。
画像:Juan Gaertner / Shutterstock私たちの体の内部は、私たちの細胞とは何の関係もない何十億もの微生物が住んでいる本物の生態系です。これがまだ少し気になることではなかったかのように、これらの微生物の99%が研究されたことがないことがわかりました。
Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday
シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。
オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。
Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。
遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。
2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。
計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。