#現象
React + TypeScriptにてlocalstrageを利用したいのですが
実装方法が分からずで困っています。
LocalStorageでの保存が可能であればよいので
JavaScriptなどで対応すべきなのでしょうか。。。
#ソース
store
1// import { Store } from "redux"; 2import { createStore, combineReducers } from "redux"; 3// import { createStore, applyMiddleware, combineReducers, compose } from "redux"; 4import speakReducer, { SpeakState } from "./speak/reducers"; 5// import thunk from "redux-thunk"; 6// import speak from "./speak"; 7 8export type AppState = { 9 speak: SpeakState; 10}; 11 12const store = createStore( 13 combineReducers<AppState>({ ※この辺いじってできたら理想。 14 speak: speakReducer, 15 }) 16); 17 18export default store; 19
index
1import React from "react"; 2import ReactDOM from "react-dom"; 3import "./index.css"; 4import App from "./views/App"; 5import * as serviceWorker from "./serviceWorker"; 6import { Provider } from "react-redux"; 7import store from "./state/store"; 8 9// const store = configureStore(); 10 11ReactDOM.render( 12 <React.StrictMode> 13 <Provider store={store}> 14 <App /> 15 </Provider> 16 </React.StrictMode>, 17 document.getElementById("root") 18); 19 20// If you want your app to work offline and load faster, you can change 21// unregister() to register() below. Note this comes with some pitfalls. 22// Learn more about service workers: https://bit.ly/CRA-PWA 23serviceWorker.unregister(); 24
reducers
1import { Reducer } from "redux"; 2import { Fold, File } from "speak"; 3import { Actions, ActionTypes } from "./actions"; 4 5export type SpeakState = { 6 folders: Fold[]; 7 files: File[]; 8 // check: boolean; 9}; 10 11export const initialState: SpeakState = { 12 folders: [ 13 { 14 folderId: 1, 15 name: "果物", 16 text: "A", 17 opened: true, 18 }, 19 { 20 folderId: 2, 21 name: "こってり系", 22 text: "B", 23 opened: true, 24 }, 25 { 26 folderId: 3, 27 name: "飲み物", 28 text: "C", 29 opened: false, 30 }, 31 ], 32 files: [ 33 { 34 folderId: 1, 35 fileId: 1, 36 name: "りんご", 37 text: "apple", 38 checked: false, 39 listening: false, 40 indicate: true, 41 }, 42 { 43 folderId: 1, 44 fileId: 2, 45 name: "ぶどう", 46 text: "grape", 47 checked: false, 48 listening: false, 49 indicate: true, 50 }, 51 { 52 folderId: 1, 53 fileId: 3, 54 name: "シャンパン", 55 text: "Champagne", 56 checked: false, 57 listening: false, 58 indicate: true, 59 }, 60 { 61 folderId: 1, 62 fileId: 4, 63 name: "しょうゆ", 64 text: "Soy sauce", 65 checked: false, 66 listening: false, 67 indicate: true, 68 }, 69 { 70 folderId: 2, 71 fileId: 1, 72 name: "塩", 73 text: "salt", 74 checked: false, 75 listening: false, 76 indicate: true, 77 }, 78 { 79 folderId: 2, 80 fileId: 2, 81 name: "豚骨", 82 text: "pork bone", 83 checked: false, 84 listening: false, 85 indicate: true, 86 }, 87 { 88 folderId: 2, 89 fileId: 3, 90 name: "鶏", 91 text: "chicken", 92 checked: false, 93 listening: false, 94 indicate: true, 95 }, 96 { 97 folderId: 3, 98 fileId: 1, 99 name: "酸辣湯麺", 100 text: "hot and sour noodles", 101 checked: false, 102 listening: false, 103 indicate: true, 104 }, 105 { 106 folderId: 3, 107 fileId: 2, 108 name: "トンカツ", 109 text: "pork cutlet", 110 checked: false, 111 listening: false, 112 indicate: true, 113 }, 114 { 115 folderId: 3, 116 fileId: 3, 117 name: "ラーメン", 118 text: "ramen", 119 checked: false, 120 listening: false, 121 indicate: true, 122 }, 123 { 124 folderId: 3, 125 fileId: 4, 126 name: "日本酒", 127 text: "Japanese sake", 128 checked: false, 129 listening: false, 130 indicate: true, 131 }, 132 { 133 folderId: 3, 134 fileId: 5, 135 name: "ワイン", 136 text: "Wine", 137 checked: false, 138 listening: false, 139 indicate: true, 140 }, 141 ], 142}; 143 144const speakReducer: Reducer<SpeakState, Actions> = ( 145 state = initialState, 146 action 147) => { 148 switch (action.type) { 149 case ActionTypes.CHANGE_SEARCH: { 150 if (action.payload.text) { 151 state.files 152 .filter((file) => file.text.includes(action.payload.text)) 153 .forEach((file) => { 154 file.indicate = false; 155 }); 156 } else { 157 state.files.forEach((file) => { 158 file.indicate = true; 159 }); 160 } 161 return { 162 ...state, 163 }; 164 } 165 case ActionTypes.CLICK_FOLDER: { 166 state.folders.forEach((folder) => { 167 if (folder.folderId === action.payload.id) { 168 folder.opened = !folder.opened; 169 } 170 }); 171 return { 172 ...state, 173 }; 174 } 175 case ActionTypes.CLICK_PLAY: { 176 const folderId = action.payload.folderId; 177 const fileId = action.payload.folderId; 178 const playBefore = action.payload.playBefore; 179 if (folderId && fileId) { 180 // 単独 181 state.files 182 .filter( 183 (file) => file.folderId === folderId && file.fileId === fileId 184 ) 185 .forEach((file) => { 186 file.listening = playBefore; 187 }); 188 } 189 return { 190 ...state, 191 }; 192 } 193 case ActionTypes.CLICK_FILE: { 194 // チェック対象ファイル 195 const target = state.files.filter( 196 (file) => 197 file.folderId === action.payload.folderId && 198 file.fileId === action.payload.fileId 199 ); 200 target[0].checked = !action.payload.checked; 201 return { 202 ...state, 203 }; 204 } 205 case ActionTypes.CLICK_ALL: { 206 // チェック対象フォルダ 207 const targetFolders = state.folders.filter( 208 (fold) => fold.opened === true 209 ); 210 // チェック対象ファイル 211 const targetFoldId = [ 212 targetFolders.map((fold) => { 213 return fold.folderId; 214 }), 215 ]; 216 state.files.forEach((file) => { 217 if (targetFoldId[0].includes(file.folderId)) { 218 file.checked = action.payload.checked; 219 } 220 }); 221 222 return { 223 ...state, 224 }; 225 } 226 case ActionTypes.FOLDER_ADD: { 227 alert("aaaaaaaa"); 228 return { 229 ...state, 230 }; 231 } 232 233 case ActionTypes.FOLDER_DEL: { 234 alert("folder.del"); 235 return { 236 ...state, 237 }; 238 } 239 240 case ActionTypes.FILE_ADD: { 241 alert("file.add"); 242 return { 243 ...state, 244 }; 245 } 246 247 case ActionTypes.FILE_DEL: { 248 alert("file.del"); 249 return { 250 ...state, 251 }; 252 } 253 254 case ActionTypes.MUSIC_START: { 255 alert("music.start"); 256 return { 257 ...state, 258 }; 259 } 260 case ActionTypes.MUSIC_STOP: { 261 alert("music.stop"); 262 return { 263 ...state, 264 }; 265 } 266 case ActionTypes.MUSIC_END: { 267 alert("music.end"); 268 return { 269 ...state, 270 }; 271 } 272 273 default: { 274 return state; 275 } 276 } 277}; 278 279export default speakReducer; 280
#環境
Windows
React(re-ducks)
TypeScript
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。