2021年5月23日日曜日

Javascript で日付操作

 Javascriptで日付操作をするときnew Date()などで面倒だったけど、momentがよさそうだったのでとりあえずメモ。


[ドキュメント]
  http://momentjs.com/
[参考]
(わくわくBank)
https://www.wakuwakubank.com/posts/606-javascript-moment/

[インストール]

    npm install moment

[使い方]

  1. とにもかくにもインポート
    import moment from moment;
  2. 処理でのコーディング
    (現在日付を取得)
    moment().format("YYYY-MM-DD HH:mm:ss")

  3. こんなことも?
    (ロケール指定)
       moment.locale('ja')
    (加算:add)
       moment().add(数字,単位)
         単位: 年:'y',月:'M',週:'w',日:'d',時間:'h',分:'m',秒:'s'
    (減算:subtract)
       moment().subtract(数字,単位)
          単位は加算と同じ
    (差分:diff)
       元moment.diff(比較対象moment,単位,小数調整)
       単位は加算と同じ、デフォルトはミリ秒
     小数調整は小数以下あり(true),なし(false)
    (はじめ:startOf と おわり:endOf)
     moment().startOf(単位)  はじめ 
       moment().endOf(単位) おわり
     単位は加算と同じ
    (ほかの日時と比較:isAfter,isBefore,isSame)
       元より比較対照が後であればtrue : 元moment.isAfter(比較対象moment)
       元より比較対照が前であればtrue : 元moment.isBefore(比較対象moment)
       元と比較対照が同じであればtrue : 元moment.isSame(比較対象moment)
    (日付の生成)
      現在時刻(デフォルト) : moment()
      文字列で指定              : moment("2021-05-23")
      オブジェクトで指定     : moment({years:2021,months:5,days:23})
      Dateオブジェクト   : monent(new Date(2021,5,23))

2021年5月22日土曜日

Reactでコンポーネント間のデータ共有がしたい

 Reactは親から子コンポーネントに値を渡す場合、引数(props)として渡すことができる。ただ引数で実装する場合、親から孫や、兄弟で同じ値を参照しようとすると必要もないのに、propsに設定しまくることになるので、メンテンナンス性が良くない。

React ではContext APIを用意しているので、上記のようなケースの場合に使える。


[ドキュメント]

   https://ja.reactjs.org/docs/context.html

[インストール] 

  ※Reactに含まれているuseContextを使うので、Reactが入っていればよし。

[ソース例]

[context/app.js] Context用のファイル
import { createContext } from 'react';
const AppContext = createContext();
export default AppContext;

[App.js] アプリ本体
import AppContext  from './context/app';
import { useState } from 'react';

function App() {
  //authという状態とsetAuthという設定用関数を取得
  let [auth,setAuth] = useState();
  return (
    //AppContextで共有するauthとsetAuthを設定
    <AppContext.Provider value={{"auth":auth,"setAuth":setAuth}} >
    <Sample></Sample>
    </AppContext.Provider>
  );
}

[sample.js] 子コンポーネント
import React,{useContext} from 'react';
import AppContext  from './context/app';
function App(){
    //useContextでAppContextの状態を取得
    let app_context=useContext(AppContext);
    //Contextに値を設定
    app_context.setAuth({user_id:1});
   //参照
    console.log(app_context.auth);//{user_id:1}
    
    return (
        <div></div>
    );
}
export default Sample;


[ソース内での書き方]

  1.  createContextでContextを生成する。
    他のコンポーネントにimportするため、外部ファイルにしておく。
    適当に名前を付けてたContext用の変数にcreateContext()の戻り値を設定する。
      const AppContext = createContext();
    他のソースで読みこんだ時にアクセスできるように宣言をしておく
      export default AppContext;

  2. 共有したい範囲のコンポーネント上位に、ContextのProviderを設置する。

    定義したContextにはProviderが標準で用意される。
    定義したContextに合わせてタグを作る
    <AppContext.Provider value={オブジェクト}></AppContext>
    ソース例(App.js)では、面倒なのでuseState()で管理する値と、変更用の関数を用意して、それらをContentに設定している。

  3. Context.Consumer側での値の参照
    上位はPoviderで、受け取る側はCunsumerというらしい。
      関数コンポーネントの場合はuseContext()フックが使えるので、意識しなくても大丈夫。

     利用する場合は、useContext(定義したContext)で利用するContextを取得する。
     ソース例では、AppContextとしているので、useContext(AppContext)と記述することになる。
    Contextが取得できれば、あとは、共有した要素に直接以下のようにアクセスできる
        Context.共有値
    ソース例では、値保持用のauthと変更用のsetAuthという関数型の値を共有しているので、
        app_context.auth
        app_context.setAuth({user_id:2}) 
    といったようにアクセスできる。

React Routerでベースをルート以外にする方法

 React Routerは初期状態だと、"/"を起点にしてしまうので、デプロイ先が/hoge/のようになるとおかしくなる。
回避するには   

    <BrowserRouter basename="/test/">

 のように、BrowserRouterの属性でbasenameに配置場所を指定すればよい。

