Reactのサード・ステップ2
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfras...
-戻る([[React]] -> [[Redux]])
--...[[Reactの5thステップ]]
--[[Reactのファースト・ステップ2]]
--[[Reactのセカンド・ステップ2]]
--Reactのサード・ステップ2
*目次 [#bf704575]
#contents
*概要 [#rbd0d9e0]
引き続き[[Redux]]対応を行う。
*詳細 [#k95528b7]
**プロンプト [#gad08276]
CrudSampleとCrudSample2があるが、構成が複雑なCrudSample2...
以下のCrudSample2のmessageをRedux対応させたい。修正方法...
.\src\store\index.ts
.\src\store\counterSlice.ts
.\src\pages\CrudSample2.tsx
.\src\components\CrudSample2\Buttons.tsx
.\src\components\CrudSample2\DropDownLists.tsx
.\src\components\CrudSample2\Inputs.tsx
.\src\components\CrudSample2\Outputs.tsx
```
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
export const store = configureStore({
reducer: {
counter: counterReducer,
},
})
// 型エクスポート(useSelector / useDispatch で使用)
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
```
```
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
interface CounterState {
value: number
}
const initialState: CounterState = {
value: 0,
}
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1
},
decrement: (state) => {
state.value -= 1
},
incrementByAmount: (state, action: PayloadAction<num...
state.value += action.payload
},
reset: (state) => {
state.value = 0
},
},
})
export const { increment, decrement, incrementByAmount, ...
export default counterSlice.reducer
```
```
import * as React from 'react';
import constants from '../const';
import common from '../common.ts';
import oauth_oidc from '../touryo/oauth_oidc';
import Inputs from '../components/CrudSample2/Inputs';
import DropDownLists from '../components/CrudSample2/Dro...
import Buttons from '../components/CrudSample2/Buttons';
import Outputs from '../components/CrudSample2/Outputs';
// ===== 型定義 =====
interface DdlState {
ddlDap: string;
ddlMode1: string;
ddlMode2: string;
ddlIso: string;
ddlExRollback: string;
ddlOrder: string;
ddlOrderSequence: string;
}
interface ShipperState {
shipperID: string;
companyName: string;
phone: string;
}
interface CrudSample2State {
message: string;
ddl: DdlState;
shipper: ShipperState;
shippers: ShipperState[];
loading: boolean;
}
// ===== コンポーネント =====
export class CrudSample2 extends React.Component<Record<...
{
constructor(props: Record<string, never>) {
super(props);
this.state = {
message: '',
ddl: {
ddlDap: 'SQL',
ddlMode1: 'individual',
ddlMode2: 'static',
ddlIso: 'NT',
ddlExRollback: '-',
ddlOrder: 'c1',
ddlOrderSequence: 'A',
},
shipper: {
shipperID: '',
companyName: '',
phone: '',
},
shippers: [
{
shipperID: '',
companyName: '',
phone: '',
},
],
loading: true,
};
}
// ===== render =====
render() {
const containerStyle: React.CSSProperties = { textAl...
const div0Style: React.CSSProperties = {};
const div1Style: React.CSSProperties = { display: 'i...
const div2Style: React.CSSProperties = { display: 'i...
return (
<div style={containerStyle}>
<h1>CRUD sample</h1>
<p>This component demonstrates CRUD.</p>
<div style={div0Style}>
<DropDownLists onChangeDdl={(e) => this.receiv...
</div>
<div style={div1Style}>
<Inputs
shipper={this.state.shipper}
onChangeInput={(e) => this.receiveInputChang...
/>
</div>
<div style={div2Style}>
<Outputs
loading={this.state.loading}
shippers={this.state.shippers}
message={this.state.message}
/>
</div>
<div>
<Buttons
onClickButton={(e) => this.receiveButtonClic...
/>
</div>
</div>
);
}
// ─── 子コンポーネントからのイベント受信 ────────────...
receiveDDLChanged(ddl: Partial<CrudSample2State>): voi...
this.setState(ddl as CrudSample2State);
}
receiveInputChanged(shipper: Partial<CrudSample2State>...
this.setState(shipper as CrudSample2State);
}
receiveButtonClick(actionType: string): void {
switch (actionType) {
case 'SelectCount': this.selectCount(); retu...
case 'SelectAll_DT': this.selectAll_DT(); retu...
case 'SelectAll_DS': this.selectAll_DS(); retu...
case 'SelectAll_DR': this.selectAll_DR(); retu...
case 'SelectAll_DSQL': this.selectAll_DSQL(); retu...
case 'Select': this.select(); retu...
case 'Insert': this.insert(); retu...
case 'Update': this.update(); retu...
case 'Delete': this.delete(); retu...
default: return;
}
}
// ===== WebAPI イベントハンドラ =====
selectCount() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'SelectCount',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollba...
(data) => {
if (data.message) {
this.setState({ message: JSON.stringify(data.m...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
selectAll_DT() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'SelectAll_DT',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollba...
(data) => {
if (data.result) {
this.setState({ message: '', shippers: data.re...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
selectAll_DS() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'selectAll_DS',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollba...
(data) => {
if (data.result) {
this.setState({ message: '', shippers: data.re...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
selectAll_DR() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'selectAll_DR',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollba...
(data) => {
if (data.result) {
this.setState({ message: '', shippers: data.re...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
selectAll_DSQL() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'selectAll_DSQL',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollback
+ '&orderColumn=' + this.state.ddl.ddlOrder
+ '&orderSequence=' + this.state.ddl.ddlOrderSeq...
(data) => {
if (data.result) {
this.setState({ message: '', shippers: data.re...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
select() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'select',
oauth_oidc.createHttpRequestHeader(true),
JSON.stringify({
ddlDap: this.state.ddl.ddlDap,
ddlMode1: this.state.ddl.ddlMode1,
ddlMode2: this.state.ddl.ddlMode2,
ddlExRollback: this.state.ddl.ddlExRollback,
shipper: {
shipperID: this.state.shipper.shipperID,
companyName: '',
phone: '',
},
}),
(data) => {
if (data.result) {
const result = data.result as ShipperState;
this.setState({
shipper: {
shipperID: result.shipperID,
companyName: result.companyName,
phone: result.phone,
},
});
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
insert() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'insert',
oauth_oidc.createHttpRequestHeader(true),
JSON.stringify({
ddlDap: this.state.ddl.ddlDap,
ddlMode1: this.state.ddl.ddlMode1,
ddlMode2: this.state.ddl.ddlMode2,
ddlExRollback: this.state.ddl.ddlExRollback,
shipper: {
shipperID: '0',
companyName: this.state.shipper.companyName,
phone: this.state.shipper.phone,
},
}),
(data) => {
if (data.message) {
this.setState({ message: JSON.stringify(data.m...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
update() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'update',
oauth_oidc.createHttpRequestHeader(true),
JSON.stringify({
ddlDap: this.state.ddl.ddlDap,
ddlMode1: this.state.ddl.ddlMode1,
ddlMode2: this.state.ddl.ddlMode2,
ddlExRollback: this.state.ddl.ddlExRollback,
shipper: {
shipperID: this.state.shipper.shipperID,
companyName: this.state.shipper.companyName,
phone: this.state.shipper.phone,
},
}),
(data) => {
if (data.message) {
this.setState({ message: JSON.stringify(data.m...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
delete() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'delete',
oauth_oidc.createHttpRequestHeader(true),
JSON.stringify({
ddlDap: this.state.ddl.ddlDap,
ddlMode1: this.state.ddl.ddlMode1,
ddlMode2: this.state.ddl.ddlMode2,
ddlExRollback: this.state.ddl.ddlExRollback,
shipper: {
shipperID: this.state.shipper.shipperID,
companyName: '',
phone: '',
},
}),
(data) => {
if (data.message) {
this.setState({ message: JSON.stringify(data.m...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
}
```
```
import * as React from 'react';
// 型定義
interface Shipper {
shipperID: string;
companyName: string;
phone: string;
}
interface OutputsProps {
shippers: Shipper[];
loading: boolean;
message?: string;
}
interface OutputsState {
shippers: Shipper[];
loading: boolean;
message?: string;
}
export class Outputs extends React.Component<OutputsProp...
// constructor
constructor(props: OutputsProps) {
super(props);
this.state = {
shippers: [
{
shipperID: '',
companyName: '',
phone: '',
},
],
loading: true,
message: undefined,
};
}
// lifecycle
// componentWillReceiveProps は非推奨のため getDerived...
static getDerivedStateFromProps(
newProps: OutputsProps
): OutputsState {
return {
loading: newProps.loading,
shippers: newProps.shippers,
message: newProps.message,
};
}
// render
render() {
let contents: React.ReactNode = null;
if (this.state.loading) {
contents = (
<p>
<em>...Table...</em>
</p>
);
} else {
contents = (
<table className="table">
<thead>
<tr>
<th>ShipperID</th>
<th>CompanyName</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
{this.state.shippers.map((shipper) => (
<tr key={shipper.shipperID}>
<td>{shipper.shipperID}</td>
<td>{shipper.companyName}</td>
<td>{shipper.phone}</td>
</tr>
))}
</tbody>
</table>
);
}
return (
<div>
{contents}
<p>処理結果:{this.state.message}</p>
</div>
);
}
}
export default Outputs;
```
```
import * as React from 'react';
// Propsの型定義
interface ButtonsProps {
onClickButton: (actionType: string) => void;
}
export class Buttons extends React.Component<ButtonsProp...
constructor(props: ButtonsProps) {
super(props);
}
render() {
return (
<div>
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
</div>
);
}
onClickButton(actionType: string): void {
this.props.onClickButton(actionType);
}
}
export default Buttons;
```
**修正内容 [#e4537aef]
crudSample2Sliceは、crudSample、crudSample2で共用するため...
-先ずは「store」の内容
--crudSample2Slice.ts
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
interface CrudSample2SliceState {
message: string;
}
const initialState: CrudSample2SliceState = {
message: '',
}
const crudSample2Slice = createSlice({
name: 'crudSample2',
initialState,
reducers: {
setMessage: (state, action: PayloadAction<string>) =...
state.message = action.payload;
},
clearMessage: (state) => {
state.message = '';
},
},
})
export const { setMessage, clearMessage } = crudSample2S...
export default crudSample2Slice.reducer
--index.ts
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
import crudSample2Reducer from './crudSample2Slice' // ...
export const store = configureStore({
reducer: {
counter: counterReducer,
crudSample2: crudSample2Reducer, // ← 追加
},
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
-CrudSample2.tsx
--ヘッダ
// Redux 関連のインポート
import { connect } from 'react-redux';
import type { RootState, AppDispatch } from '../store';
import { setMessage, clearMessage } from '../store/crudS...
// ===== 型定義 =====
// Propsの型定義
interface StateProps {
message: string;
}
interface DispatchProps {
onSetMessage: (msg: string) => void;
onClearMessage: () => void;
}
// コンポーネント自身のProps(connect後に外から渡すもの...
type CrudSampleProps = StateProps & DispatchProps;
...
interface CrudSample2State {
//message: string; は Redux管理のため削除
ddl: DdlState;
shipper: ShipperState;
shippers: ShipperState[];
loading: boolean;
}
--ボディ
---クラス冒頭部
export class CrudSample2 extends React.Component<CrudSam...
{
constructor(props: CrudSampleProps) {//Record<string, ...
super(props);
this.state = {
// message: '', は Redux管理のため削除
---Render部
this.props.message → this.state.message
---イベントハンドラ
// ===== WebAPI イベントハンドラ =====
// this.setState({ message: ... }) → this.props.onSetMe...
// this.setState({ message: '' }) → this.props.onClear...
--フッタ
// ===== Redux connect =====
const mapStateToProps = (state: RootState): StateProps =...
message: state.crudSample.message,
});
const mapDispatchToProps = (dispatch: AppDispatch): Disp...
onSetMessage: (msg: string) => dispatch(setMessage(msg...
onClearMessage: () => dispatch(clearMessage()),
});
export default connect(mapStateToProps, mapDispatchToPro...
**同様にAboutを修正 [#e29b5de3]
同様に
import { useSelector } from 'react-redux'
import type { RootState } from '../store'
export default function About() {
// Reduxのstoreから値を取得
const count = useSelector((state: RootState) => state....
const message = useSelector((state: RootState) => stat...
return <div>
<h1>About</h1>
<p>About Pageです。</p>
{/* countを表示 */}
<p>現在のカウント: {count}</p>
{/* messageを表示 */}
<p>現在のメッセージ: {message}</p>
</div>
}
*参考 [#u1559c3a]
-FrontendTemplates/UI/SPA/React at develop · OpenTouryoPr...
https://github.com/OpenTouryoProject/FrontendTemplates/tr...
終了行:
「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfras...
-戻る([[React]] -> [[Redux]])
--...[[Reactの5thステップ]]
--[[Reactのファースト・ステップ2]]
--[[Reactのセカンド・ステップ2]]
--Reactのサード・ステップ2
*目次 [#bf704575]
#contents
*概要 [#rbd0d9e0]
引き続き[[Redux]]対応を行う。
*詳細 [#k95528b7]
**プロンプト [#gad08276]
CrudSampleとCrudSample2があるが、構成が複雑なCrudSample2...
以下のCrudSample2のmessageをRedux対応させたい。修正方法...
.\src\store\index.ts
.\src\store\counterSlice.ts
.\src\pages\CrudSample2.tsx
.\src\components\CrudSample2\Buttons.tsx
.\src\components\CrudSample2\DropDownLists.tsx
.\src\components\CrudSample2\Inputs.tsx
.\src\components\CrudSample2\Outputs.tsx
```
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
export const store = configureStore({
reducer: {
counter: counterReducer,
},
})
// 型エクスポート(useSelector / useDispatch で使用)
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
```
```
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
interface CounterState {
value: number
}
const initialState: CounterState = {
value: 0,
}
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1
},
decrement: (state) => {
state.value -= 1
},
incrementByAmount: (state, action: PayloadAction<num...
state.value += action.payload
},
reset: (state) => {
state.value = 0
},
},
})
export const { increment, decrement, incrementByAmount, ...
export default counterSlice.reducer
```
```
import * as React from 'react';
import constants from '../const';
import common from '../common.ts';
import oauth_oidc from '../touryo/oauth_oidc';
import Inputs from '../components/CrudSample2/Inputs';
import DropDownLists from '../components/CrudSample2/Dro...
import Buttons from '../components/CrudSample2/Buttons';
import Outputs from '../components/CrudSample2/Outputs';
// ===== 型定義 =====
interface DdlState {
ddlDap: string;
ddlMode1: string;
ddlMode2: string;
ddlIso: string;
ddlExRollback: string;
ddlOrder: string;
ddlOrderSequence: string;
}
interface ShipperState {
shipperID: string;
companyName: string;
phone: string;
}
interface CrudSample2State {
message: string;
ddl: DdlState;
shipper: ShipperState;
shippers: ShipperState[];
loading: boolean;
}
// ===== コンポーネント =====
export class CrudSample2 extends React.Component<Record<...
{
constructor(props: Record<string, never>) {
super(props);
this.state = {
message: '',
ddl: {
ddlDap: 'SQL',
ddlMode1: 'individual',
ddlMode2: 'static',
ddlIso: 'NT',
ddlExRollback: '-',
ddlOrder: 'c1',
ddlOrderSequence: 'A',
},
shipper: {
shipperID: '',
companyName: '',
phone: '',
},
shippers: [
{
shipperID: '',
companyName: '',
phone: '',
},
],
loading: true,
};
}
// ===== render =====
render() {
const containerStyle: React.CSSProperties = { textAl...
const div0Style: React.CSSProperties = {};
const div1Style: React.CSSProperties = { display: 'i...
const div2Style: React.CSSProperties = { display: 'i...
return (
<div style={containerStyle}>
<h1>CRUD sample</h1>
<p>This component demonstrates CRUD.</p>
<div style={div0Style}>
<DropDownLists onChangeDdl={(e) => this.receiv...
</div>
<div style={div1Style}>
<Inputs
shipper={this.state.shipper}
onChangeInput={(e) => this.receiveInputChang...
/>
</div>
<div style={div2Style}>
<Outputs
loading={this.state.loading}
shippers={this.state.shippers}
message={this.state.message}
/>
</div>
<div>
<Buttons
onClickButton={(e) => this.receiveButtonClic...
/>
</div>
</div>
);
}
// ─── 子コンポーネントからのイベント受信 ────────────...
receiveDDLChanged(ddl: Partial<CrudSample2State>): voi...
this.setState(ddl as CrudSample2State);
}
receiveInputChanged(shipper: Partial<CrudSample2State>...
this.setState(shipper as CrudSample2State);
}
receiveButtonClick(actionType: string): void {
switch (actionType) {
case 'SelectCount': this.selectCount(); retu...
case 'SelectAll_DT': this.selectAll_DT(); retu...
case 'SelectAll_DS': this.selectAll_DS(); retu...
case 'SelectAll_DR': this.selectAll_DR(); retu...
case 'SelectAll_DSQL': this.selectAll_DSQL(); retu...
case 'Select': this.select(); retu...
case 'Insert': this.insert(); retu...
case 'Update': this.update(); retu...
case 'Delete': this.delete(); retu...
default: return;
}
}
// ===== WebAPI イベントハンドラ =====
selectCount() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'SelectCount',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollba...
(data) => {
if (data.message) {
this.setState({ message: JSON.stringify(data.m...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
selectAll_DT() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'SelectAll_DT',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollba...
(data) => {
if (data.result) {
this.setState({ message: '', shippers: data.re...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
selectAll_DS() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'selectAll_DS',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollba...
(data) => {
if (data.result) {
this.setState({ message: '', shippers: data.re...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
selectAll_DR() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'selectAll_DR',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollba...
(data) => {
if (data.result) {
this.setState({ message: '', shippers: data.re...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
selectAll_DSQL() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'selectAll_DSQL',
oauth_oidc.createHttpRequestHeader(false),
'ddlDap=' + this.state.ddl.ddlDap
+ '&ddlMode1=' + this.state.ddl.ddlMode1
+ '&ddlMode2=' + this.state.ddl.ddlMode2
+ '&ddlExRollback=' + this.state.ddl.ddlExRollback
+ '&orderColumn=' + this.state.ddl.ddlOrder
+ '&orderSequence=' + this.state.ddl.ddlOrderSeq...
(data) => {
if (data.result) {
this.setState({ message: '', shippers: data.re...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
select() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'select',
oauth_oidc.createHttpRequestHeader(true),
JSON.stringify({
ddlDap: this.state.ddl.ddlDap,
ddlMode1: this.state.ddl.ddlMode1,
ddlMode2: this.state.ddl.ddlMode2,
ddlExRollback: this.state.ddl.ddlExRollback,
shipper: {
shipperID: this.state.shipper.shipperID,
companyName: '',
phone: '',
},
}),
(data) => {
if (data.result) {
const result = data.result as ShipperState;
this.setState({
shipper: {
shipperID: result.shipperID,
companyName: result.companyName,
phone: result.phone,
},
});
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
insert() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'insert',
oauth_oidc.createHttpRequestHeader(true),
JSON.stringify({
ddlDap: this.state.ddl.ddlDap,
ddlMode1: this.state.ddl.ddlMode1,
ddlMode2: this.state.ddl.ddlMode2,
ddlExRollback: this.state.ddl.ddlExRollback,
shipper: {
shipperID: '0',
companyName: this.state.shipper.companyName,
phone: this.state.shipper.phone,
},
}),
(data) => {
if (data.message) {
this.setState({ message: JSON.stringify(data.m...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
update() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'update',
oauth_oidc.createHttpRequestHeader(true),
JSON.stringify({
ddlDap: this.state.ddl.ddlDap,
ddlMode1: this.state.ddl.ddlMode1,
ddlMode2: this.state.ddl.ddlMode2,
ddlExRollback: this.state.ddl.ddlExRollback,
shipper: {
shipperID: this.state.shipper.shipperID,
companyName: this.state.shipper.companyName,
phone: this.state.shipper.phone,
},
}),
(data) => {
if (data.message) {
this.setState({ message: JSON.stringify(data.m...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
delete() {
this.setState({ message: '' });
common.postFetch(
constants.CrudSampleRootUrl + 'delete',
oauth_oidc.createHttpRequestHeader(true),
JSON.stringify({
ddlDap: this.state.ddl.ddlDap,
ddlMode1: this.state.ddl.ddlMode1,
ddlMode2: this.state.ddl.ddlMode2,
ddlExRollback: this.state.ddl.ddlExRollback,
shipper: {
shipperID: this.state.shipper.shipperID,
companyName: '',
phone: '',
},
}),
(data) => {
if (data.message) {
this.setState({ message: JSON.stringify(data.m...
}
},
(msg) => this.setState({ message: JSON.stringify(m...
);
}
}
```
```
import * as React from 'react';
// 型定義
interface Shipper {
shipperID: string;
companyName: string;
phone: string;
}
interface OutputsProps {
shippers: Shipper[];
loading: boolean;
message?: string;
}
interface OutputsState {
shippers: Shipper[];
loading: boolean;
message?: string;
}
export class Outputs extends React.Component<OutputsProp...
// constructor
constructor(props: OutputsProps) {
super(props);
this.state = {
shippers: [
{
shipperID: '',
companyName: '',
phone: '',
},
],
loading: true,
message: undefined,
};
}
// lifecycle
// componentWillReceiveProps は非推奨のため getDerived...
static getDerivedStateFromProps(
newProps: OutputsProps
): OutputsState {
return {
loading: newProps.loading,
shippers: newProps.shippers,
message: newProps.message,
};
}
// render
render() {
let contents: React.ReactNode = null;
if (this.state.loading) {
contents = (
<p>
<em>...Table...</em>
</p>
);
} else {
contents = (
<table className="table">
<thead>
<tr>
<th>ShipperID</th>
<th>CompanyName</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
{this.state.shippers.map((shipper) => (
<tr key={shipper.shipperID}>
<td>{shipper.shipperID}</td>
<td>{shipper.companyName}</td>
<td>{shipper.phone}</td>
</tr>
))}
</tbody>
</table>
);
}
return (
<div>
{contents}
<p>処理結果:{this.state.message}</p>
</div>
);
}
}
export default Outputs;
```
```
import * as React from 'react';
// Propsの型定義
interface ButtonsProps {
onClickButton: (actionType: string) => void;
}
export class Buttons extends React.Component<ButtonsProp...
constructor(props: ButtonsProps) {
super(props);
}
render() {
return (
<div>
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
<button className='btn-primary' onClick=...
</div>
);
}
onClickButton(actionType: string): void {
this.props.onClickButton(actionType);
}
}
export default Buttons;
```
**修正内容 [#e4537aef]
crudSample2Sliceは、crudSample、crudSample2で共用するため...
-先ずは「store」の内容
--crudSample2Slice.ts
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
interface CrudSample2SliceState {
message: string;
}
const initialState: CrudSample2SliceState = {
message: '',
}
const crudSample2Slice = createSlice({
name: 'crudSample2',
initialState,
reducers: {
setMessage: (state, action: PayloadAction<string>) =...
state.message = action.payload;
},
clearMessage: (state) => {
state.message = '';
},
},
})
export const { setMessage, clearMessage } = crudSample2S...
export default crudSample2Slice.reducer
--index.ts
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
import crudSample2Reducer from './crudSample2Slice' // ...
export const store = configureStore({
reducer: {
counter: counterReducer,
crudSample2: crudSample2Reducer, // ← 追加
},
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
-CrudSample2.tsx
--ヘッダ
// Redux 関連のインポート
import { connect } from 'react-redux';
import type { RootState, AppDispatch } from '../store';
import { setMessage, clearMessage } from '../store/crudS...
// ===== 型定義 =====
// Propsの型定義
interface StateProps {
message: string;
}
interface DispatchProps {
onSetMessage: (msg: string) => void;
onClearMessage: () => void;
}
// コンポーネント自身のProps(connect後に外から渡すもの...
type CrudSampleProps = StateProps & DispatchProps;
...
interface CrudSample2State {
//message: string; は Redux管理のため削除
ddl: DdlState;
shipper: ShipperState;
shippers: ShipperState[];
loading: boolean;
}
--ボディ
---クラス冒頭部
export class CrudSample2 extends React.Component<CrudSam...
{
constructor(props: CrudSampleProps) {//Record<string, ...
super(props);
this.state = {
// message: '', は Redux管理のため削除
---Render部
this.props.message → this.state.message
---イベントハンドラ
// ===== WebAPI イベントハンドラ =====
// this.setState({ message: ... }) → this.props.onSetMe...
// this.setState({ message: '' }) → this.props.onClear...
--フッタ
// ===== Redux connect =====
const mapStateToProps = (state: RootState): StateProps =...
message: state.crudSample.message,
});
const mapDispatchToProps = (dispatch: AppDispatch): Disp...
onSetMessage: (msg: string) => dispatch(setMessage(msg...
onClearMessage: () => dispatch(clearMessage()),
});
export default connect(mapStateToProps, mapDispatchToPro...
**同様にAboutを修正 [#e29b5de3]
同様に
import { useSelector } from 'react-redux'
import type { RootState } from '../store'
export default function About() {
// Reduxのstoreから値を取得
const count = useSelector((state: RootState) => state....
const message = useSelector((state: RootState) => stat...
return <div>
<h1>About</h1>
<p>About Pageです。</p>
{/* countを表示 */}
<p>現在のカウント: {count}</p>
{/* messageを表示 */}
<p>現在のメッセージ: {message}</p>
</div>
}
*参考 [#u1559c3a]
-FrontendTemplates/UI/SPA/React at develop · OpenTouryoPr...
https://github.com/OpenTouryoProject/FrontendTemplates/tr...
ページ名: