Closed11
Next.jsでアプリ作成(できた)
ピン留めされたアイテム
Todo + Counterアプリができた。
最初スタイルが崩れるのは原因不明。todoとcounterを行ったり来たりすると治る。
コードとプレビューを公開。
CodeSandboxすごい。
プレビューを見られない場合はこちら: https://codesandbox.io/s/unruffled-stonebraker-zwbf8
本番ビルド&公開にはVercelがやばい
- Vercelにプロダクションをビルドしたら直った。開発のときだけっぽい。
- ボタン一発でデプロイできるの凄すぎる。。
https://csb-zwbf8-ltnxfx1wz.vercel.app
技術構成
- Next.js
- TypeScript
- React Hooks
- Redux
- Redux ToolKit
- Material-UI
学び
- redux toolkit がとにかく便利。機能別でsliceを分けて管理すると見通しが良い。
- reduxのスタイルガイドを読み込んでstoreやreducerの設計を学ぶ。
- 今までreduxが難しそうと避けてたのがもったいない。FlutterのProviderパターンよりも、わかりやすい。今までボイラープレートを書く読むのがめんどくさかっただけ。非同期は今のところミドルウェアではなく、React Hooksの useEffect使った方がわかりやすい。HooksとRedux Toolkit(RTK)さまさま。
- redux DevToolsを使うにはRTKの configStore を使えばいいだけなのでそれも良い。
- Next.jsが環境やらrouterやら用意してくれるおかげで1秒で開発し始められるのすごい。
- material-uiが分かった。次はレイアウトもきっちりやりたい。気合が足りない。
Goal
Next.js で自社プロダクトをリリースする
習得したいこと
- TypeScript
- Redux
- Redux Toolkit
- 非同期処理にはHooks
- ドメイン駆動っぽくロジックを分離する
- material UI
- Firebase Auth
- Firestore をロジック分離して呼び出し
- styled-jsx+atomic Designによるコンポーネント指向UI組み立て
学習順
- Next.js, React Hooks, Redux, Redux Toolkit のチュートリアル、ガイドを読む
-
Counter App を作る
- hooksで作る
- redux を適用
- Todo App を作る
- Firebase Authでログイン
- Firestoreでtodo
進捗と詰まったところを投稿していく
- Next.js上でTypeScriptとReact Hooks でuseReducerを使いRedux風にカウンターアプリを作るまでできた
- _app.tsx上からreducerをページにpropsで渡そうと思ったが、無理そう。[できるかわからない]
// _app.tsx
function MyApp({ Component, pageProps }: AppProps) {
const [state, dispatch] = useReducer(countReducer, initialState)
return <Component {...pageProps} state={state} dispatch={dispatch} /> //こうやって渡すのは無理
}
// index.tsx
const Home: React.FC<Props> = ({ state, dispatch }) => {
console.log(state)
return (
<>
<h1>{state.number}</h1>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
)
}
export default Home
- 直接渡すのは無理なので、Provider, Contextで渡す。
- Context + Provider で, _app.js上からreducerとグローバルステートを渡す。
// _app.tsx
...
export type State = {
number: number
}
export type Action = {
type: string
}
const initialState = { number: 0 }
const countReducer = (state: State, action: Action): State => {...}
export const CounterContext = React.createContext(
{} as { state: State; dispatch: React.Dispatch<Action> }
)
function MyApp({ Component, pageProps }: AppProps) {
const [state, dispatch] = useReducer(countReducer, initialState)
return (
<CounterContext.Provider value={{ state, dispatch }}>
<Component {...pageProps} />
</CounterContext.Provider>
)
}
// index.tsx
...
export const Home: React.FC = () => {
const { state, dispatch } = useContext(CounterContext)
return (
<>
<h1>{state.number}</h1>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
)
}
- Material UIを導入。レイアウトのやり方が不慣れ。Flutterはシンプルでよかったな、、
import React, { useContext } from 'react'
import { CounterContext } from './_app'
import { Typography, Button, Grid } from '@material-ui/core'
export const Home: React.FC = () => {
const { state, dispatch } = useContext(CounterContext)
return (
<>
<Grid container alignItems="center" direction="column">
<Typography variant="h1">{state.number}</Typography>
<Grid container justify="center" spacing={2}>
<Button
variant="contained"
color="secondary"
onClick={() => dispatch({ type: 'decrement' })}
>
-
</Button>
<Button
variant="contained"
color="primary"
onClick={() => dispatch({ type: 'increment' })}
>
+
</Button>
</Grid>
</Grid>
</>
)
}
export default Home
- redux, redux-toolkitを導入し、グローバルstoreで状態を管理。
- redux-toolkitを使えば思ったより簡単にreduxが使える!楽!
// redux.ts
import { configureStore, createAction, createReducer } from '@reduxjs/toolkit'
export type State = {
number: number
}
const increment = createAction('increment')
const decrement = createAction('decrement')
const initialState = { number: 0 }
const countReducer = createReducer(initialState, {
[increment.type]: (state) => ({ number: state.number + 1 }),
[decrement.type]: (state) => ({ number: state.number - 1 }),
})
export const store = configureStore({ reducer: countReducer })
// _app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return (
<Provider store={store}>
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
</Provider>
)
}
// index.tsx
export const Home: React.FC = () => {
const count = useSelector((state: State) => state.number)
const dispatch = useDispatch()
...
}
- createSlice でactions, reducerを一気に生成して、関心ごとで分離したコードが書ける。便利い
- 少し書き直し。
// redux.ts
const counterSlice = createSlice({
name: 'count',
initialState,
reducers: {
increment: (state)=>{
state.number++
},
decrement:(state)=>{
state.number--
},
},
})
export const { increment, decrement } = counterSlice.actions
export const store = configureStore({ reducer: counterSlice.reducer })
- Todo リストも追加するにあたり、
- ページごとにredux moduleを分け、combineReducer で結合
- Material UI でAppBarでページを移動できるようにした
- rootStateの型は、store.ts で型をexportできる。
const reducer = combineReducers({
counter: counterReducer,
})
export type RootState = ReturnType<typeof reducer>
export const store = configureStore({ reducer })
count+todo AppをFirebase上で動かす
- ログイン機能をつける
- データをfirestoreでユーザーごとに管理
新しいアプリ作り始めたのでクローズ
このスクラップは2021/01/03にクローズされました