npm startで起動する際にも変える必要があるので、プロジェクトのpackage.jsonでhomepageを指定する必要がある。

 “homepage”:”/test/”



React Hook Formでフォーム要素の管理をしてみる

 Reactでフォーム画面を構成したいときに、標準(?)だとinput要素一つ一つにstateを管理するようなつくりで面倒くさいので、React Hook Formが使えそうだったのでなんとくメモ。

非制御コンポーネント (Uncontrolled Components) を、管理下(register)に登録することで、form要素の一括してデータを取り扱える(操作およびvalidateion)ようにしている感じ。
非制御コンポーネントな要素だけだと、Material UIやBootstrapなどでラップしている部品は使えないことになるこえど、そのあたりは考慮されている模様。
今回は、非制御コンポーネントの書き方をメモ。

useState()で状態を一つずつ管理したり、useRef()を使用して参照先を管理するよりはわかりやすいかなぁと。※中身はuseRef()使っているのかも



[ドキュメント]

   https://react-hook-form.com/jp/

[インストール] 

  $npm install react-hook-form

[ソース例] ログイン画面のイメージ
import {useForm} from 'react-hook-form';
function Login(){
    const { register, handleSubmit, formState: { errors },reset } = useForm();
    //Sumit時に呼ばれる処理
    const handleLink = (form_data) => {
        console.log(form_data);
    };
    return (
        <div>
        <form onSubmit={handleSubmit(handleLink)}>
                アカウント:<input type="text" {...register("account", { required: true })} /><br/>
                パスワード:<input type="password" {...register("password", { required: true })} /><br/>
                    <button type="submit">送信</button>
                    <button onClick={()=>{reset()}}>キャンセル</button>
                    <p>{(errors.account || errors.password) && "アカウントとパスワードをどちらも入力してください。"}</p>
                </form>
        </div>
    );
}

[ソース内での書き方]

  1. とにもかくにもインポート

    import {useForm} from 'react-hook-form';

  2. 関数コンポーネント内で、useForm()を仕様
    useForm()から取得できるものはいろいろとあるけど、以下を使ってみた

        register    フォーム要素の関連付け(?)用の関数
        handleSubmit    Submitで呼ばれる関数
        formState:{arrors}    フォーム要素のエラーの状況
        reset  フォーム要素の要素を再設定用の関数

    useForm()の引数として、フォームに設定するデフォルト値なんかも設定できる

  3. form要素のonSubmitイベントでuseForm()で取得したhandleSubmitをコール

    form要素で送信ボタンなどのsubmitをした際にhadleSubmitが呼ばれるようにする。
    hadleSbumitの引数として、実際に実行したい関数を設定しておく。
    指定した関数への引数として、4.で登録するinput要素のnameをキーにしたオブジェクトが設定されるので、それぞれの要素にアクセスしやすい。

  4. input要素を管理下に登録

    useForm()で取得したregisterを使って、input要素を管理下に登録する。
    inputの属性として、registerも戻りが設定されるように記載する。

    <input type="text" {...register("account", { required: true,maxLength:{value:5,message:"5文字まで"} })} />

    regiserの引数として、第1引数にキーとなる名称、第2引数は任意で、簡易的なバリデーションの情報を設定する

    registerの前の...はスプレッド構文 (...) というらしく、オブジェクトや配列などを展開してくれる便利な構文だそうです。

    バリデーションは以下が使える。registerでの登録の際にはエラー時のメッセージも登録できる。
        required    必須
        min    最小値
        max    最大値
        minLength    最小文字数
        maxLength    最大文字数
        pattern    正規表現
        validate    オリジナルのチェック関数を設定

  5. reset処理を追加(必要なら)
    resetを使うと管理要素をセットしなおしてくれる。
    引数なしだとすべて空にしてくれるが、オブジェクトでkey:valueを指定することによって
    上の例ではリセットボタンを
    ボタンのタイプをreset(<button type="reset">リセット</button>)としても空にはなる
    その際には、フックの対象にならないので、イベントが走らない。

    初期表示の値を入れるのであれば、以下のようにuseEffect()で実行させると入力済みにしてくれる。

        useEffect(()=>{
            reset({account:'start_string'})
        },[reset]);

Javascriptでサーバへアクセスするのにfetchメソッドを使ってみる。

 
以前は、 XMLHttpRequest や jQuery の ajaxメソッドを使ってサーバへのアクセスをしていたけど、今はfetchメソッドを使うとシンプルにかけそうなのでなんとくなくメモ。

前は非同期処理をする際に、コールバック関数をつなげていくような見通しがわるいコード
になってたけど、イマドキはpromiseが使えるので、見た目すっきりでいい感じ。


(参考)
https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch


[基本的な使い方(promise)]

