EditorConfig, ESLint, Prettierによって記法を統一、自動整形をおこないます。
tsconfig.jsonは、Nextが生成するものに paths
と baseUrl
を追加したものを使用します。
要件に応じて.envを導入します。
https://github.com/motdotla/dotenv#readme
Next.js開発元であるZEIT製のZEIT Nowを使用。
https://zeit.co/
以下のコマンドを実行後、out/
ディレクトリにSPAが生成されます。
yarn run build && yarn run export
Next.jsに備わるDynamic Routingを使用していきます。
https://nextjs.org/docs/routing/dynamic-routes
pages/
ディレクトリ配下のファイル名 = URLとなります。
基本的な例
pages/index.tsx → localhost:3000/
pages/detail.tsx → localhost:3000/detail
動的ルーティングの例
pages/post/[pid].js → localhost:3000/post/1
以下のように pid
を取得できます。
import { useRouter } from 'next/router'
const Post = () => {
const router = useRouter()
const { pid } = router.query
return <p>Post: {pid}</p>
}
export default Post
Redux Toolkitを使用したスタイルを採用。
Reduxの公式スタイルガイドで、Redux Toolkitの使用が推奨されています。
https://redux.js.org/style-guide/style-guide/#use-redux-toolkit-for-writing-redux-logic
非同期処理については、redux-thunkやredux-sagaを用いず、カスタムフックを作成します。
https://qiita.com/Naturalclar/items/6157d0b031bbb00b3c73
カスタムフックは src/hooks/
フォルダ配下で管理します。
Redux DevTools Extensionを用いて検証をおこないます。 https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=ja
styled-componentsを使用します。
カラーやサイズなどの共通化できるものは src/utils/styles/
で管理します。
(styled-componentsのthemingは記述が冗長になるので使用しません。)
グローバルなスタイルは src/utils/styles/GlobalStyle.ts
に記述します。
各コンポーネントごとのスタイルは以下のようにします。
import styled from 'styled-components'
const Component = () => (
<div>
hoge
<p>fuga</p>
</div>
)
const StyledComponent = styled(Component)`
color: red;
> p {
color: blue;
}
`
以下のような5層でコンポーネントを構成します。
// (1) import層
import React from 'react'
import styled from 'styled-components'
// (2) Types層
type ContainerProps = {...}
type Props = {...} & ContainerProps
// (3) DOM層
const Component: React.FC<Props> = props => (...)
// (4) Style層
const StyledComponent = styled(Component)`...`
// (5) Container層
const Container: React.FC<ContainerProps> = props => {
return <StyledComponent {...props} />
}
Style層で >
が2つまでであれば見通しが良いですが、
それ以上深くなる場合は、別コンポーネントとして切り出すべきタイミングとなります。
const StyledComponent = styled(Component)`
> * > * > button {...}
`
↑ >
が3つ続いているため、このあたりで切り出す目安とします。
参照:https://qiita.com/Takepepe/items/41e3e7a2f612d7eb094a
UsersListItem.tsx
といった命名はせずに、
users/list/item/index.tsx
のようにディレクトリを切る構成にします。
参照:https://qiita.com/Takepepe/items/41e3e7a2f612d7eb094a#comment-905be26e139a8fb1e9cb
users
├── index.tsx
├── title.tsx
└── list
├── index.tsx
├── title.tsx
└── item
├── index.tsx
├── title.tsx
├── avatar.tsx
└── icon.svg
Vue.jsスタイルガイドにあるルールを参考にしますが、
上述のとおりパスカルケースやケバブケースは用いずにディレクトリを切ってしまう方針です。
axiosを用いて非同期通信をおこないますが、
ラップしたリクエストを担うモジュールを、src/utils/request/
に実装しています。
今後、axios以外に乗り換えたい!となったとしても同じインターフェースを実装すれば交換できる構成としています。
src/api/
フォルダ配下で、エンドポイントごとに関数化したファイルを管理し、
APIに関するコードの一貫性向上、APIの変更に備えます。
// src/api/getUserData.js
import request from '~/utils/request'
function getUserData({ userId }) {
const path = `/users/${userId}`
return request.get(path)
}
export default getUserData
// src/api/updateUserData.js
import request from '~/utils/request'
function updateUserData({ userId, data }) {
const path = `/users/${userId}`
return request.put(path, { data })
}
export default updateUserData
1ファイル1関数1export。(パスが一緒でもMethodが異なれば別の関数にします。)
名前をつけることで、パスやMethodを見なくても何をするものか推測しやすくなります。
また、TypeScriptによるエディタの補完が効くようになります。