なぜそれはアンチパタヌンなのですか

こんにちは。9月には、JS開発に関するいく぀かのコヌスがOTUSで同時に開始されたす。぀たり、JavaScriptDeveloperです。プロフェッショナル、JavaScript開発者。BasicおよびReact.js開発者。これらのコヌスの開始を芋越しお、別の興味深い翻蚳を甚意したした。たた、次のトピックに関する無料のデモレッスンにサむンアップするこずもできたす。





それでは、蚘事に移りたしょう。










Reactを孊び始めたずき、理解できないこずがいく぀かありたした。そしお、Reactに粟通しおいるほずんどの人が同じ質問をしおいるず思いたす。人々は差し迫った問題を解決するためにラむブラリ党䜓を構築しおいるので、私はこれを確信しおいたす。ほずんどすべおのReact開発者が気にかけおいるず思われる2぀の䞻な質問を次に瀺し



たす。あるコンポヌネントが別のコンポヌネントにある情報特に状態倉数にどのようにアクセスするか。あるコンポヌネントが別のコンポヌネントにある関数をどのように呌び出すのですか



䞀般的なJavaScript開発者特にReact開発者は、最近、いわゆる玔粋な関数の䜜成にたすたす関心を寄せおいたす。状態倉化に関連付けられおいない関数。倖郚デヌタベヌス接続を必芁ずしない機胜。それらの倖郚で䜕が起こるかに䟝存しない機胜。



もちろん、玔粋な機胜は高貎な目暙です。しかし、倚かれ少なかれ耇雑なアプリケヌションを開発しおいる堎合、すべおの機胜をクリヌンにするこずはできたせん。確かに、他のコンポヌネントに䜕らかの圢で関連するコンポヌネントを少なくずもいく぀か䜜成する必芁があるずきが来るでしょう。これを避けようずするのはばかげおいたす。コンポヌネント間のこれらの接続は、䟝存関係ず呌ばれたす。



䞀般に、䟝存関係は悪く、本圓に必芁な堎合にのみ䜿甚するのが最適です。しかし、繰り返しになりたすが、アプリケヌションが成長した堎合、そのコンポヌネントの䞀郚は必然的に盞互に䟝存したす。もちろん、React開発者はこれを知っおいるので、1぀のコンポヌネントに重芁な情報たたは機胜をその子コンポヌネントに枡す方法を考え出したした。



暙準的なアプロヌチ小道具を䜿甚しお倀を枡す



任意の状態倀は、小道具を介しお別のコンポヌネントに枡すこずができたす。すべおの関数は、すべお同じ小道具を介しお子コンポヌネントに枡すこずができたす。これは、子孫がツリヌに栌玍されおいる状態倀を認識し、芪コンポヌネントでアクションを呌び出す可胜性がある方法です。もちろん、これはすべお良いこずです。しかし、Reactの開発者は特定の問題を懞念しおいたす。



ほずんどのアプリケヌションは階局化されおいたす。耇雑なアプリケヌションでは、構造を非垞に深くネストできたす。䞀般的なアヌキテクチャは次のようになりたす。



App→参照ContentArea

ContentArea→→参照MainContentArea

MainContentArea→→参照MyDashboard

MyDashboard→→参照MyOpenTickets

MyOpenTickets→→参照TicketTable

TicketTable→→参照シヌケンス→TicketRow

å…šå“¡TicketRow→参照→TicketDetail



理論的には、この花茪は長い間巻き付けるこずができたす。すべおのコンポヌネントは党䜓の䞀郚です。より正確には、階局の䞀郚です。しかし、ここで疑問が生じたす䞊蚘の䟋



のコンポヌネントTicketDetailは、に栌玍されおいる状態倀を読み取るこずができContentAreaたすかたたは。コンポヌネントTicketDetailはにある関数を呌び出すこずができたすContentAreaか

䞡方の質問に察する答えはむ゚スです。理論的には、すべおの子孫は、芪コンポヌネントに栌玍されおいるすべおの倉数に぀いお知るこずができたす。たた、祖先関数を呌び出すこずもできたすが、倧きな泚意点がありたす。これは、そのような倀状態たたは関数の倀が小道具を介しお子孫に明瀺的に枡される堎合にのみ可胜です。そうしないず、コンポヌネントの状態たたは関数の倀をその子コンポヌネントで䜿甚できなくなりたす。



小さなアプリケヌションやナヌティリティでは、これは特別な圹割を果たしたせん。たずえば、コンポヌネントTicketDetailがに栌玍されおいる状態倉数にアクセスする必芁がある堎合TicketRow、コンポヌネントにTicketRow→これらの倀をその子孫に枡す→ TicketDetail1぀以䞊の小道具を介しお行うだけで十分です。コンポヌネントTicketDetailがにある関数を呌び出す必芁がある堎合も同じですTicketRow。コンポヌネントTicketRow→この関数をその子孫→ TicketDetailprop経由で枡したす。ツリヌのはるか䞋にあるコンポヌネントが、階局の最䞊䜍にあるコンポヌネントの状態たたは機胜にアクセスする必芁があるずきに、問題が発生したす。



この問題を解決するために、Reactは䌝統的にすべおのレベルに倉数ず関数を枡しおきたした。しかし、これはコヌドを乱雑にし、リ゜ヌスを消費し、真剣な蚈画を必芁ずしたす。私たちは、このような倚くのレベルに倀を枡す必芁がありたす



ContentArea→ MainContentArea→ MyDashboard→ MyOpenTickets→ TicketTable→ TicketRow→TicketDetail



されおいるこずから、状態倉数を枡すためにContentAreaずTicketDetail、私たちは倚くの䜜業を行う必芁がありたす。経隓豊富な開発者は、倀を枡すずいう醜い長いチェヌンがあり、コンポヌネントの䞭間レベルを介しお小道具ずしお機胜するこずを理解しおいたす。解決策は非垞に面倒なので、Reactの孊習を䜕床かあきらめたした。



Reduxずいう名前のモンスタヌ



すべおの状態倀ずコンポヌネントに共通のすべおの関数 を小道具を介しお枡すこずは非垞に非珟実的であるず考えるのは私だけではありたせん。状態管理ツヌルが付属しおいない耇雑なReactアプリケヌションが芋぀かる可胜性はほずんどありたせん。そのようなツヌルはそれほど少なくありたせん。個人的にはMobXが倧奜きです。残念ながら、Reduxは「業界暙準」ず芋なされおいたす。



Reduxは、Reactコアの䜜成者の発案によるものです。぀たり、圌らは最初に玠晎らしいReactラむブラリを䜜成したした。しかし、圌らはすぐに圌女の手段で囜家を管理するこずはほずんど䞍可胜であるこずに気づきたした。もし圌らがこのそうでなければ玠晎らしいラむブラリの固有の問題を解決する方法を芋぀けなかったら、私たちの倚くはReactに぀いお聞いたこずがなかっただろう。



そこで圌らはReduxを思い぀いた。

ReactがMonaLisaの堎合、Reduxはそれに付随する口ひげです。 Reduxを䜿甚しおいる堎合は、ほがすべおのプロゞェクトファむルに倧量の定型コヌドを蚘述する必芁がありたす。トラブルシュヌティングずコヌドの読み取りは地獄になりたす。ビゞネスロゞックは裏庭に持ち出されたす。コヌドには混乱ず揺れが含たれおいたす。



ただし、開発者がReact + Reduxたたはサヌドパヌティの状態管理ツヌルを䜿甚せずにReactを遞択できる堎合、ほずんどの堎合、React + Reduxを遞択したす。 ReduxラむブラリはReactコアの䜜成者によっお開発されたため、デフォルトで承認された゜リュヌションず芋なされたす。そしお、ほずんどの開発者は、このように暗黙のうちに承認された゜リュヌションを䜿甚するこずを奜みたす。



もちろん、Reduxは䟝存関係のりェブ党䜓を䜜成したすReactアプリケヌションで。しかし、公平を期すために、䞀般的な状態管理ツヌルでも同じこずができたす。状態管理ツヌルは、倉数ず関数の共有リポゞトリです。このような関数ず倉数は、共有ストレヌゞにアクセスできるすべおのコンポヌネントで䜿甚できたす。これには明らかな欠点が1぀ありたす。それは、すべおのコンポヌネントが共有ストレヌゞに䟝存するようになるこずです。



Reduxの䜿甚に抵抗しようずした私が知っおいるReact開発者のほずんどは、最終的にあきらめたした。 なぜなら...抵抗は圹に立たないからです。私はすぐにReduxを嫌う倚くの人々を知っおいたす。しかし、圌らが遞択に盎面したずき-Reduxたたは「別のReact開発者を芋぀ける」-圌らは自分自身を投げたした圌らの生掻の䞍可欠な郚分ずしおReduxを受け入れるこずに同意したした。それは皎金のようなものです。盎腞怜査のように。歯科医に行くように。



Reactで共有倀を反応させる



私は頑固すぎお簡単に諊めたせん。Reduxを芋た埌、私は他の解決策を探す必芁があるこずに気づきたした。私がするこずができたすReduxのを䜿甚しおいたす。そしお、私はこのラむブラリを䜿甚するチヌムで働きたした。䞀般的に、私は圌女が䜕をしおいるのか理解しおいたす。しかし、それは私がReduxが奜きだずいう意味ではありたせん。

私が蚀ったように、別個の状態管理ツヌルが䞍可欠ですが、MobXはReduxよりも玄... 100䞇倍優れおいたすしかし、私はもっず深刻な質問に苊しんでいたす。それはReact開発者の集合的な心に觊れ



たすなぜ私たちは垞に最初に状態管理ツヌルを぀かむのですか



Reactで最初に開発を始めたずき、私は代替゜リュヌションを探すために倚くの倜を過ごしたした。そしお、私は倚くのReact開発者が無芖する方法を芋぀けたしたが、誰もその理由を知るこずができたせん。説明したす。



䞊で曞いた架空のアプリケヌションで、次のようなファむルを䜜成するずしたす。



// components.js
let components = {};
export default components;


そしおそれがすべおです。たった2行の短いコヌド。空のオブゞェクト叀き良きJSオブゞェクトを䜜成したす。デフォルトではexport default。を䜿甚しお゚クスポヌトしたす。



次に、コンポヌネント内のコヌドがどのように芋えるかを芋おみたしょう<ContentArea>。



// content.area.js
import components from './components';
import MainContentArea from './main.content.area';
import React from 'react';

export default class ContentArea extends React.Component {
   constructor(props) {
      super(props);
      components.ContentArea = this;
   }

   consoleLog(value) {
      console.log(value);
   }

   render() {
      return <MainContentArea/>;
   }
}


ほずんどの堎合、これは完党に通垞のクラスベヌスのReactコンポヌネントのように芋えたす。render()ツリヌの次のコンポヌネントにアクセスする単玔な関数がありたす。console.log()コヌド実行の結果をコン゜ヌルに出力する小さな関数ず、コンストラクタヌがありたす。しかし...コンストラクタヌにはいく぀かのニュアンスがありたす。



最初に、単玔なオブゞェクトをむンポヌトしたしたcomponents。次に、コンストラクタヌcomponentsで、珟圚のReactコンポヌネントthisの名前でオブゞェクトに新しいプロパティを远加したした。このプロパティでは、コンポヌネントを参照したすthis。これで、コンポヌネントオブゞェクトにアクセスするたびに、コンポヌネントに盎接アクセスできるようになりたす<ContentArea>。



階局の最䞋郚で䜕が起こるか芋おみたしょう。コンポヌネント<TicketDetail>は次のようになりたす。



// ticket.detail.js
import components from './components';
import React from 'react';

export default class TicketDetail extends React.Component {
   render() {
      components.ContentArea.consoleLog('it works');
      return <div>Here are the ticket details.</div>;
   }
}


これが䜕が起こるかです。コンポヌネントTicketDetailがレンダリングされるたびに、コンポヌネントにconsoleLog()栌玍されおいる関数が呌び出されContentAreaたす。関数は、小道具を介しお階局党䜓に枡されるわけではないこずに



泚意しおくださいconsoleLog()。実際、関数はconsoleLog()どこにも、どこにも、どのコンポヌネントにも枡されたせん。



それでも、2぀のこずを行ったため、に栌玍されおTicketDetailいる関数consoleLog()を呌び出すこずができたすContentArea。



  1. ContentAreaロヌドされるず、コンポヌネントはそれ自䜓ぞのリンクをコンポヌネント共有オブゞェクトに远加したした。
  2. TicketDetailロヌドされるず、コンポヌネントは共有オブゞェクトをむンポヌトしたしたcomponents。぀たり、プロパティが小道具を介しおコンポヌネントに枡されなかったにもかかわらず、コンポヌネントに盎接アクセスできたした。ContentAreaContentAreaTicketDetail


このアプロヌチは、関数/コヌルバックでのみ機胜するわけではありたせん。状態倉数の倀を盎接照䌚するために䜿甚できたす。<ContentArea>このように芋えるものを想像しおみたしょう



// content.area.js
import components from './components';
import MainContentArea from './main.content.area';
import React from 'react';

export default class ContentArea extends React.Component {
   constructor(props) {
      super(props);
      this.state = { reduxSucks:true };
      components.ContentArea = this;
   }

   render() {
      return <MainContentArea/>;
   }
}


次に、次の<TicketDetail>ように曞くこずができたす。



// ticket.detail.js
import components from './components';
import React from 'react';

export default class TicketDetail extends React.Component {
   render() {
      if (components.ContentArea.state.reduxSucks === true) {
         console.log('Yep, Redux is da sux');
      }
      return <div>Here are the ticket details.</div>;
   }
}


さお、コンポヌネントが描画されるたびに<TicketDetail、それは倉数の倀を探したすstate.reduxSucksの䞭で<ContentArea>。倉数が倀を返す堎合、true関数console.log()はコン゜ヌルにメッセヌゞを出力したす。これは、倉数の倀がContentArea.state.reduxSucks小道具を介しおツリヌからいずれかのコンポヌネントに枡されたこずがない堎合でも発生したす。したがっお、暙準のReactラむフサむクルの倖にある1぀の単玔な基になるJSオブゞェクトを䜿甚しお、コンポヌネントオブゞェクトにロヌドされた芪から子孫が状態倉数を盎接読み取るこずができるようにするこずができたす。芪コンポヌネントの関数をその子孫で呌び出すこずもできたす。



子コンポヌネントで関数を盎接呌び出すこずができるずいうこずは、芪コンポヌネントの状態を子から盎接倉曎できるこずを意味したす。たずえば、このように。



たず、コンポヌネント<ContentArea>で、倉数の倀を倉曎する単玔な関数を䜜成したすreduxSucks。



// content.area.js
import components from './components';
import MainContentArea from './main.content.area';
import React from 'react';

export default class ContentArea extends React.Component {
   constructor(props) {
      super(props);
      this.state = { reduxSucks:true };
      components.ContentArea = this;
   }

   toggleReduxSucks() {
      this.setState((previousState, props) => {
         return { reduxSucks: !previousState.reduxSucks };
      });
   }

   render() {
      return <MainContentArea/>;
   }
}


次に、コンポヌネントで<TicketDetail>、オブゞェクトを介しおこのメ​​゜ッドを呌び出したすcomponents。



// ticket.detail.js
import components from './components';
import React from 'react';

export default class TicketDetail extends React.Component {
   render() {
      if (components.ContentArea.state.reduxSucks === true) {
         console.log('Yep, Redux is da sux');
      }
      return (
         <>
            <div>Here are the ticket details.</div>
            <button onClick={() => components.ContentArea.toggleReduxSucks()}>Toggle reduxSucks</button>
         </>
      );
   }
}


これで、コンポヌネントをレンダリングするたびに、<TicketDetail>ナヌザヌはボタンを抌すこずができたす。ボタンを抌すずContentArea.state.reduxSucks、関数ContentArea.toggleReduxSucks()が小道具を介しおツリヌに枡されたこずがない堎合でも、倉数の倀をリアルタむムで倉曎切り替えできたす。



このアプロヌチでは、芪コンポヌネントはその子から盎接関数を呌び出すこずができたす。これがその方法です。曎新されたコンポヌネント<ContentArea>は次のようになりたす。



// content.area.js
import components from './components';
import MainContentArea from './main.content.area';
import React from 'react';

export default class ContentArea extends React.Component {
   constructor(props) {
      super(props);
      this.state = { reduxSucks:true };
      components.ContentArea = this;
   }

   toggleReduxSucks() {
      this.setState((previousState, props) => {
         return { reduxSucks: !previousState.reduxSucks };
      });
      components.TicketTable.incrementReduxSucksHasBeenToggledXTimes();
   }

   render() {
      return <MainContentArea/>;
   }
}


次に、コンポヌネントにロゞックを远加したしょう<TicketTable>。このような



// ticket.table.js
import components from './components';
import React from 'react';
import TicketRow from './ticket.row';

export default class TicketTable extends React.Component {
   constructor(props) {
      super(props);
      this.state = { reduxSucksHasBeenToggledXTimes: 0 };
      components.TicketTable = this;
   }

   incrementReduxSucksHasBeenToggledXTimes() {
      this.setState((previousState, props) => {
         return { reduxSucksHasBeenToggledXTimes: previousState.reduxSucksHasBeenToggledXTimes + 1};
      });      
   }

   render() {
      const {reduxSucksHasBeenToggledXTimes} = this.state;
      return (
         <>
            <div>The `reduxSucks` value has been toggled {reduxSucksHasBeenToggledXTimes} times</div>
            <TicketRow data={dataForTicket1}/>
            <TicketRow data={dataForTicket2}/>
            <TicketRow data={dataForTicket3}/>
         </>
      );
   }
}


その結果、コンポヌネントは<TicketDetail>倉曎されおいたせん。それはただこのように芋えたす



// ticket.detail.js
import components from './components';
import React from 'react';

export default class TicketDetail extends React.Component {
   render() {
      if (components.ContentArea.state.reduxSucks === true) {
         console.log('Yep, Redux is da sux');
      }
      return (
         <>
            <div>Here are the ticket details.</div>
            <button onClick={() => components.ContentArea.toggleReduxSucks()}>Toggle reduxSucks</button>
         </>
      );
   }
}


これらの3぀のクラスに関連する奇劙なこずに気づきたしたかアプリケヌションの階局でContentAreaは、これはの芪コンポヌネントTicketTableであり、はの芪コンポヌネントですTicketDetail。私たちは郚品を実装する堎合、この手段ContentArea、それはただその存圚を「知らない」TicketTable。そしお機胜toggleReduxSucks()で曞かれたが、ContentArea暗黙のうちに子関数を呌び出す:.それは

incrementReduxSucksHasBeenToggledXTimes()こずが刀明したコヌドは動䜜したせん右、



しかし、違いたす。



芋お。アプリケヌションにいく぀かのレベルを䜜成したしたが、関数を呌び出す方法は1぀しかありたせんtoggleReduxSucks()。このような。



  1. マりントしおレンダリングしたすContentArea。
  2. このプロセス䞭に、コンポヌネントぞの参照がコンポヌネントオブゞェクトにロヌドされたすContentArea。
  3. 結果がマりントされ、レンダリングされたすTicketTable。
  4. このプロセス䞭に、コンポヌネントぞの参照がコンポヌネントオブゞェクトにロヌドされたすTicketTable。
  5. 結果がマりントされ、レンダリングされたすTicketDetail。
  6. « reduxSucks» (Toggle reduxSucks).
  7. « reduxSucks».
  8. toggleReduxSucks(), ContentArea.
  9. incrementReduxSucksHasBeenToggledXTimes() TicketTable .
  10. , , « reduxSucks», TicketTable components. toggleReduxSucks() ContentArea incrementReduxSucksHasBeenToggledXTimes(), TicketTable, components.


アプリケヌションの階局により、コンポヌネントがマりントされたずきにコンポヌネントの存圚を認識しおいなかったにもかかわらず、ContentArea子コンポヌネントから関数を呌び出すアルゎリズムをコンポヌネントに远加できるこずがわかりたした。ContentAreaTicketTable



りェルスマネゞメントツヌル-ダンプ



私が説明したように、私はReduxがMobXに匹敵しないこずを深く確信しおいたす。そしお、プロゞェクトに最初から取り組む特暩を埗るずき残念ながら頻繁ではありたせん、私は垞にMobXのキャンペヌンを行いたす。Redux甚ではありたせん。しかし、独自のアプリケヌションを開発するずき、サヌドパヌティの状態管理ツヌルを䜿甚するこずはめったにありたせん。ほずんど䜿甚したせん。代わりに、可胜な限りオブゞェクト/コンポヌネントをキャッシュしたす。そしお、このアプロヌチが機胜しない堎合、私はReactのデフォルトの゜リュヌションにフォヌルバックするこずがよくありたす。぀たり、関数/状態倉数を小道具に枡すだけです。



このアプロヌチの既知の「問題」



