[React] 初心者講座01 <create-react-app>
Recoil(Reactの状態管理)に興味があるのでReactのTemplateが欲しくなった。
せっかくなのでTemplate作成手順をまとめる。
ReduxとかMiddlewareとかはふれない。
Recoilもまだ、さわれていない。
目標
- create-react-appができる
- router下準備ができる
完成形
2021/11月現在、ヘッダしかない。
ソースは以下。
nodeは以下のverにアップデートしてから実装。
$ node -v
v16.13.0
$ npm -v
8.1.0
$ npx create-react-app --version
4.0.3
create-react-app
まずはcreate-react-app
typescript
で作成する。cra-sample
部分は好きな名前で良い。
craはcreate-react-appの頭文字をとった。
$ npx create-react-app cra-sample --template typescript
VSCode起動時にtsconfig.json
とApp.tsx
に以下のエラーが出た。
--jsx' オプションの引数は 'preserve', 'react-native', 'react' である必要があります。
--jsx' フラグが指定されていないと、JSX を使用できません。
解決方法は、tsx
ファイルを選択しているときVScodeの右下にTypeScriptのverが表示されている。
クリックでver変更でき、3.8.3
→4.4.4
にしたら直った。
起動してみる。http://localhost:3000/
で見れる。
$ npm start
Prettier and ESLint
とりあえずlinterを入れておく。
$ ./node_modules/.bin/eslint --init
✔ How would you like to use ESLint? -> To check syntax, find problems
✔ What type of modules does your project use? -> JavaScript modules (import/export)
✔ Which framework does your project use? -> React
✔ Does your project use TypeScript? -> Yes
✔ Where does your code run? · Browser
✔ What format do you want your config file to be in? -> JavaScript
✔ Would you like to install them now with npm? -> Yes
$ npm install --save-dev eslint-plugin-react @typescript-eslint/parser @typescript-eslint/eslint-plugin
$ npm install --save-dev prettier eslint-plugin-prettier eslint-config-prettier
$ echo {}> .prettierrc.json
$ echo > .prettierignore
{
"printWidth": 100,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "all"
}
build
coverage
サブディレクトリ
src直下に以下の構成でサブディレクトリを作成する。
ついでにApp.tsx
もviews
直下に移動しておく。
さらについでにtestファイルは今は不要なので消す。
- src/
- views/
- atoms/
- organisms/
- ecosystems/
- environments/
- views/
MUI(Material-UI)
デザインシステムとしてMUI(Material-UI)
を入れる。
MUI v5よりemotion
or styled-components
が必須になった。
[参考]npm trands:@emotion/styled vs styled-components
$ npm install @mui/material @emotion/react @emotion/styled
アイコンはMaterial icons
。SVGなので伸縮してもキレイ。
$ npm install @mui/icons-material
package.jsonメモ
"@mui/material": "^5.1.1"
""@emotion/react": "^11.6.0"
@emotion/styled": "^11.6.0"
試しにButton
を表示する。使い方は公式を見る。
App.tsxを少し書き換えた。<Box>
タグはMUIにおける便利な<div>
タグ。
Componentの書き方の解説はもう少し後にする。
import React from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
const App: React.VFC = () => {
return (
<Box>
<Box>Create React App Sample</Box>
<Button variant="contained">Test!</Button>
</Box>
);
};
export default App;
MUIのstyleを変えれるようにThemingを導入する。
createTheme
内でpalette
をいじるとベースカラーを変更できる。
import { createTheme } from '@mui/material/styles';
import { blueGrey, green } from '@mui/material/colors';
const theme = createTheme({
palette: {
primary: {
main: green[500],
},
},
components: {
MuiCssBaseline: {
styleOverrides: {
body: {
backgroundColor: blueGrey[50],
},
},
},
},
});
export default theme;
theme.ts
はviews直下に配置しておいて、index.ts
にimportする。
ついでにCssBaselineも入れる。
import { CssBaseline, ThemeProvider } from '@mui/material';
import theme from './views/theme';
...
ReactDOM.render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<CssBaseline />
<App />
</ThemeProvider>
</React.StrictMode>,
document.getElementById('root'),
);
ところでMUIのButtonはデフォルトのstyleでtext-transform: uppercase;
が設定されているため、英文字はすべて大文字になる。
不要だったら以下のように書き換えてしまってもよい。
const theme = createTheme({
components: {
MuiButton: {
styleOverrides: {
root: {
textTransform: 'none',
},
},
},
},
});
paletteについては公式のカラーパレットを使ってもいいし、カラーパレットのサイトを参考にしても良い。
以下、抜粋。
ルーティング
$ npm install react-router-dom@5
$ npm install --save-dev @types/react-router-dom
App.tsx
で表示させたいComponentをBrowserRouter
Switch
Route
でラップする。
以下の例では起動時のパスが/
なのでcra-app
にRedirectし<Home />
を表示する。
exact
strict
sensitive
等はpathをどれだけ正確に判定するかの属性でこちらで詳細を確認できる。
import React from 'react';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import Home from './environments/Home';
const App: React.VFC = () => {
return (
<BrowserRouter>
<Switch>
<Redirect exact strict from="/" to="/cra-app" />
<Route sensitive path="/cra-app">
<Home />
</Route>
</Switch>
</BrowserRouter>
);
};
<Home />
のルーティングの仕組みをざっくり作ってしまう。
以下は<App />
からRedirectで<Home />
に遷移したあと、またRedirectで<DashboardView />
に遷移している。
<DataListView />
にもpathを与える。
const Home: React.VFC = () => {
const { path } = useRouteMatch();
return (
<Box>
<Box>Create React App Sample</Box>
<Switch>
<Route exact sensitive path={`${path}`}>
<Redirect to={`${path}/dashboard`} />
</Route>
<Route exact sensitive path={`${path}/dashboard`}>
<DashboardView />
</Route>
<Route exact sensitive path={`${path}/data-list`}>
<DataListView />
</Route>
</Switch>
</Box>
);
};
import React from 'react';
import Box from '@mui/material/Box';
const DashboardView: React.VFC = () => {
return <Box>DashboardView</Box>;
};
export default DashboardView;
import React from 'react';
import Box from '@mui/material/Box';
const DataListView: React.VFC = () => {
return <Box>DataListView</Box>;
};
export default DataListView;
ボタンを押すことでの遷移処理は未実装だが、urlの末尾を
http://localhost:3000/cra-app/dashboard
http://localhost:3000/cra-app/data-list
のように直接書き換えると画面の表示が切り替わっていることを確認できる。
このとき、Create React App Sample
は常に表示されていることが分かる。
ここをに共通ヘッダComponentを定義すれば常に表示されることになる。
遷移処理はもう少し後に記述する。
基本の画面レイアウトを実装
画面レイアウトは以下のようにする。
scrollに応じてヘッダが隠れたりするものが流行っている気もするが今回は固定。
上図の黒枠部分のComponentをatoms
に実装。
Componentの基本的な書き方はこれらの後に説明する。
import React from 'react';
import Box from '@mui/material/Box';
type AppContainerProps = {
children: React.ReactNode;
};
const AppContainer: React.VFC<AppContainerProps> = (props) => {
return (
<Box display="flex" flexDirection="column" height="100vh">
{props.children}
</Box>
);
};
export default AppContainer;
同様に赤枠部分のcomponentの実装。
const MainContainer: React.VFC<MainContainerProps> = (props) => {
return (
{/* marginとか余白はまた今度 */}
<Box flexGrow={1} sx={{ overflowY: 'auto' }}>
{props.children}
</Box>
);
};
ついでに青枠部分のヘッダComponentをorganisms
に仮実装する。
ヘッダは複数作らない気がするので、サブディレクトリは作らない。増えたらまた考える。
ここでポイントとなっているのはヘッダに表示するアプリ名をpropsで受け取っていること。
organisms
Componentの責務は「レイアウトを整えて表示」することである。
import React from 'react';
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import Box from '@mui/material/Box';
type AppHeaderProps = {
appTitle: string;
};
const AppHeader: React.VFC<AppHeaderProps> = (props) => {
return (
<AppBar position="static">
<Toolbar>
<Box>{props.appTitle}</Box>
</Toolbar>
</AppBar>
);
};
export default AppHeader;
上記のComponentを組み込んだ<Home />
が以下。
const Home: React.VFC = () => {
const { path } = useRouteMatch();
return (
<AppContainer>
<AppHeader appTitle="Create React App Sample" />
<MainContainer>
<Switch>
<Route exact sensitive path={`${path}`}>
<Redirect to={`${path}/dashboard`} />
</Route>
<Route exact sensitive path={`${path}/dashboard`}>
<DashboardView />
</Route>
<Route exact sensitive path={`${path}/data-list`}>
<DataListView />
</Route>
</Switch>
</MainContainer>
</AppContainer>
);
};
続き
Discussion