fetch(接続先文字列, { オプション })
 .then((response) => {
  //Responseオブジェクトが引数に設定される
    //httpステータス404とかでもここまで到達するのでResponse.statusかResponse.okプロパティで正常か判定をしたほうがよい。
    if (!response.ok) {
        throw new Error();
    }
    //ResponseのBody部を戻り値にしてやるBodyに設定されているデータに応じて容易に取得するためのメソッドが用意されている
  // バイナリ:response.blob(),JSON形式: response.json() ,Text形式: response.text() ,FomrData形式: response.formData()

    return response.json(); //bodyがJSON文字列の場合の取得例
 })
 .then((data) => {
    //前のthenのリターンが引数として設定される
    //response body部の処理を記述する想定
   
    
 })
 .catch((error) => {
    // ネットワークトラブルか、then句での例外などの処理を記述
 });


<<GETの場合>>
オプションは省略可能
fetch(接続先文字列)


<<POSTの場合>>
オプション部分で、method,cache,bodyを指定する
fetch(接続先文字列, {   
    method: 'POST',
        cache: 'no-cache',
        headers: {
              'Content-Type': 'application/json',
        },
        body: data  //送りたいデータ
 }
)

bodyに設定設定するのは、テキストかformData,バイナリと何でもよい。

[json文字列の場合]
 適当なオブジェクト(data)をJSON.stringify(data)としてJSONに変換するだけでOK
   body:JSON.stringify(data)


 ※オプション部分にヘッダーとして、Content-Typeなどを設定するとよい。
  headers: {
    'Content-Type': 'application/json',
  },

[formDataの場合]
ファイルアップロードとかする場合はformDataのほうがよさげ。
const data = new FormData();
let blob = new Blob(['Sample text'], {
    type: 'text/plain'
});data.append('data1', blob, 'foo.txt');

2021年5月20日木曜日

React Routerで画面遷移をするときのメモ

 Reactで画面を切り替えるのに、React Routerが使えそうだったのでなんとくメモ。

 ざっくりとした感覚だと、URLのパスを条件として、呼び出すコンポーネントを切り替える感じ
 パスが切り替わったタイミングで、判定してくれるので、React Routerの用意するLinkやuseHistory()でするhistory.push()やhistory.replace()、あとはwindow.location.hrefなどでパスを操作することで、表示するコンポーネントを切り替えることができる。
 

[ドキュメント]

   https://reactrouter.com/

[インストール] 

  $npm install react-router-dom
[ソース内での書き方]
  1.  ルーティングをするソースでのインポート

    import {
      BrowserRouter,
      Switch,
      Route
    } from 'react-router-dom';

  2.  ルーティングの定義
    (記述例)
    <BrowserRouter>
     <Switch>
       <Route exact path="/" component={Login}  />
       <Route exact path="/top" component={Top}  />
     </Switch>
    </BrowserRouter>

    • BrowserRouter
      React Routerでコンポーネントを切り替える位置に配置する。
      BrowserRouterで切り替える子コンポーネント内でも再度切り替えるための記述可能。
      特にパラメータは不要。


    • Swtich
      BrowserRouterの子要素として切り替える条件を囲うために配置する。
      子要素としてRouteを配置する。


    • Route
      ルーティング条件を記述するために配置する。切り替える条件分配置する。
      パラメータとして、条件となるパスを定義するpathと条件に一致する際に呼び出すコンポーネントを定義するcomponentを設定する。
      pathだけだと部分一致になるので厳密な一致を条件とする場合はexactをパラメータとして追加する。path部分は正規表現やパスをパラメータとして受け取るための定義もできるのでいろいろと使えそう

  3. URLパスの切り替え
    URLのパスの切り替えは大まかに以下の3つ
    • React Routerが用意するLink
      import {Link} from 'react-router-dom';//インポート

      <Link to {path="/next/"}>次へ</Link>


    • React Routerが用意するhistoryの操作
      ※関数コンポーネントの場合は
      フックでuseHistory()を使える

      import {useHistory} from 'react-router-dom';//インポート

      let {history} = useHistory();
      const next =()=>{history.push("/")};//履歴が残る

      const back=()=>{history.replace("/")};//履歴が残らない

    • windowsオブジェクトのlocation.hrefの操作
      普通にwindows.location.href="/"としても操作できる

 

2021年5月16日日曜日

Reactでテーブル表示にMaterial-Tableを使うときのメモ

サーバから取得したデータを表形式で表示することが多いので、テーブル関連を探していたら、Mateial-UIの拡張として、Material-Tableなるものがあったのでとりあえずメモ。

Material-UIがインストールされていることが前提。

[ドキュメント]

   https://material-table.com/#/

[インストール] 

  $npm install --save material-table
[ソース内での書き方]
  1. とにもかくにもインポート
    import MaterialTable from 'material-table';

  2.  JSXの中での記述
    MaterialTableのタグに属性値としてtittle,columns,dataなどを渡す。
    プロパティはここを参照
    <MaterialTable
            title={"Material-tableテスト"}
            columns={[
              { title: 'カラム1', field: 'col1' },
              { title: 'カラム2', field: 'col2' }
            ]}
            data={[
              
              { col1: 'データ1', col2: 'データ3' },
              { col1: 'データ2', col2: 'データ4' }
            ]}
            options={{
              showTitle: true,
            }}
          />