- 投稿日:2020-12-23T23:55:24+09:00
数値入力で input[type="number"]を使ったら、ユーザから問い合わせが増えてしまった話
この記事は SmartHR Advent Calendar 2020 23 日目の記事です。
こんばんは! @diescake です。
今年は、React で「そこそこの規模で、そこそこ機能のフォームアプリケーション」を設計・実装する機会がありました。
技術選定でformik+yupを選んだので、その選定理由と結果を共有しよう!……そんなふうに考えていた時期が私にもありました。
驚くほど筆が進まず、いつの間にやら当日どころか既に夜になってしまったので tips 的な話に逃げる運びとなりました。ご了承ください。
というわけで、数値入力フォームに何気なく
input[type="number"]を利用したら、ユーザから問い合わせが増えてしまった話です!input[type="number"] とは?
今更説明するまでもないくらい基本的な要素ですが HTML において
inputはユーザの入力を受け付ける要素で、type属性に"number"を指定すると、数値入力用のフォームを実現できます。
- MDN - <input type="number" />
<input type="number" />PC Chrome 87 の場合だと、こんな感じの UI でレンダリングされます。
大体のブラウザでは、フォーカスするとクリッカブルな
▲▼アイコンが表示されて、クリックすることでインクリメント・デクリメントできます。加えて、通常のテキスト入力フォームである
input[type="text"]とは異なりinput[type="number"]の場合は、数値として valid な値しか入力を受け付けません。そのため、数値の入力を期待しているフォームでは
input[type="number"]を使うと安心です。
なんといっても、入力された value をそのままparseInt()なりNumber()に食わせれば数値として取り出せるのですから…。そう考えて
input[type="number"]を利用しました。どんな問い合わせが発生したのか?
さて、ウェブアプリケーションをリリースしてユーザが触れるようになると、数値の入力ができない という問い合わせが発生しました。
キーボードを叩いても、数値入力フォームは無反応。テキスト入力フォームは入力できるのに、と……。問い合わせを受け、プログラムを見直してもフォームに
disabledな状態は定義していない……。
何より、テキスト入力は可能なのにどうして数値入力だけできないんや…… ?うーん、何かしらのユーザ環境依存だったり、ブラウザ依存? そうか!
IE! やはりIEお前なのか!(ぐるぐる目)
などなど、色々と調査をしたものの……。原因はなんだったのか?
わかってしまえばとても単純で、ユーザの IME で
全角入力のまま数字キーを叩いてたことが原因でした。
全角数字は valid な数値として扱われないため、キーを叩いてもフォームは反応しません。さらに悪いことに、この数値入力フォームでは 空入力を許容していませんでした。
つまり初期値の0を削除できないということですね。なんでこんな仕様にしていたか言い訳をすると、フォームに対応する数値の型を
numberに絞っていたことが原因です。type = { なんらかの数値A: number なんらかの数値B: number ... }こうすると、
なんらかの数値は non nullable として扱えるので、何かと楽なのはお分かりいただけます……よね?……というわけで、開発都合で、
BackSpaceキー押しても無反応だし、(全角入力の状態で)数字キーを押しても無反応という、ユーザにとってとても分かりづらい状況が生まれていました。どう対処したのか?
結局の所、数値入力フォームは
input[type="text"]として自由に入力して貰って、onBlurのタイミングでサニタイズ、フォーマットすることにしました。
全角数値やーといった入力も、半角文字列に置き換え valid な数値に変換しています。合わせて、フォームに対応する型定義も、
numberからnumber | nullや、素直にstringに変更する必要がありますが、
ここは、入力中の文字列は、ローカルスコープのuseStateで保持するようにして、onBlurのタイミングでフォームに対応する値を更新することでnumberのまま凌ぎました。いっそここまでくると、非制御コンポーネントにするという手段もありかもしれませんねー。
また、方針は変えずに半角数値のみを許容するにしても、
全角入力のままキーを叩いたら、tooltip で警告を出すような仕組みでも良いかもしれません。例えば、OS のログイン画面だと、CapsLock のまま password を入力しようとすると tooltip で警告がでますよね。アレみたいなイメージです。
おわりに
話をスムーズにするため、そこはかとなく事実を湾曲しております!?
実際には
input[type="number"]ではなくて、同等の動作をする自作コンポーネントに起因した話だったり、私は直接ユーザからの問い合わせを受ける立場になく、サポートチーム経由の話だったりします。私は常々 SPA を書くエンジニアとして、使いやすさを大事にしていると思い込んでいたんですが、
いざ蓋をあけてユーザに触ってもらうと、多々反省もありました。子供の頃読んだ
地獄先生ぬ〜べ〜の不幸の手紙の話をよく覚えているのですが、1 人 1 人のヘイトが小さくとも数十万人のヘイトが集まると巨大な怨念になりますよね。
いつしかこの怨念が生霊となって復習を果たしに来ることがないよう、フィードバックを受け止めてカイゼンを重ねていこうと思います!では、明日は SmartHR の誇る催眠術師 @ouji-miyahara です!
参考文献
- 地獄先生ぬーべー 4 巻 (ジャンプコミックス)
- 投稿日:2020-12-23T23:45:31+09:00
TheGraph(Subgraph)を使って独自のERC20トークンの保有者一覧をフロント(React)に表示する
概要
Ethereumのエコシステムにはいくつか欠かせないツールが存在しますが、その中でもThe Graphの使い方をご紹介いたします。
The Graphは、Ethereumの情報にアクセスするためのAPIを、GraphQLを使って誰もが簡単に構築できるサービスです。Who are the owners of the CryptoKitties born between January and February of 2018?
https://thegraph.com/docs/introduction
例えば、2018年の1月~2月の間にCryptoKittiesのオーナーだった人は誰か?という情報をEthereumのメインネットから取得しサービス上に表示してあげたいとします。
この場合、サービス事業者はEthereumのノードを立てて、ログを参照しながら独自のDBに情報を保存しつつ、APIを作り、フロント側に渡すみたいなことをしないといけません。ここで、The Graphを使うことで、indexしておきたいデータをcontractのEventを軸に設定でき、簡単にGraphQLを使ったAPIを構築できます。
そこで今回は、ERC20のトークンをデプロイし、そのEvent情報をThe Graphを用いて取得し、Reactで構築されたフロント側に表示したいと思います。
環境やツール
- MacOS Catalina
- Node v14.5.0
- graph-cli
- Remix
- OpenZeppelin
- Github
- CreateEthApp
ERC20のデプロイ
今回ERC20は OpenZeppelin を使って開発します。
OpenZeppelinは厳格にテストされたスマートコントラクトのライブラリを提供してくれるサービスです。その中でも今回は、
ERC20.solを使っていきます。
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.solERC20のコードはこちら
pragma solidity ^0.6.0; import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; contract AdventCalendarToken is ERC20 { string private _name = "AdventCalendarToken"; string private _symbol = "ACT"; uint8 private _decimals = 18; address account = msg.sender; uint value = 10000000000000000000000; constructor() ERC20( _name, _symbol) public { _mint(account, value); } }トークンの名前を
AdventCalendarToken
初期発行量を10000000000000000000000
初期発行分の受け取りアドレスはコントラクトをデプロイしたアドレスです。コントラクト開発やトークンのデプロイなどをまだやったことがないという方はこちらから具体的なトークン発行のフローを確認してください。
https://note.com/toshitoissho/n/n93eadf07fd47今回ERC20は
Rinkeby環境にデプロイしています。また、デプロイしたERC20トークンのコントラクトアドレスがこちらです。
0x45882688e3Ef40Aa727F4EEB1cba11D1b29E228DEtherscanを参照:
https://rinkeby.etherscan.io/address/0x45882688e3Ef40Aa727F4EEB1cba11D1b29E228DERC20には2種類のEventが設定されています。
https://eips.ethereum.org/EIPS/eip-20#eventsevent Transfer(address indexed _from, address indexed _to, uint256 _value)event Approval(address indexed _owner, address indexed _spender, uint256 _value)Subgraphでは、このEvent情報を軸にデータを構築していきます。
ちなみにTransferはトークンの送金を行った際に発火するEventで、Approvalは第三者アドレスに対してトークンのTransfer権限を与えた時(approveした時)に発火するEventです。今回はTransferイベントの情報を表示したいと思いますので、事前に自分のウォレットから複数回他のウォレットアドレスに対してTransfer(送金)しておきましょう。
Subgraphの構築
コントラクトの準備ができたら、Subgraphを作っていきます。
アカウント登録
まずはThe Graph上でアカウントを登録します。
アカウント登録にはGithubアカウントが必要です。
https://thegraph.com/アカウント登録できたら、次にgraph-cliをインストールします。
Subgraphのセットアップ
# NPM $ npm install -g @graphprotocol/graph-cli # Yarn $ yarn global add @graphprotocol/graph-cli次に作業用のディレクトリを作ります。
$ mkdir subgraph $ cd subgraphその後、Subgraphのプロジェクトを作成します。
$ graph init以下のような問いが出てきますので、設定していきましょう。
✔ Subgraph name · toshiakitakase/advent-calendar-token ✔ Directory to create the subgraph in · advent-calendar-token ✔ Ethereum network · rinkeby ✔ Contract address · 0x45882688e3Ef40Aa727F4EEB1cba11D1b29E228D ✖ Failed to fetch ABI from Etherscan: ABI not found, try loading it from a local file ✔ ABI file (path) · ./abi.json ✔ Contract Name · AdventCalendarToken
Subgraph nameは<GITHUB_USERNAME>/<SUBGRAPH_NAME>で、ご自身の情報を設定していきます。
Ethereumのnetworkはコントラクトをデプロイした環境と同一のRinkebyを使います。
Contract addressは先ほどERC20をデプロイしたコントラクトを使います。
ABIはローカルでコントラクトを開発してる場合はそのパスを指定します。
今回はRemixでコントラクトを開発したので、Remixからabiを取得し、subgraphディレクトリ内に保存し(abi.json)、そのパスを指定しました。
Contract nameは実装したコントラクトの名前を指定します。これでプロジェクトができました。 lsすると
advent-calendar-tokenができていることが確認できます。$ ls abi.json advent-calendar-tokenSubgraphの実装
ここからSubgraphの実装を進めていきます。
dataSources内にstartBlock追加します。subgraph.yamlspecVersion: 0.0.2 schema: file: ./schema.graphql dataSources: - kind: ethereum/contract name: AdventCalendarToken network: rinkeby source: address: "0x45882688e3Ef40Aa727F4EEB1cba11D1b29E228D" abi: AdventCalendarToken startBlock: 7751082 #ここを追加 mapping: kind: ethereum/events apiVersion: 0.0.4 language: wasm/assemblyscript entities: - Approval - Transfer abis: - name: AdventCalendarToken file: ./abis/AdventCalendarToken.json eventHandlers: - event: Approval(indexed address,indexed address,uint256) handler: handleApproval - event: Transfer(indexed address,indexed address,uint256) handler: handleTransfer file: ./src/mapping.tsこれはどのBlockから同期を開始するかを指定するものです。
未指定の場合、同期に時間がかかってしまうので、コントラクトをデプロイしたBlockから同期するようにしましょう。次にSchemaを設定していきます。
今回は、トークンの所有者一覧を表示したいので、ウォレットのアドレス・トークンのアドレス・ウォレットの残高を含んだEntityを実装します。
初期状態で記載されているものは削除し、下記に置き換えます。schema.graphqltype AccountTokenBalance @entity { id: ID! #wallet address token: String! #token address balance: BigInt! #現在のトークン残高 }その後下記のコマンドを実行することで、
/generatedにschemaが生成されます。$ graph codegenそしてここからEventに応じたロジックを実装していきます。
mapping.tsimport { BigInt } from "@graphprotocol/graph-ts"; import { Transfer } from "../generated/AdventCalendarToken/AdventCalendarToken"; import { AccountTokenBalance } from "../generated/schema"; // Transferのイベントが発火された時に実行されるfunction export function handleTransfer(event: Transfer): void { let tokenId = event.address.toHex(); let toAddress = event.params.to.toHex(); let toAccount = AccountTokenBalance.load(toAddress); if (toAccount == null) { toAccount = new AccountTokenBalance(toAddress); toAccount.balance = BigInt.fromI32(0); } toAccount.balance = toAccount.balance.plus(event.params.value); toAccount.token = tokenId; toAccount.save(); let fromAddress = event.params.from.toHex(); if (fromAddress == "0x0000000000000000000000000000000000000000") { return; } let fromAccount = AccountTokenBalance.load(fromAddress); if (fromAccount == null) { fromAccount = new AccountTokenBalance(fromAddress); fromAccount.balance = BigInt.fromI32(0); } fromAccount.balance = fromAccount.balance.minus(event.params.value); fromAccount.token = tokenId; fromAccount.save(); }ここでは、
TransferのEventが発火するたびに、トークンのfromアドレスとtoアドレスの残高を書き換えています。
トークンが最初にmintされた時から全てのEventをチェックして計算してくれるので、現在の残高を取得できます。
これを利用して、トークンの保有者一覧を生成していきます。ここまででSubgraphの実装は完了です。
Subgraphのデプロイ
次にアカウントの認証を実行します。
$ graph auth https://api.thegraph.com/deploy/ <access-token>
access-tokenは, https://thegraph.com/explorer/dashboard/ でログインするとdashboardから確認できます。次に
advent-calendar-tokenに入り、プロジェクトをデプロイします。$ cd advent-calendar-token $ yarn deployしかし、ここでおそらくエラーになります。
✖ Failed to deploy to Graph node https://api.thegraph.com/deploy/: subgraph name not found: toshiakitakase/advent-calendar-token You may need to created it at https://thegraph.com/explorer/dashboard.SubgraphのデプロイにはThe GraphのDashboardでもプロジェクトの作成が必要です。
https://thegraph.com/explorer/dashboard/ にアクセスし、プロジェクトの設定を行います。Dashboard上から新規にSubgraphを作成します。
SUBGRAPH NAMEは事前に作ったSubgraph nameを
advent-calendar-tokenとしているため、Advent Calendar Tokenとします。
(この名前をみてデプロイしているので、正しい名前をつけましょう)一般公開したくないSubgraphの場合、
HIDEをONにします。その後、再度Deployを実行します。
$ cd advent-calendar-token $ yarn deploy以下のように表示されれば成功です。
Build completed: Qmdhv61aXCnsyMUmdAikDxWRXvn81M54RfEgYmnafHFNpu Deployed to https://thegraph.com/explorer/subgraph/toshiakitakase/advent-calendar-token Subgraph endpoints: Queries (HTTP): https://api.thegraph.com/subgraphs/name/toshiakitakase/advent-calendar-token Subscriptions (WS): wss://api.thegraph.com/subgraphs/name/toshiakitakase/advent-calendar-token※注意点※
なお、SubgraphはEthereumのブロックと同期し、Event情報を取得しているため、デプロイしてすぐに使えるわけではありません。
下の画像の通り、Sync(同期)までには一定の時間がかかりますのでお気をつけください。
同期が完了したらSubgraphの作成成功です。
Reactを使ったフロント構築
ここからはフロントエンドの実装を進めていきます。
フロントの実装にはCreate React Appのように簡単にEthereumのDappを作れるCreate Eth Appを使っていきます。Create Eth App
https://github.com/paulrberg/create-eth-appまずは
token_trackerという名でプロジェクトを作ります。$ yarn create eth-app token_tracker $ cd token_tracker $ yarn react-app:starthttp://localhost:3000/ にアクセスしい以下が表示されればOKです。
Create Eth Appにはweb3Modal( https://github.com/Web3Modal/web3modal )が組み込まれており、
Connect WalletでMetamaskに簡単接続されるなど、DApp開発で便利な実装が最初から含まれています。今回はSubgraphの呼び出しのみを行うので、それらに関する実装を進めていきましょう。
まずはsubgraph.js内でクエリを書いていきます。src/graphql/subgraph.jsimport { gql } from "apollo-boost"; const GET_TRANSFERS = gql` { accountTokenBalances(orderBy: balance) { id token balance } } `; export default GET_TRANSFERS;次に、
/src/index.jsにSubgraphのAPIのURLをセットします。src/index.jsconst client = new ApolloClient({ uri: "https://api.thegraph.com/subgraphs/name/toshiakitakase/advent-calendar-token", });これで設定は完了です。
あとはApp.js内で呼び出していきましょう。初期に記載されている内容は今回ほとんど利用しないため、一旦削除し、下記のように実装します。
src/App.jsimport React, { useEffect, useState } from "react"; import { useQuery } from "@apollo/react-hooks"; import GET_TRANSFERS from "./graphql/subgraph"; function App() { const { loading, error, data } = useQuery(GET_TRANSFERS); const [tokenHolders, setTokenHolders] = useState([]); useEffect(() => { if (!loading && !error && data) { setTokenHolders(data.accountTokenBalances); } }, [loading, error, data]); return ( <div> {tokenHolders.map((tokenHolder) => ( <div key={tokenHolder.id} style={{ margin: "20px" }}> <div>アドレス: {tokenHolder.id}</div> <div>残高: {tokenHolder.balance}</div> </div> ))} </div> ); } export default App;これで完成!
画面をみると4つのアドレスがトークンを保有していることがわかります。
このようなトークン保有者一覧や、いつの時点でいくつ持っていたのか?といった情報を管理するにはノードの運用やDBの構築などで開発者にとってはコストになっていきます。
これを簡単な実装のみでSubgraphにデータのIndexを任せて、フロントから簡単にデータを取得できるのは開発者にとってはとっても楽ですね。これからDAppを作る予定の方は是非TheGraphを試してみてください。
- 投稿日:2020-12-23T22:07:14+09:00
【React】Qiita 週間LGTM数ランキング【自動更新】
他のタグ
AWSAndroidDockerGitGoiOSJavaJavaScriptLinuxNode.jsPHPPythonRailsReactRubySwiftTypeScriptVimVue.js集計について
- 期間: 2020-12-17 ~ 2020-12-24
- 条件: ストック数が 2 以上の記事
LGTM 数ランキング
1 位: フロントエンドエンジニアがSPAを開発する上で理解しておきたいこと
JavaScriptSPAVue.jsReact新人プログラマ応援130 LGTM
@shohta-noda さん ( 2020-12-22 10:16 に投稿 )2 位: ぴえん?かどうか判定するクソアプリをつくった
88 LGTM
@kokushin さん ( 2020-12-18 17:29 に投稿 )3 位: Next.jsの自分なりのベストプラクティスを6点紹介する
16 LGTM
@redshoga さん ( 2020-12-18 22:40 に投稿 )4 位: React開発者必見!!先日発表されたReact Server Componentsとは?
JavaScriptAdventCalendarTypeScriptReactssr15 LGTM
@Rui1009 さん ( 2020-12-23 00:51 に投稿 )5 位: AWSとReactで始めるShopifyアプリ開発イベントレポート
15 LGTM
@t-kurasawa さん ( 2020-12-17 18:49 に投稿 )6 位: React初案件獲得までの流れ(学習・案件探し・面接・契約まで)&Udemy活用術
TypeScriptReactreactnativereduxnext.js13 LGTM
@newt0 さん ( 2020-12-19 17:47 に投稿 )7 位: 【SSRとは】シンプルなHTML・CSRと比べながらSSRを理解する
12 LGTM
@mtoyopet さん ( 2020-12-22 11:24 に投稿 )8 位: JavaScriptエキスパートになるための36の概念
JavaScriptNode.jsプログラミング翻訳React10 LGTM
@baby-degu さん ( 2020-12-21 09:54 に投稿 )9 位: Next.jsを使うべき5つの理由 + 実装Tips
JavaScriptNode.jsnginxReactnext.js10 LGTM
@Yuki_Oshima さん ( 2020-12-19 00:04 に投稿 )10 位: React開発効率を3倍にするVS Code拡張機能&環境設定
ReactreactnativeVSCodereduxnext.js9 LGTM
@newt0 さん ( 2020-12-19 00:44 に投稿 )11 位: styled-componentsと一緒に使うと便利なstyled-systemの紹介
Reactcss-in-jsstyled-componentsstyled-system7 LGTM
@kourin1996 さん ( 2020-12-17 17:57 に投稿 )12 位: React Server Componentについてまとめてみた
6 LGTM
@Yuki-Kurita さん ( 2020-12-23 11:40 に投稿 )13 位: Next.jsでサウナで整いたいお気持ち度合い記録アプリを3時間で作る
JavaScriptNode.jsReactnext.jsVercel6 LGTM
@yutaroshimamura さん ( 2020-12-19 01:35 に投稿 )14 位: バリデーションにreact-hook-formが便利だった
ValidationReactnext.jsreact-hook-form5 LGTM
@282Haniwa さん ( 2020-12-24 17:32 に投稿 )15 位: Next.js+GrapqhQLでShopifyアプリを開発する
4 LGTM
@hal_256 さん ( 2020-12-21 20:21 に投稿 )16 位: React Hooksについてと、便利な独自フックのご紹介
4 LGTM
@sai1023 さん ( 2020-12-18 23:31 に投稿 )17 位: 色々な角度から見た GraphQL
初心者向けswaggerReactGraphQLNestJS4 LGTM
@a-tsu さん ( 2020-12-17 13:07 に投稿 )18 位: React高階コンポーネント(HOC)について
3 LGTM
@nouka さん ( 2020-12-22 19:09 に投稿 )19 位: React Hooks でキーワードによる絞り込み検索を実装する
JavaScriptTypeScriptReactreact-hooks3 LGTM
@takf-jp さん ( 2020-12-20 23:55 に投稿 )20 位: React Naivigation v5 画面遷移時のアニメーション
3 LGTM
@impl_chamuji さん ( 2020-12-17 19:36 に投稿 )21 位: TheGraph(Subgraph)を使って独自のERC20トークンの保有者一覧をフロント(React)に表示する
EthereumReactsolidityGraphQLTheGraph2 LGTM
@toshiaki_takase さん ( 2020-12-23 23:45 に投稿 )22 位: React Recoil事始め
1 LGTM
@taka4sato さん ( 2020-12-22 03:38 に投稿 )
- 投稿日:2020-12-23T22:07:14+09:00
【React】Qiita 週間 LGTM 数ランキング【自動更新】
他のタグ
AWSAndroidDockerGitGoiOSJavaJavaScriptLinuxNode.jsPHPPythonRailsReactRubySwiftTypeScriptVimVue.js初心者集計について
- 期間: 2020-12-20 ~ 2020-12-27
- 条件: ストック数が 2 以上の記事
LGTM 数ランキング
1 位: フロントエンドエンジニアがSPAを開発する上で理解しておきたいこと
JavaScriptSPAVue.jsReact新人プログラマ応援253 LGTM
@shohta-noda さん ( 2020-12-22 10:16 に投稿 )2 位: React開発者必見!!先日発表されたReact Server Componentsとは?
JavaScriptAdventCalendarTypeScriptReactssr18 LGTM
@Rui1009 さん ( 2020-12-23 00:51 に投稿 )3 位: 【SSRとは】シンプルなHTML・CSRと比べながらSSRを理解する
12 LGTM
@mtoyopet さん ( 2020-12-22 11:24 に投稿 )4 位: JavaScriptエキスパートになるための36の概念
JavaScriptNode.jsプログラミング翻訳React11 LGTM
@baby-degu さん ( 2020-12-21 09:54 に投稿 )5 位: バリデーションにreact-hook-formが便利だった
ValidationReactnext.jsreact-hook-form9 LGTM
@282Haniwa さん ( 2020-12-24 17:32 に投稿 )6 位: React Server Componentについてまとめてみた
8 LGTM
@Yuki-Kurita さん ( 2020-12-23 11:40 に投稿 )7 位: Rails(APIモード)× React × TypeScriptで作るシンプルなTodoアプリ
RailsTypeScriptReactTodoアプリ4 LGTM
@kazama1209 さん ( 2020-12-24 19:41 に投稿 )8 位: Next.js+GrapqhQLでShopifyアプリを開発する
4 LGTM
@hal_256 さん ( 2020-12-21 20:21 に投稿 )9 位: TheGraph(Subgraph)を使って独自のERC20トークンの保有者一覧をフロント(React)に表示する
EthereumReactsolidityGraphQLTheGraph3 LGTM
@toshiaki_takase さん ( 2020-12-23 23:45 に投稿 )10 位: React高階コンポーネント(HOC)について
3 LGTM
@nouka さん ( 2020-12-22 19:09 に投稿 )11 位: React Hooks でキーワードによる絞り込み検索を実装する
JavaScriptTypeScriptReactreact-hooks3 LGTM
@takf-jp さん ( 2020-12-20 23:55 に投稿 )12 位: Reactで開発してみた 〜色々気づいたことプチまとめ〜
2 LGTM
@nakamo-03 さん ( 2020-12-25 20:04 に投稿 )13 位: React Recoil事始め
1 LGTM
@taka4sato さん ( 2020-12-22 03:38 に投稿 )
- 投稿日:2020-12-23T17:59:56+09:00
Reactのプロジェクトにexlint-config-airbnbを導入する
きっかけ
普通のeslintを入れるよりも、exlint-config-airbnbを入れた方が、コードの規約が厳しいので、可読性が上がるとのこと。
https://speakerdeck.com/watanabeyu/du-miyasuikodofalseshu-kifang-falsesusume?slide=11
前提
create-react-appで作成したプロジェクトに導入します。
導入
必要なパッケージをインストールする。
$ npm i -D eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react
.eslintrcをプロジェクトディレクトリの直下に作成し、以下のように記述する。{ "extends": "airbnb" }以上で導入は完了。
propsを型チェックする
以下のようなコンポーネントがあった時、
import React from 'react'; const Title = (props) => ( <h1>{props.title}</h1> ); export default Title;propsの型をチェックしていないので、ESlintに怒られてしまう。
まずは、以下のようにpropsを受け取るようにする。
const {title} = props;受け取ったら、
prop-tyoesで型をチェックする。パッケージをインストール
$ npm i -S prop-types以下のような形で、型をチェックする。
import React from 'react'; import PropTypes from 'prop-types'; const Title = (props) => { // 追加 const { title } = props; return ( <h1>{title}</h1> ); }; // 追加 Title.propTypes = { title: PropTypes.string.isRequired, }; export default Title;参考
https://qiita.com/sugx2/items/ed58605e4e12519876fd
https://ja.reactjs.org/docs/typechecking-with-proptypes.html
https://speakerdeck.com/watanabeyu/du-miyasuikodofalseshu-kifang-falsesusume
- 投稿日:2020-12-23T17:19:03+09:00
[初学者向け]Django・Reactおすすめ書籍まとめ
こんにちは、文系からITのお仕事について1年目のくまきちです。
初心者の方向けに、何を学べるかを書きながら、特によかった本やウェブサイトを紹介していきます。勉強を始めたばかりの大学時代は、周りにITに造詣の深い友人や先輩がいなかったため本やウェブサイトに頼りきりでした。
知識がなかったので、やりたいことと関係のない本もたくさん買ってしまいましたね・・・。
皆さんにはお金を無駄にして欲しくないので(笑)、ちょこっと概要も書きつつおすすめを紹介していきます。勉強し始める方の一助になりますように!Django
Djangoを始める
掌田津耶乃 「Python Django3超入門」
一番初めにやりました。Djangoでどうやってインストールするの?から教えてくれる。
知識ゼロからウェブサイト作成まで。
Django Brothers https://djangobrothers.com
ブログ、メモアプリを作れる無料チュートリアル。
構造を理解しやすくて勉強になるので個人的にはおすすめ。少し応用「会員機能」「デプロイ」
Django Brothers「Django チュートリアルで学ぶ Web 開発入門 」
会員機能、カスタムユーザーモデルを用いた会員機能について学べる。ECショップの作り方も。
大高 隆「動かして学ぶ! Python Django開発入門」
会員機能、Bootstrapの導入方法、Django + AWSでのデプロイについて勉強できる。SES導入なども。
(AmazonLinux2AMIになり、Let’s Encryptの部分のコードはそのままでは実行できなくなってしまった。)番外編
Django Narito Blog https://blog.narito.ninja/
わからないことはまずこちらのブログで検索(笑)。
DRF + Vue.jsの情報もたくさん。
森本哲也,中野正輝,池 徹, 岡田幸大「できる 仕事がはかどるPython自動処理 全部入り。」
Python ファイル書き込み、読み出しなどの編集などの自動処理。使えると便利!React
Reactを始める
たかぴろ(@takapiro_99) 「React ハンズオン 2020 夏」
知識ゼロから外部APIの利用とSPAの構築、firebaseでデプロイするところまで学べる。
環境構築についてもとても参考になるので、他の言語を学び始める人もぜひ参考に!
React Tutorial https://react-tutorial.app/
Reactの基礎について手を動かしながら学べる。後半は有料だけど、無料枠が充実している。おすすめ!DRF + ReactでSPAを作る
CodingEntrepreneurs 「Create a Twitter-like App with Python Django JavaScript and React. Full TUTORIAL」
YouTubeのチュートリアル動画。DRF + Reactでツイッターみたいなサービスの構築。
(途中のdjango埋め込み認証機能はそのままではうまくいかなかった。できた方いたら教えて欲しいです。)番外編
JavaScript | MDN https://developer.mozilla.org/ja/docs/Web/JavaScript
JavaScriptについてわかりやすく説明してくれる。
React以前の問題だ・・・と感じた時に。
まだまだちゃんと理解している部分は少ないですが、できることを増やしつつ理解していけたらなと思っています!
もっと知識をつけて本を間違って買わないようにしたいですね・・・
- 投稿日:2020-12-23T14:09:59+09:00
Next.jsで__dirnameを使いたい
__dirnameで欲しい値が返ってきてない
nextjs内に使用しているAPIでpg-promiseを利用しているのですが、pg-promiseでsqlファイルを読み込む際に上手くパスが設定できませんでした。
process.cwd()を使うだけでした
ちゃんとドキュメンテーションに書いてありました。
参考:Reading files: Use process.cwd()
ちなみにpg-promiseのsql読み込みは以下のようになりました。
import {QueryFile} from 'pg-promise'; import {join} from 'path'; const sql = (file) => { //process.cwd()が元々は__dirname const fullPath = join(process.cwd(), file); return new QueryFile(fullPath, {minify: true}); };どうやらsqlファイルを何度も読み込んでるみたいなので、対策を別途調べてみます。
WARNING: Creating a duplicate QueryFile object for the same file
- 投稿日:2020-12-23T13:50:56+09:00
Reducerにswitchを使いたくない
Reducerをオブジェクト(Object)で作りたい
ReactのフックAPIのリファレンスを見ると、以下のようにswitchを使ってReducerを定義している。
しかし、私はswitchがあまり好きではないので、オブジェクトで書くようにしている。example.jsconst initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } }引用: フックAPIリファレンス(https://ja.reactjs.org/docs/hooks-reference.html#usereducer)
createReducer関数をつくる
以下のようにReducerを書けるようにcreateReducerという関数を作った。
{ [アクションタイプ1]: (state, action) => ({変更後のステート}), [アクションタイプ2]: (state, action) => ({変更後のステート}), ... }createReducer.jsexport const createReducer = (initialState={}, handlers={}) => (state = initialState, action) => handlers[action.type] && handlers[action.type]({...state}, action) || {...state}説明は割愛するが、これを利用することで、前述のフックAPIリファレンスのサンプルコードを以下のように書くことができる。
example.jsconst initialState = {count: 0}; const reducer = createReducer(initialState, { ['increment']: state => ({...state, count: state.count + 1}), ['decrement']: state => ({...state, count: state.count - 1}) }), initialState)また、 payloadがある場合には、以下のように書くことができる。
example.jsconst reducer = createReducer(initialState, { [UPDATE_SUGGESTION_ITEMS]: (state, {payload}) => ({...state, suggestionItems: payload}), [FETCH_POSTS]: (state, {payload}) => ({...state, tmpResult: payload}), [FETCH_POST_DETAIL]: (state, {payload}) => ({...state, post: payload}), }), initialState)
- 投稿日:2020-12-23T11:40:45+09:00
React Server Componentについてまとめてみた
先日、ReactがReact Server Componentsを予告しました。まだ開発中とのことなので使えるのは先になりそうですが、非常に面白い内容となっているのでこちらで共有したいと思います。
What is React Server Component
React Server Componentとは、サーバーサイドのみで実行され、バンドルサイズへの影響を与えません。React Server Componentはクライアントでダウンロードされないため、アプリの起動時間などの向上などが期待できます。
また、Server Componentは、データベースなどサーバサイドのデータソースにアクセスすることができたり、レンダリングするClient Componentを動的に選択することができます。
ここで簡単な例に触れてみましょう。React Server Componentを使った例
以下はノートのタイトルと本文をサーバーサイドから取得し表示し、ノートのエディタをClient Reactコンポーネントとしてレンダリングする例です。
まず、Server Componentを実装するには拡張子を
.server.jsまたは.server.jsx、.server.tsxなどにします。import db from 'db.server'; // (A1) import NoteEditor from 'NoteEditor.client'; function Note(props) { const {id, isEditing} = props; // (B) const note = db.posts.get(id); return ( <div> <h1>{note.title}</h1> <section>{note.body}</section> {/* (A2) */} {isEditing ? <NoteEditor note={note} /> : null } </div> ); }この例からいくつか重要なことがわかります。
- A1 :Client Reactコンポーネントをインポートする時は
.client.jsまたは.client.jsx,.client.tsxの拡張子をつける。- B : データベースなどのサーバーサイドのデータソースに直接アクセスしている
- A2: Client Componentは
isEditingがtrueの時のみクライアントにロードされる。つまり必要に応じて動的にロードされることになる続いて動的にロードされる
NoteEditorコンポーネント(Client Component)について見ていきましょう。export default function NoteEditor(props) { const note = props.note; const [title, setTitle] = useState(note.title); const [body, setBody] = useState(note.body); const updateTitle = event => { setTitle(event.target.value); }; const updateBody = event => { setTitle(event.target.value); }; const submit = () => { // ...save note... }; return ( <form action="..." method="..." onSubmit={submit}> <input name="title" onChange={updateTitle} value={title} /> <textarea name="body" onChange={updateBody}>{body}</textarea> </form> ); }この例で重要な点は、Server Componentの結果をクライアントにレンダリングするときに、以前にレンダリングされた可能性のあるClient Componentの状態を保持することです。具体的には、Reactは、サーバーから渡された新しいPropsを既存のクライアントコンポーネントにマージし、これらのコンポーネントの状態(およびDOM)を維持して、focus、stateや進行中のアニメーションなどを保持します。
React Server Componentのメリット
他にもたくさんのメリットがあるので今確認できるものを紹介していきます。
Zero-Bundle-Size Components
冒頭に述べたように、React Server Componentはサーバーサイドのみで実行されるので、バンドルサイズが0となります。そのため開発時にコードサイズによるパフォーマンス低下を回避することができます。
// NoteWithMarkDown.js // 従来のReactコンポーネントなのでそのままのバンドルサイズとなる import marked from 'marked'; // 35.9K (11.2K gzipped) import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped) function NoteWithMarkdown({text}) { const html = sanitizeHtml(marked(text)); return (/* render */); } // NoteWithMarkdown.server.js // ServerComponentなのでバンドルサイズが0になる import marked from 'marked'; // zero bundle size import sanitizeHtml from 'sanitize-html'; // zero bundle size function NoteWithMarkdown({text}) { // same as before }バックエンドへのフルアクセス
Reactでアプリを作成する際の課題として、データへのアクセス方法及び、データの保存場所が挙げられるそうです。Server Componentはバックエンドに直接アクセスできるので、例えば新しいアプリを作成し始めた時などに、データの保存場所がわからない場合にはファイルシステムを用いることもできます。
// Server Componentなのでバックエンドにアクセスできる import fs from 'react-fs'; function Note({id}) { const note = JSON.parse(fs.readFile(`${id}.json`)); return <NoteWithMarkdown note={note} />; }自動コード分割
コード分割により、アプリケーションを小さなバンドルに分割することができ、クライアントに送信するコードを減らせます。これの一般的なアプローチは、ルート毎にバンドルを遅延ロードするか、実行時になんらかの基準により異なるモジュールを遅延ロードすることが挙げられます。
// Client component import React from 'react'; // これらの1つは、クライアントでレンダリングされるとロードを開始する const OldPhotoRenderer = React.lazy(() => import('./OldPhotoRenderer.js')); const NewPhotoRenderer = React.lazy(() => import('./NewPhotoRenderer.js')); function Photo(props) { // Switch on feature flags, logged in/out, type of content, etc: if (FeatureFlags.useNewPhotoRenderer) { return <NewPhotoRenderer {...props} />; } else { return <PhotoRenderer {...props} />; } }コード分割はパフォーマンス向上に役立ちますが、import時に
React.lazyを用いて動的インポートする必要が出てきます。また、このアプローチはコンポーネントのロード開始タイミングを遅らせるため、コードのロードする量を減らすといった利点を弱めてしまいます。そこで、Server Componentを用いることでこれらの問題に対応することができます。コード分割を自動化するために、Server Componentは全てのClient Componentを潜在的なコード分割点として扱います。
加えて、Server Componentは開発者により早く使用するコンポーネントを選ばせることができるので、クライアントはレンダリングプロセスの早期段階でコンポーネントをダウンロードできます。
// Server Componentなので自動コード分割される import React from 'react'; // これらの1つは、レンダリングされてクライアントにストリーミングされると、ロードを開始する import OldPhotoRenderer from './OldPhotoRenderer.client.js'; import NewPhotoRenderer from './NewPhotoRenderer.client.js'; function Photo(props) { // Switch on feature flags, logged in/out, type of content, etc: if (FeatureFlags.useNewPhotoRenderer) { return <NewPhotoRenderer {...props} />; } else { return <PhotoRenderer {...props} />; } }No waterfall
パフォーマンスが低下する原因の1つとして、アプリケーションがデータをフェッチするために連続してリクエストを行うときに発生します。たとえば、以下の例のように最初にコンポーネントをレンダリングしてから、
useEffect()内でデータをフェッチすることで生じます。// Note.js function Note(props) { const [note, setNote] = useState(null); useEffect(() => { // 子のwaterfallによりレンダリング後にロードされます fetchNote(props.id).then(noteData => { setNote(noteData); }); }, [props.id]); if (note == null) { return "Loading"; } else { return (/* render note here... */); } }親コンポーネントと子コンポーネント両方でこのアプローチをとってしまうと、子コンポーネントは親コンポーネントがデータをロードし終わるまでデータをロードし始めることができません。ただし、このアプローチをとるとアプリケーションが必要なデータを正確にフェッチすることができ、レンダリングされていないUIの部分のデータをフェッチしないようにするといったメリットがあります。
Server Componentを使用すると、サーバとクライアントの連続した往復処理をサーバに移すことでこのメリットをそのままに、問題点を解決することができます。またこの往復処理をサーバーに移動することで、リクエストのレイテンシーを減らし、パフォーマンスを向上させることができます。さらに、Server Componentはコンポーネント内から必要最小限のデータを直接フェッチし続けることができます。
// Note.server.js - Server Component function Note(props) { // サーバに低いレイテンシでデータにアクセスし、レンダリング中にロードされます const note = db.notes.get(props.id); if (note == null) { // handle missing note } return (/* render note here... */); }まとめ
今回説明したServer Componentの特徴を以下にまとめます。
- React Server Componentはサーバーサイドのみで実行されるので、バンドルサイズが0となる
- Client Component(従来のReactコンポーネント)とServer Componentをわけるために
.client.js、.server.jsのように拡張子を変える- データベース、ファイルシステムサーバー側のデータソースにアクセスできる
- レンダリングするClient Componentを動的にロードできるのでクライアントではページのレンダリングに必要な最小限のコードのみダウンロードできる
- リロード時にクライアントの情報を保持する
さらに詳しい情報が知りたい場合は、公式からデモ動画を見て、デモ用のプロジェクトを試してみてください?
参考
- 投稿日:2020-12-23T11:17:35+09:00
typescriptでnumberが自然数かどうか、booleanで返す関数
typescriptで自然数を判別したい
調べると、型でなんとかしようとする記事が目立った。
でもなんかむずそうだから、普通に関数でやろうと思った。// 自然数だったらtrueを返す const isNatureNum = (num: number): boolean => num > 0 && isInteger(num);使い所
cssのプロパティって、自然数しか使えない場面ってある。
自分の場合、grid使うときにrowを制限したいときとか使った。
この実装だとlimitRowがnull,undefined,0,''らへんは全部grid-auto-rowsになるはず(間違ってたらごめんね)
そもそも型でnumberに絞ってるけどね。isNatureNum(prop.limitRow) ? { overflow: 'hidden', gridTemplateRows: `${prop.gridHeight}`, height: 'auto', maxHeight: `calc(${prop.gridHeight} * ${prop.limitRow})`, } : { gridAutoRows: `${prop.gridHeight}` };もっといい方法あったら教えてください
- 投稿日:2020-12-23T09:24:21+09:00
React import/exportについて
export名とimport名が違うのはなんで??となったので調べたことをメモしておく。
import
①defaultでexportされているものについてはimport時にファイルパスさえあっていれば自由に名付けて良い。(当然同じ名前でも構わない)
import 〇〇 from 'ファイルのPath等'
import 『export時の名前』AS 〇〇 from 'ファイルのPath等'②defaultではないものについては
import { 〇〇 } from 'ファイルのPath等'と記載する。
この際、export時と同じ名前を使用する必要がある。③②で名前を変えたい時は、
import { 〇〇 AS つけたい名前 } from 'ファイルのPath等'で変更することができる。export
default
・export 〇〇でファイル・変数を自由にexortできる。
・クラス名・変数名に関わらず、export default 〇〇で自由に名付けられる。(1ファイルにつき1つのみ)以上、参考になれば幸いです。
- 投稿日:2020-12-23T07:15:45+09:00
React.StrictModeをApolloClientと一緒に使う時は気をつけろ
下のページを見れば分かる通り、React.StrictModeとApolloClientの併用は2020/12/23現在いくつかの問題を抱えている。
https://github.com/apollographql/apollo-client/search?q=StrictMode&type=issues
これらの問題が解決される前は、React.StrictModeは使うべきではないかもしれない。
使うにしてもStrictModeが問題を引き起こす可能性があることを頭の片隅においておくべきである。
私みたいに残り少ない人生の貴重な半日を無駄にしたくなければね。
create react appで生成したプロジェクトはindex.jsでReact.StrictMode使ってるからはずそう。
- 投稿日:2020-12-23T05:07:22+09:00
Gatsby.jsで"EMFILE: too many open files"というエラーが出たときの対処法(Vercel)
シチュエーション
Gatsby.jsで大量の画像ノードを作成したところ、あるとき突然以下のようなエラーが出ました。
このエラーはローカルで開発しているMac上では再現せず、Vercelでデプロイした場合のみ発生しました。
解決方法
gatsby-node.jsの上部に、以下を追加し、再度デプロイします。const realFs = require('fs') const gracefulFs = require('graceful-fs') gracefulFs.gracefulify(realFs)このエラーはデフォルトの
fsを使用していると起こる一般的なエラーらしく、その対策として存在するgraceful-fsを使用するようにgatsby-source-filesystemに伝えている感じなのかな、と思います。参考
この対処法は以下のissueに乗っていました。
https://github.com/gatsbyjs/gatsby/issues/12011
- 投稿日:2020-12-23T01:08:50+09:00
Gatsbyでのコンテンツ管理方法
Gatsbyではマークダウン、Googleスプレッドシート、Wordpressなどの従来のCMSなどの様々なデータソースを選択することができます。
そして、1つのデータソースに限る必要もなく、複数のデータソースを組み合わせることもできます。Contentfulについてについて
Contentful】入門。Conentfulとは?導入方法・設定手順の解説
https://fromscratch-y.work/ja/blog/technology/other/start-contentful/【画像解説】Contentfulの使い方【活用方法も紹介】
https://colorfree-map.com/howto-contentfulGraphQLでContentfulのデータを扱うための準備
プラグインの準備
yarn add gatsby-plugin-contentfulgatsby-config.jsにプラグインの設定を追加します。 optionsではContentfulのSpaceID,AccessToken, HOSTを指定する。
ただし、ファイルを直接記述せず環境変数を利用します。(ファイル中にトークンを残したくないため、環境変数を使用する)*環境変数とは、OSが設定値などを永続的に保存し、利用者や実行されるプログラムから設定・参照できるようにしたもの。プログラムの実行時などに必要となる、利用者やコンピュータごとに内容が異なる設定値などを記録するために用いられる。
{ resolve: `gatsby-source-contentful`, options: { spaceId: process.env.CONTENTFUL_SPACE_ID; accessToken: process.env.CONTENTFUL_ACCESS_TOKEN; host: process.env.CONTENTFUL_HOST; }, },開発サーバーの起動
環境変数にした3つの値を指定して、開発サーバーを起動します。(デプロイ時にも環境変数が必要になる)
CONTENTFUL_SPACE_ID=***** CONTENTFUL_ACCESS_TOKEN=***** CONTENTFUL_HOST=cdn.contentful.com gatsby develop -H 0.0.0.0GraphiQLで確認する
GraphiQLにアクセスして、プラグインが機能していることを確認します。
参考文献:
Webサイト高速化のための静的サイトジェネレーター GatsbyJSで実現する高速&実用的なサイト構築
IT用語辞典:http://e-words.jp/w/%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0.html
- 投稿日:2020-12-23T00:51:57+09:00
React開発者必見!!先日発表されたReact Server Componentsとは?
はじめに
12月21日、Facebookから予期せぬクリスマスプレゼントが配られました?
reactjsによって、こちらにReact Server Componentsなるものが突如発表され、React界隈でとても話題になっています。
僕もTwitterでこのニュースを見つけて、ReactでServer???なんかやばそう。そう思いながらこのページを覗くと、説明はどうやら動画のみっぽい。
しゃーねーなーっつって、動画開いたら再生時間57分。当然全部英語...。おいおい、頼むよほんと。
まあ眠くなりかけながらなんとか見終えて、個人的にまとめてみました。
僕がこれ書いてる時点では、ある程度体系的な日本語での記事はほんとにいくつか散見される程度だったので、
日本最速(ほぼ)で紹介します?
それじゃー早速どうぞ。対象の読者
- Reactへの知見がある程度ある方
- React Server Components興味あるけど、動画長げーしって方
React Server Componentsの概要
React Server Componentsは、サーバーサイドにComponentsを置いて、そこからデータ取得を行うことで、余分なネットワーク通信を介したデータのやりとりを減らし、アプリケーションの高速化を実現します。
Componentの種類には
- ${Component名}.client.js (フロントでレンダリング)
- ${Component名}.server.js (サーバーサイドでのレンダリング)
- ${Component名}.js (Shared Component、詳細は後述)
の3つがあります。何がいいか
1.backend内で直接データをfetchできるため、取得速度が早い
NoteList.server.jsexport default function NoteList() { const notes = fetch('http://localhost:4000/notes').json(); // ラップしなくて良い return notes.length > 0 ? ( <ul> { notes.map(note => ( <li> <SidebarNote note={note} /> </li> )) } </ul> ) }動画では上記のようなコードが紹介されています。server.jsファイルでも、普段のReactの記法とに大した差分はありません。
言うとすれば、notesのfetch処理は同期的に扱われるため、普段のようにuseEffect等のhooksでラップする必要はありません。こちらは.server.jsファイルなので、サーバーサイドでのレンダリングがされます。
このようにデータの取得をserverレンダリングのコンポーネントで行うことで、スムーズなデータの受け渡しが可能となり、レンダリングが高速になります。2. server.jsのcomponentで使われるライブラリはnode_modulesに入らないため、clientでの余分なダウンロードがいらない
動画では日付をフォーマットするために、date-fnsというライブラリを用いて説明がされていました。これを用いた日付のフォーマット処理をserver.jsで行うことにより、date-fnsがフロントにビルドされるnode_modulesのディレクトリに居なくなります。
これによって少しでもビルドするモジュールの容量を減らすことができ、アプリケーションの高速化に繋がります。3. SSRと異なり、client-sideのStateが保持される
ここまで聞いて、いやいやSSRやんけ。って思いましたね?
動画内では、SSRとの違いとしてStateの扱いについての違いが挙げられていました。
React Server Componentsでは、useState等で管理されるクライアントのstateが初期化されず、クライアント側でそのまま保持されます。
これはReact Server Componentsがページ全体のHTMLへのレンダリングをせず、必要なComponentのみ再レンダーが走るよう、特殊なフォーマット形式(一見jsonに似てるけどそれともちょっと違う)への変換を行うために可能なそう。4. SharedComponentを使って、server / clientでのレンダリングが柔軟に切り替えられる
サーバーサイドでレンダリングを行うserver.jsファイルに書かれたComponentはフロントとのインタラクティブ性を持つような実装はできません。
つまり、eventListener(onClickとかね)やuseStateは使えません。
そのため、これらのフロントとのインタラクティブ性が必要なComponentはclientでのレンダリングを行い、そうでない部分に関してはサーバーサイドでのレンダリングをするのが理想的といえます。
Shared Component(${Component名}.jsファイルに定義される)はどんなComponentをimportしているかによって、クライアントによるレンダリングを行うか、サーバーサイドでのレンダリングにするかが決定されます。
動画ではnoteのプレビュー機能を例に解説されていました。
noteは完成された投稿を閲覧するだけの場合であれば、フロントとのインタラクティブ性は特にないため、サーバーサードによるレンダリングで十分そうです。ですが、プレビュー機能となると、ユーザーの修正に合わせて常に表示内容が変更される必要があります。この場合はフロントでのレンダリングが必須です。Componentの切り分けを適切に行うことで、Componentを共通化しながら柔軟にどちらでレンダリングするかをハンドリングできます。
終わりに
いかがだったでしょうか?基本的にはデータのfetchをサーバーサイドでレンダリングするComponentで行い、フロントとのインタラクティブ性があるComponentで使う場合はpropsとして渡すと言う感じになりそうです。
詳細については、下記の動画を参考にしてください、また、demoのrepositoryも公開されているので、自分も後で触ってみようかと思います。
正式に公開されるのが楽しみですね。参考








