簡単なtodoアプリを作成しようとしていますが、つまずいて前に進めなくなりました...
下記のように、taskとidのまとまりを一つのtodoとして、
TypeScript
1 type Todo = { 2 task: string, 3 id: number 4 } 5 6 type TodoState = { 7 todos: Todo[]; 8 }
それを配列の形でstateとして扱うようにして、その配列をmapメソッドで展開してUI上に表示させようと考えていましたが、書きのエラーメッセージが出て、表題のとおりstateがundefinedになってしまいます。
TypeError: Cannot read property 'map' of undefined
原因がどこにあるかわからず困っています。4ファイル分のコードを共有するので問題点などご指摘頂けると幸いです。
osなどの環境は下記の通りです。
OS macOS 10.15.7
"react": "^17.0.1", "react-dom": "^17.0.1", "react-hook-form": "^6.11.0", "react-redux": "^7.2.2", "react-scripts": "4.0.0", "redux": "^4.0.5", "typescript": "^4.0.3",
node.js 14.13.1
コード
App.tsx
useSelectorの2つの型引数としては、1つ目にはReducerの引数stateの型を渡し、2つ目にはuseSelectorで抽出する値の型を指定しています。
import React from 'react'; import { useForm } from 'react-hook-form'; import { useDispatch,useSelector } from 'react-redux'; import { add } from './action'; import { Todo,TodoState } from './reducer'; import './App.css'; export type InputText = { task: string; } function App() { const { register,handleSubmit,reset } = useForm(); const todos = useSelector<TodoState,Todo[]>((state)=>state.todos); const dispatch = useDispatch(); const onSubmit = (data: InputText): void => { const {task} = data; dispatch(add(task)); reset() }; return ( <> <form onSubmit={handleSubmit(onSubmit)}> <input name="task" ref={register}/> <input type="submit"/> </form> <ul> { todos.map((t) => { return( <li key={t.task}>{t.task}</li> ) }) } </ul> </> ); } export default App;
reducer.ts
型TodoStateをTodo[]として、Reducerの返り値の型に設定すれば、stateが配列として返ってくるという認識でしたが、うまくいきません。
●気になっていること
下記のコードのswitch文のcase Type.Addのreturn文の部分で、波括弧{}でオブジェクトの形式で書いていますが、「配列かえすなら角括弧[]使わないとな...)と思い、波括弧の代わりに角括弧を使い、配列の形式にするとエラーが出てしまいます。
※idはtodoを配列としてstateに追加していき、それの長さに応じて割り振りを行おうと思っていたのですが、表題の通りstateがundefinedとして返ってきたので実装できていません。ここではエラーが出ないように?をつけています。
import { Reducer } from 'redux'; import { TodoAction, TodoActionType as Type } from './action'; export type Todo = { task: string, id?: number } export type TodoState = { todos: Todo[]; } export const initialState: TodoState = {todos:[{task:"",id:0}]}; export const todoReducer: Reducer<TodoState,TodoAction> = ( state: TodoState = initialState, action: TodoAction ): TodoState => { switch (action.type) { case Type.ADD: return { ...state, ...action.payload } default:{ const check: never = action.type return check } } };
index.tsx
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import { createStore } from 'redux'; import { Provider } from 'react-redux'; import { todoReducer,initialState } from './reducer'; const store = createStore(todoReducer,initialState); ReactDOM.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode>, document.getElementById('root') );
action.ts
export const TodoActionType = { ADD:'ADD' } as const; type ValueOf<T> = T[keyof T]; export type TodoAction = { type: ValueOf<typeof TodoActionType> payload:{ task: string } } export const add = (text: string): TodoAction => ({ type: TodoActionType.ADD, payload:{ task:text } })
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/11/15 01:32