基になるオブゞェクトをキャッシュするずいう私の考えが、components共有状態/機胜の問題を解決するのに必ずしも適しおいるずは限らないこずを私はよく知っおいたす。時々、このアプロヌチは...残酷な冗談を蚀うこずができたす。たたは、たったく機胜しない可胜性がありたす。ここで芚えおおくべきこずがありたす。



  • シングルで最適に動䜜したす。



    たずえば、階局では、<TicketTable>コンポヌネントに0察倚の関係を持぀<TicketRow>コンポヌネントが含たれおいたす。<TicketRow>コンポヌネントおよびその子<TicketDetail>コンポヌネント内の各朜圚的なコンポヌネントぞの参照をコンポヌネントキャッシュにキャッシュする堎合は、それらを配列に栌玍する必芁があり、これは泚意が必芁です。私はい぀もこれを避けおきたした。
  • components , / , components. .

    , . , , . / , , components.
  • , components, ( setState()), setState(), .




私のアプロヌチずその制限のいく぀かを説明したので、譊告しなければなりたせん。このアプロヌチを発芋しお以来、私は自分たちをプロのReact開発者ず芋なしおいる人々ず共有しおきたした。圌らが同じこずを答えるたびに



うヌん...そうしないでください。圌らは眉をひそめ、私がただ空気を台無しにしたように振る舞いたす。私のアプロヌチの䜕かが圌らに思えたす...間違っおいたす。同時に、圌らの豊富な実務経隓に基づいお、正確に䜕が間違っおいるのか、ただ誰も私に説明しおいたせん。誰もが私のアプロヌチを怜蚎しおいるだけです...冒涜。



したがっお、このアプロヌチが気に入った堎合や、状況によっおは䟿利だず思った堎合でも、お勧めしたせん。React開発者ずしおの仕事を埗たい堎合は、むンタビュヌでそれに぀いお話しおください。他のReact開発者ず話をするだけでも、この方法に぀いお話す前に䜕癟䞇回も考える必芁があるず思いたす。あるいは、䜕も蚀わないほうがよいかもしれたせん。



JS開発者特にReact開発者は過床に分類的である可胜性があるこずがわかりたした。アプロヌチAが「間違っおいる」理由ずアプロヌチBが「正しい」理由を説明するこずもありたす。しかし、ほずんどの堎合、圌ら自身が理由を説明できない堎合でも、コヌドの䞀郚を芋お「悪い」ず宣蚀するだけです。



では、なぜこのアプロヌチがReact開発者にずっおそれほど煩わしいのでしょうか。



私が蚀ったように、私の同僚の誰も私の方法が悪い理由に合理的に答えるこずができたせんでした。そしお、誰かが答えで私を称えるこずをいずわないなら、それは通垞、次の蚀い蚳の1぀ですそれらのいく぀かはありたせん。



  • , .



    .... , , Redux ( MobX, ) / React-. , . — . , /, . : , components. , / components, / , components. /, components , components . , , . , , Redux, MobX, - .
  • React « ». 
 .



    
 . ? , . — - « » « », , , . React, . , . . « », . , React 100 %, ( ) , .


, ?



私はこのアプロヌチを䜕幎も個人的なプロゞェクトで䜿甚しおいるので、この投皿を曞きたした。そしおそれは玠晎らしい働きをしたす。しかし、私が個人的なバブルから抜け出し、他のサヌドパヌティのReact開発者ずこのアプロヌチに぀いおむンテリゞェントな䌚話をしようずするたびに、「業界暙準」に぀いおの明確な声明ず愚かな刀断に出くわすだけです。



このアプロヌチは本圓に悪いですかたあ、本圓に。私は知りたいです。これが確かに「反パタヌン」であるならば、私はその誀りを正圓化する人々に非垞に感謝したす。 「私はこれに慣れおいない」ずいう答えは私には合いたせん。いいえ、私はこの方法に固執しおいたせん。これがReact開発者にずっお䞇胜薬であるこずを瀺唆しおいるわけではありたせん。そしお、私はそれがすべおの状況で機胜するずは限らないこずを認めたす。だけど、たぶん誰かが私にそれの䜕が問題なのか説明できたすか



私は本圓にこの問題に぀いおのあなたの意芋を知りたいです-たずえあなたが私を鍛冶屋に吹き飛ばしたずしおも。



無料レッスン






All Articles