記事
· 2023年12月26日 7m read

CSPアプリケーションをReactを使って書き換えるその3

それでは、今回はより具体的にReact開発方法について解説します。

ショップデモのリポジトリの配下にreactというディレクトリがあります。

この下にReactのコードがあります。

ここのreact-setup.mdに記載されている通り、前準備としてreactのテンプレートを作ります。

 

npx create-react-app shopdemo --template typescript

 

あとはこのReactプロジェクトを動かすためのライブラリのインストールを行います。

詳細は、react-setup.mdに書いてあります。

まず3つのディレクトリがあって、これは絶対こうしなければならないというものでもないのですが、基本的なお作法として用意するのが一般的なようです。

  • public
    • ここにはindex.htmlだけ置くのが一般的なようです。
    • テンプレートが自動生成するものでも良いのですが、Bootstrapを使用する場合は、テンプレートのindex.htmlにそのライブラリのロードを付け加えています。
  • components
    • ここに自分で開発するreactコンポーネントを配置します。
  • hooks
    • hookを用意する場合は、ここに配置します。 ​​​​

ここでは、まずログインをするためのユーザー認証を行うコンポーネントの処理について説明します。

Login.tsxに処理を記述しています。

tsxという拡張子は、jsx形式のファイルで、typescriptで記述する際は、tsxにするのがお作法のようです。


このファイルの終わりの方にreturn文以降に以下のような記述があります。

これがjsx記法と呼ばれるもので、javascriptの中にHTML文を埋め込むことができます。

 

return (

<div>

<h1>ログイン</h1>

<form onSubmit={handleSubmit}>

<table>

<tbody>

<tr>

<td><label>利用者ID:</label></td>

<td><input name="userid" type="text" placeholder="userid" /></td>

</tr>

<tr>

<td><label>パスワード</label></td>

<td><input name="password" type="password" placeholder="password" /></td>

</tr>

<tr><td><button type="submit">ログイン</button></td></tr>

</tbody>

</table>

</form>

{isError && <p style={{ color: "red" }}>{`${errorText}`}</p>}

</div>

);

};

 

ここでユーザー名とパスワードを入力してもらって、ログイン認証を行う処理を作っていきます。

前回の記事でReactは基本SPAでサブミットはないという説明をしましたが、このログイン処理のように複数のデータをフォーム形式で入力してサブミットするというようなケースは多々あります。

方法は色々あるのですが、ここではreact-router-domというものを使っています。

それ以外にもnext.jsというフレームワークが有名です。

実際にサブミットしているように見えますが、実際にPOSTしているわけではなく、react-router-domというフレームワークの中であくまでもSPAの枠組みの中で処理は実装されている感じです。

(もしかしたらこの理解は間違っているかも)

ここでonSubmitコールバックとしてhandleSubmitというメソッドが呼ばれています。

ここの中括弧は、jsxの作法の1つで、そのカッコ内にjavascriptを記述できます。

ここでは、handleSubmitはJavaScriptの変数で、以下のように定義されています。

ちなみにReactでは変数定義は、基本const、たまにletが使われ、varは使いません。

古いJavaScriptしか知らない人にとってはここが1つのハードルかもしれません。

そして以下のコードは厳密に言うと、TypeScriptですが、あんまり褒められたTypeScriptコードではありません。

eventという変数の型としてanyを使っていますが、本当は適切なイベント型を指定するべきです。

そのイベントに紐づいた(ここはフォームデータなので)データ要素としてユーザー名とパスワードを取得しています。

そしてuserLoginCheckというメソッドを呼び出しています。

 

  const handleSubmit = (event: any) => {
    event.preventDefault();
    const { userid, password } = event.target.elements;
    userLoginCheck(userid.value, password.value).finally(() => 
    {
      if (login.status) {
        navigate("/Shop", { state: { customerId: login.customerId } })
      }
        
    })
  };
 

 

userLoginCheckの中身は以下のようになっています。

 

const userLoginCheck = async (userid: any, userpassword: any) => {

let status = false;

let customerId = 0;

setIsLoading(true);

setIsError(false);

await axios

.get<any>(`http://${serverAddress}:${serverPort}${applicationName}/checkpassword/${userid}/${userpassword}?IRISUsername=${username}&IRISPassword=${password}`)

.then((result: any) => {

if (result.data.authorized === 'ok') {

login.status = true;

login.customerId = result.data.ID;

}

else {

setIsError(true);

setErrorText('ログインが失敗しました');

}

})

.catch((error: any) => {

setIsError(true)

if (error.response) {

setErrorText(error.response.data.summary);

}

else if (error.request) {

setErrorText(error.request);

}

else {

setErrorText(error.message);

}

})

.finally(() => setIsLoading(false))

};

 

 

この後、RESTのインタフェースによりサーバーのAPIを呼び出します。

RESTのインタフェースの実装も複数ありますが、ネット上でサンプルがたくさん見つかるaxiosというライブラリを使用しています。

ここでREST APIのurlを指定します。 

このurlにcheckpasswordというメソッド名が含まれているのがわかると思います。

これがIRIS側で呼ばれるメソッド名となります。

ログインチェックがOKだったら、react-router-domに含まれるnavigateメソッドを呼び出して、/Shopにページ遷移します。

(実際にページ遷移しているわけではなくあくまでもエミュレーション)

あと、axiosの呼び出しは非同期なので、結果が返る前に呼び出しが戻ってくるので、最初はその動きになかなか慣れないかもしれません。

 

ログインが成功するとShop.tsxが呼ばれます。

このページはさらに複数のコンポーネントで構成されています。

そしてショッピングカートの機能を実装するためにcreateContextを使いコンテキスト情報を管理します。

navigate経由でページ遷移する際にデータを引き継ぐ仕組みとしてuseLocationというフックが用意されているので、それを使って情報を引き継ぎます。

jsx記法によるHTML定義の中で動的にデータを変更したい部分にはuseStateというフックを使用します。

 

import React from 'react';
import { createContext, useState, Dispatch,SetStateAction } from "react";
import { Header } from './Header';
import { ShoppingCart } from './ShoppingCart';
import { ProductList } from './ProductList';
import { useLocation } from "react-router-dom"

export type shopItem = {
        productCode: string;
        productName: string;
        price: number;
        units: number;
  };
  
export const ShopContext = createContext({} as {
    orderItems: shopItem[];
    setOrderItems: Dispatch<SetStateAction<shopItem[]>>;
    }
  ); 

export const Shop = () => {

  const [orderItems, setOrderItems] = useState<shopItem[]>([]);
  
  const location = useLocation();
        
  const values={orderItems,setOrderItems};
  
  return (
    <>
    <div className="title">
    <Header customerId = {location.state.customerId} /> 
    </div>
    <ShopContext.Provider value={values}>
    <div className="shoppingcart" style = {{ float: "left",width: "40%",height: "100%",overflow: "auto",border: "solid #000000 1px"}}>    
    <ShoppingCart customerId = {location.state.customerId} />
    </div>
    <div id="productlist" style = {{ width: "60%",height: "100%",overflow: "auto",border: "solid #000000 1px"}}>
    <ProductList />
    </div>
    </ShopContext.Provider>
    </>    
  );    
}
export default Shop;

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください