見出し画像

nextjs with typescript:21 SWRの使い方trigger設定、OptimisticなUI

【1】TriggerでSWRを動かす

前回までは
「ボタン押下 ⇒ alert()でブラウザフォーカス外し ⇒ ボタン押下でブラウザフォーカス戻し ⇒ SWRによるデータフェッチ」
という状態であった。

alertウィンドウ等は出さずに、ボタンを押したらすぐ反映(描画)される方がうれしい。これを実現するのがSWRの「trigger」。

...(略)...

import { trigger } from 'swr';

...(略)...

const AddVtuber=()=>{

   return (
       <div>
           
           <Formik 
               initialValues={
                   {
                       name:'',
                       details:''
                   }
               } 
               onSubmit= { async(values,formikHelpers)=>{
                   
                   await axios.post('http://localhost:4001/persons',values);
                   
                   formikHelpers.resetForm();//フォームリセット
                   //alert(` input data ${values.name} and ${values.details} added ! `)
                   trigger('http://localhost:4001/persons');
               }}
           >
...(略)...

画像1

画像2

ざっくりいうと
「Trigger」はSWRにデータフェッチすべきURL(サーバ)を教えて、データをキャッシュするきっかけ(=trigger)を作っている
という感じ。

【2】Optimistic UI(楽観的UI)とmutate(ミューテート)

■Optimistic UI(楽観的UI)
 これはクライアントから何か送信したときに、サーバからの応答を待たずにクライアント側の画面を更新してしまう手法

例えば
・チャットアプリでメッセージを送ったときに、送信完了を待たずにひとまずメッセージをタイムラインに表示しておくような挙動

・メモ帳アプリでメモ編集画面からメモ一覧画面に戻るときに、裏で編集中メモを保存しつつ一覧画面にはすでに反映済みにしておく挙動

Facebookの「いいねボタン」、youtubeの「高評価・低評価ボタン」などの押したらすぐ更新されているように見える挙動

・・・などなど

このような挙動のためにSWRでは「mutate」を用意している

■mutate(ミューテート)
書式

(alias) mutate(key: keyInterface, data?: any, shouldRevalidate?: boolean | undefined): Promise<any>

key⇒ここにURLを指定する
data⇒SWRでフェッチしたデータ(キャッシュデータ相当)
shouldRevalidate⇒データ取得とデータキャッシュ化の実行有無

【例】:ボタンを押すとmutateで先に画面描画。裏で「axios.post()」をしてからtriggerでデータを再フェッチして正式な反映をさせる

【components/AddVtuber.tsx】

import {Formik,Form,Field} from 'formik';
import {Button,Box,FormGroup,TextField} from '@material-ui/core';
import axios from 'axios';
import useSWR,{ mutate,trigger } from 'swr';

const AddVtuber=()=>{

   //mutate用に先にデータフェッチをしておく
   const {data} = useSWR('http://localhost:4001/persons');

   return (
       <div>
           
           <Formik 
               initialValues={
                   {
                       name:'',
                       details:''
                   }
               } 
               onSubmit= { async(values,formikHelpers)=>{
                   

                   //post前にフェッチしているデータに対し更新をいれる。
                   //第2引数にフェッチデータdataとformikでバインドしてるvaluesを連結させる
                   //ただし,
                   //revalidate=false⇒SWRでのデータ再取得はaxios.postの後にする
                   mutate('http://localhost:4001/persons',[...data,values],false);


                   await axios.post('http://localhost:4001/persons',values);
                   
                   formikHelpers.resetForm();//フォームリセット
                   //alert(` input data ${values.name} and ${values.details} added ! `)
                   trigger('http://localhost:4001/persons');
               }}
           >

               <Form>
                   <FormGroup>
                       <Field as={TextField} name="name" label="name" />
                   </FormGroup>
                   
                   <FormGroup>
                       <Field as={TextField} name="details" label="about" />
                   </FormGroup>

                   <Box marginTop={1}>
                       <Button type="submit" variant="contained" color="primary"> Add  </Button>
                   </Box>
               </Form>


           </Formik>

       </div>
   );
}

export default AddVtuber

画像3

↓ 入力したらADDボタンを押す

画像4

※今回の例ではidをmutateに渡していないので、map関数を使った繰り返しの描画時にkeyがない、とコンソール上に警告がでてるが気にしないでおく。

画像5

■まとめ:triggerとmutate

・trigger⇒SWRにデータフェッチするURL(サーバ)をおしえてデータをキャッシュするきっかけ(=trigger)を作る

・mutate最初に指定のキャッシュデータを確認する。そのあとでサーバに接続してデータをキャッシュする処理を動かす。

もっと応援したいなと思っていただけた場合、よろしければサポートをおねがいします。いただいたサポートは活動費に使わせていただきます。