質問編集履歴
2
不要な文言や誤りを修正しました。
test
CHANGED
File without changes
|
test
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
### 前提
|
2
2
|
|
3
3
|
- ag-grid-reactを利用したいです。
|
4
|
-
- ディレクトリやルーティング構成等は `bulletproof-react` を参考にさせて頂いています。
|
5
4
|
- ソースコード内の「OlympicData」は、ag-grid のサンプルコード、APIを使用しています。
|
6
5
|
|
7
6
|
### 実現したいこと
|
8
7
|
|
9
|
-
- ag-gridを描画したい
|
8
|
+
- ag-gridを描画したいです。。
|
10
9
|
|
11
10
|
### 発生している問題・エラーメッセージ
|
12
11
|
|
13
|
-
-
|
12
|
+
- 埋込の文字列「Grid」は表示されるものの、ag-gridが描画されません。コンソールログで警告等は表示されていません。
|
14
13
|
- devtoolsで確認したところ、コンポーネントとしては認識されているようです。
|
15
14
|

|
16
15
|
|
@@ -73,7 +72,7 @@
|
|
73
72
|
}, []);
|
74
73
|
return (
|
75
74
|
<>
|
76
|
-
Grid
|
75
|
+
Grid <!-- ←この文字列は表示される-->
|
77
76
|
<div style={containerStyle}>
|
78
77
|
<div style={gridStyle} className="ag-theme-alpine">
|
79
78
|
<AgGridReact<IOlympicData>
|
1
問題をシンプルに書き直しました。
test
CHANGED
File without changes
|
test
CHANGED
@@ -6,32 +6,90 @@
|
|
6
6
|
|
7
7
|
### 実現したいこと
|
8
8
|
|
9
|
-
- ag-grid
|
9
|
+
- ag-gridを描画したいだけです。。
|
10
10
|
|
11
11
|
### 発生している問題・エラーメッセージ
|
12
12
|
|
13
|
-
Headerや埋込の文字列は表示されるものの、ag-grid
|
13
|
+
- Headerや埋込の文字列は表示されるものの、ag-gridが描画されません。コンソールログで警告等は表示されていません。
|
14
|
-
コンソールログで警告等は表示されていません。
|
15
|
-

|
16
|
-
devtoolsで確認したところ、コンポーネントとしては認識されているようです。
|
14
|
+
- devtoolsで確認したところ、コンポーネントとしては認識されているようです。
|
17
15
|

|
18
16
|
|
19
17
|
### 該当のソースコード
|
20
18
|
|
21
|
-
関連コードが多く恐縮ですが、動的ルーティングのうえでag-gridの描画を実現したく、問題の勘所等、ご教示頂けますと幸いです。
|
22
|
-
|
23
19
|
src/App.tsx
|
24
20
|
```tsx
|
25
|
-
import {
|
21
|
+
import { useCallback, useMemo, useState } from 'react';
|
26
|
-
import { A
|
22
|
+
import { AgGridReact } from 'ag-grid-react';
|
23
|
+
import { ColDef, GridReadyEvent } from 'ag-grid-community';
|
27
24
|
|
25
|
+
import 'ag-grid-community/styles/ag-grid.css';
|
26
|
+
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
27
|
+
|
28
|
+
export interface IOlympicData {
|
29
|
+
athlete: string;
|
30
|
+
age: number;
|
31
|
+
country: string;
|
32
|
+
year: number;
|
33
|
+
date: string;
|
34
|
+
sport: string;
|
35
|
+
gold: number;
|
36
|
+
silver: number;
|
37
|
+
bronze: number;
|
38
|
+
total: number;
|
39
|
+
}
|
40
|
+
|
28
|
-
|
41
|
+
export const App = () => {
|
42
|
+
|
43
|
+
const containerStyle = useMemo(() => ({ width: '100%', height: '100%' }), []);
|
44
|
+
const gridStyle = useMemo(() => ({ height: '100%', width: '100%' }), []);
|
45
|
+
const [rowData, setRowData] = useState<IOlympicData[]>();
|
46
|
+
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
|
47
|
+
{ field: 'athlete', minWidth: 150 },
|
48
|
+
{ field: 'age', minWidth: 50, filter: 'agNumberColumnFilter' },
|
49
|
+
{ field: 'country', width: 120 },
|
50
|
+
{ field: 'year', width: 90 },
|
51
|
+
{ field: 'date', width: 110 },
|
52
|
+
{ field: 'sport', width: 110 },
|
53
|
+
{ field: 'gold', width: 110 },
|
54
|
+
{ field: 'silver', width: 110 },
|
55
|
+
{ field: 'bronze', width: 110 },
|
56
|
+
]);
|
57
|
+
const defaultColDef = useMemo<ColDef>(() => {
|
58
|
+
return {
|
59
|
+
editable: true,
|
60
|
+
sortable: true,
|
61
|
+
flex: 1,
|
62
|
+
minWidth: 100,
|
63
|
+
filter: true,
|
64
|
+
resizable: true,
|
65
|
+
};
|
66
|
+
}, []);
|
67
|
+
|
68
|
+
const onGridReady = useCallback((params: GridReadyEvent) => {
|
69
|
+
console.log('onGridReady called.')
|
70
|
+
fetch('https://www.ag-grid.com/example-assets/olympic-winners.json')
|
71
|
+
.then((resp) => resp.json())
|
72
|
+
.then((data: IOlympicData[]) => setRowData(data.slice(0, 600)));
|
73
|
+
}, []);
|
29
74
|
return (
|
75
|
+
<>
|
76
|
+
Grid
|
77
|
+
<div style={containerStyle}>
|
78
|
+
<div style={gridStyle} className="ag-theme-alpine">
|
79
|
+
<AgGridReact<IOlympicData>
|
80
|
+
rowData={rowData}
|
81
|
+
columnDefs={columnDefs}
|
82
|
+
defaultColDef={defaultColDef}
|
83
|
+
ensureDomOrder={true}
|
84
|
+
suppressColumnVirtualisation={true}
|
85
|
+
suppressRowVirtualisation={true}
|
86
|
+
onGridReady={onGridReady}
|
30
|
-
<A
|
87
|
+
></AgGridReact>
|
31
|
-
<AppRoutes />
|
32
|
-
</
|
88
|
+
</div>
|
89
|
+
</div>
|
90
|
+
</>
|
33
91
|
);
|
34
|
-
}
|
92
|
+
};
|
35
93
|
|
36
94
|
export default App;
|
37
95
|
```
|
@@ -54,231 +112,13 @@
|
|
54
112
|
```
|
55
113
|
|
56
114
|
|
57
|
-
src/routes/index.tsx
|
58
|
-
```tsx
|
59
|
-
import { useRoutes } from 'react-router-dom';
|
60
|
-
import { publicRoutes } from './public';
|
61
|
-
|
62
|
-
export const AppRoutes = () => {
|
63
|
-
const element = useRoutes([...publicRoutes]);
|
64
|
-
return <>{element}</>;
|
65
|
-
};
|
66
|
-
```
|
67
|
-
|
68
|
-
src/routes/public.tsx
|
69
|
-
```tsx
|
70
|
-
import { Suspense } from 'react';
|
71
|
-
import { Navigate, Outlet } from 'react-router-dom';
|
72
|
-
|
73
|
-
import { Spinner } from '@/components/Elements';
|
74
|
-
import { MainLayout } from '@/components/Layout';
|
75
|
-
import { lazyImport } from '@/utils/lazyImport';
|
76
|
-
|
77
|
-
const { OlympicDataRoutes } = lazyImport(
|
78
|
-
() => import('@/features/example'),
|
79
|
-
'OlympicDataRoutes'
|
80
|
-
);
|
81
|
-
|
82
|
-
const App = () => {
|
83
|
-
return (
|
84
|
-
<MainLayout>
|
85
|
-
<Suspense
|
86
|
-
fallback={
|
87
|
-
<div className="h-full w-full flex items-center justify-center">
|
88
|
-
<Spinner />
|
89
|
-
</div>
|
90
|
-
}
|
91
|
-
>
|
92
|
-
<Outlet />
|
93
|
-
</Suspense>
|
94
|
-
</MainLayout>
|
95
|
-
);
|
96
|
-
};
|
97
|
-
|
98
|
-
export const publicRoutes = [
|
99
|
-
{
|
100
|
-
path: '/app',
|
101
|
-
element: <App />,
|
102
|
-
children: [
|
103
|
-
{ path: '/app/example/*', element: <OlympicDataRoutes /> },
|
104
|
-
{ path: '*', element: <Navigate to="." /> },
|
105
|
-
],
|
106
|
-
},
|
107
|
-
];
|
108
|
-
```
|
109
|
-
src/utils/lazyImport.ts
|
110
|
-
```Typescript
|
111
|
-
import * as React from 'react';
|
112
|
-
|
113
|
-
// named imports for React.lazy: https://github.com/facebook/react/issues/14603#issuecomment-726551598
|
114
|
-
export function lazyImport<
|
115
|
-
T extends React.ComponentType<any>,
|
116
|
-
I extends { [K2 in K]: T },
|
117
|
-
K extends keyof I
|
118
|
-
>(factory: () => Promise<I>, name: K): I {
|
119
|
-
return Object.create({
|
120
|
-
[name]: React.lazy(() => factory().then((module) => ({ default: module[name] }))),
|
121
|
-
});
|
122
|
-
}
|
123
|
-
```
|
124
|
-
src/features/example/routes/index.tsx
|
125
|
-
```tsx
|
126
|
-
import { Route, Routes } from 'react-router-dom';
|
127
|
-
|
128
|
-
import { OlympicData} from './OlympicData';
|
129
|
-
|
130
|
-
export const OlympicDataRoutes = () => {
|
131
|
-
return (
|
132
|
-
<Routes>
|
133
|
-
<Route path="olympic" element={<OlympicData/>} />
|
134
|
-
</Routes>
|
135
|
-
);
|
136
|
-
};
|
137
|
-
```
|
138
|
-
|
139
|
-
src/components/Layout/MainLayout.tsx
|
140
|
-
```tsx
|
141
|
-
import * as React from 'react';
|
142
|
-
|
143
|
-
type MainLayoutProps = {
|
144
|
-
children: React.ReactNode;
|
145
|
-
};
|
146
|
-
|
147
|
-
export const MainLayout = ({ children }: MainLayoutProps) => {
|
148
|
-
return (
|
149
|
-
<main>{children}</main>
|
150
|
-
);
|
151
|
-
};
|
152
|
-
```
|
153
|
-
src/features/example/components/Layout.tsx
|
154
|
-
```tsx
|
155
|
-
import * as React from 'react';
|
156
|
-
|
157
|
-
import Header from '@/components/Layout/GlobalNavBar';
|
158
|
-
|
159
|
-
type LayoutProps = {
|
160
|
-
children: React.ReactNode;
|
161
|
-
title: string;
|
162
|
-
};
|
163
|
-
|
164
|
-
export const Layout = ({ children, title }: LayoutProps) => {
|
165
|
-
return (
|
166
|
-
<>
|
167
|
-
<Header sections={[]} title="Example"/>
|
168
|
-
<div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
|
169
|
-
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
170
|
-
<h2 className="mt-3 text-center text-3xl font-extrabold text-gray-900">{title}</h2>
|
171
|
-
</div>
|
172
|
-
|
173
|
-
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
174
|
-
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">{children}</div>
|
175
|
-
</div>
|
176
|
-
</div>
|
177
|
-
</>
|
178
|
-
);
|
179
|
-
};
|
180
|
-
```
|
181
|
-
|
182
|
-
|
183
|
-
src/features/example/routes/OlympicData.tsx
|
184
|
-
```tsx
|
185
|
-
import { Layout } from '../components/Layout';
|
186
|
-
import { OlympicDataForm } from '../components/OlympicDataForm ';
|
187
|
-
|
188
|
-
export const OlympicData = () => {
|
189
|
-
return (
|
190
|
-
<Layout title="OlympicData">
|
191
|
-
<OlympicDataForm />
|
192
|
-
</Layout>
|
193
|
-
);
|
194
|
-
};
|
195
|
-
```
|
196
|
-
|
197
|
-
src/features/example/components/OlympicDataForm.tsx
|
198
|
-
```tsx
|
199
|
-
import { useCallback, useMemo, useState } from 'react';
|
200
|
-
import { AgGridReact } from 'ag-grid-react';
|
201
|
-
import { ColDef, GridReadyEvent } from 'ag-grid-community';
|
202
|
-
|
203
|
-
import 'ag-grid-community/styles/ag-grid.css';
|
204
|
-
import 'ag-grid-community/styles/ag-theme-alpine.css';
|
205
|
-
|
206
|
-
export interface IOlympicData {
|
207
|
-
athlete: string;
|
208
|
-
age: number;
|
209
|
-
country: string;
|
210
|
-
year: number;
|
211
|
-
date: string;
|
212
|
-
sport: string;
|
213
|
-
gold: number;
|
214
|
-
silver: number;
|
215
|
-
bronze: number;
|
216
|
-
total: number;
|
217
|
-
}
|
218
|
-
export const OlympicDataForm = () => {
|
219
|
-
|
220
|
-
const containerStyle = useMemo(() => ({ width: '100%', height: '100%' }), []);
|
221
|
-
const gridStyle = useMemo(() => ({ height: '100%', width: '100%' }), []);
|
222
|
-
const [rowData, setRowData] = useState<IOlympicData[]>();
|
223
|
-
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
|
224
|
-
{ field: 'athlete', minWidth: 150 },
|
225
|
-
{ field: 'age', minWidth: 50, filter: 'agNumberColumnFilter' },
|
226
|
-
{ field: 'country', width: 120 },
|
227
|
-
{ field: 'year', width: 90 },
|
228
|
-
{ field: 'date', width: 110 },
|
229
|
-
{ field: 'sport', width: 110 },
|
230
|
-
{ field: 'gold', width: 110 },
|
231
|
-
{ field: 'silver', width: 110 },
|
232
|
-
{ field: 'bronze', width: 110 },
|
233
|
-
]);
|
234
|
-
const defaultColDef = useMemo<ColDef>(() => {
|
235
|
-
return {
|
236
|
-
editable: true,
|
237
|
-
sortable: true,
|
238
|
-
flex: 1,
|
239
|
-
minWidth: 100,
|
240
|
-
filter: true,
|
241
|
-
resizable: true,
|
242
|
-
};
|
243
|
-
}, []);
|
244
|
-
|
245
|
-
const onGridReady = useCallback((params: GridReadyEvent) => {
|
246
|
-
console.log('onGridReady called.')
|
247
|
-
fetch('https://www.ag-grid.com/example-assets/olympic-winners.json')
|
248
|
-
.then((resp) => resp.json())
|
249
|
-
.then((data: IOlympicData[]) => setRowData(data.slice(0, 600)));
|
250
|
-
}, []);
|
251
|
-
return (
|
252
|
-
<>
|
253
|
-
Grid
|
254
|
-
<div style={containerStyle}>
|
255
|
-
<div style={gridStyle} className="ag-theme-alpine">
|
256
|
-
<AgGridReact<IOlympicData>
|
257
|
-
rowData={rowData}
|
258
|
-
columnDefs={columnDefs}
|
259
|
-
defaultColDef={defaultColDef}
|
260
|
-
ensureDomOrder={true}
|
261
|
-
suppressColumnVirtualisation={true}
|
262
|
-
suppressRowVirtualisation={true}
|
263
|
-
onGridReady={onGridReady}
|
264
|
-
></AgGridReact>
|
265
|
-
</div>
|
266
|
-
</div>
|
267
|
-
</>
|
268
|
-
);
|
269
|
-
};
|
270
|
-
```
|
271
|
-
|
272
|
-
### 試したこと
|
273
|
-
|
274
|
-
- MainLayout.tsx に、ag-grid のコンポーネントを直書きしたところ、正しく描画されました。
|
275
|
-
|
276
115
|
### 補足情報(FW/ツールのバージョンなど)
|
277
|
-
|
116
|
+
利用ライブラリ・バージョン
|
278
117
|
- react@18.2.0
|
279
118
|
- react-dom@18.2.0
|
280
119
|
- ag-grid-community@28.2.1
|
281
120
|
- ag-grid-react@28.2.1
|
282
121
|
|
122
|
+
問題の勘所等をご教示頂きたく、よろしくお願い致します。
|
283
123
|
|
284
124
|
|