[メモ]Prettier
はじめに
prettierとtslintを組み合わせたら、良い感じのコーディングができるようになりました。Reactでコーディングするとき用の設定メモとして残します。
Prettierの設定方法 on VSCode
1. Prettier pluginをインストールする。Extensions(Ctrl + Shift + X)の検索ボックスで「Prettier」と検索する。
その後、「Prettier - Code formatter」というものをインストール。
2. VSCode上でPrettierを適用する。
settingsを開く。(Ctrl + Shift + Pより「> User Settings」と検索)
その後、「Text Editor→Formatting」より「Format On Save」にチェックをいれる。
3. プロジェクトでルールを設定する。
プロジェクトのルートに「.prettierrc」を作成します。
私の設定は以下の通りですが、お好みでどうぞ。
{ "singleQuote": true, "jsxSingleQuote": false, "trailingComma": "all", "arrowParens": "always" }
[React]Presentational+Container componentsについて
以前、同じタイトルで記事を書いたあとに、非公開にした記事を編集しようと思ったら、消えていたので再度投稿します。
はじめに
redditで以下の投稿があったので、自分の考えをアウトプットしようと思いました。www.reddit.com
※参考
medium.com
React+Reduxでコンポーネントを書いているときに、コンポーネント思想の1つとしてPresentational+Container componentsがあります。
■Presentational+Container componentsの概要
Presentational component | View部分を担当 |
---|---|
Container component | ロジック部分を担当 |
この思想によって、メンテンスのしやすいコンポーネントが出来ると思います。
ただ、参考に載せていたように、React開発に携わっているDanさんの言っていることもわかります。
Update from 2019: I wrote this article a long time ago and my views have since evolved. In particular, I don’t suggest splitting your components like this anymore. If you find it natural in your codebase, this pattern can be handy. But I’ve seen it enforced without any necessity and with almost dogmatic fervor far too many times. The main reason I found it useful was because it let me separate complex stateful logic from other aspects of the component. Hooks let me do the same thing without an arbitrary division. This text is left intact for historical reasons but don’t take it too seriously.
Presentational and Container Components - Dan Abramov - Medium
「hooksが出てきたので、もう分けなくていいんじゃないか」ってことですね。
そうですねーって感じです。hooksを使っていて思いますが、とにかくstate管理が楽です。Presentational+Container componentsでhooksを使うときは、正直view側に書きたいです。(viewでしかstate使わないし。。。storeにあるstateみたいなグローバル的なstateとは違うし。。。)
ただ、やっぱりPresentational+Container componentsの思想も個人的には捨てきれないです。(小規模アプリは除く)
以下の理由からです。
1. 1つのファイルにviewとlogicを書くと、とにかく長くなって見にくい。
2. viewとlogicを分けることによって、設計が楽になる。
私自身もどちらがいいというのは決定しきれていませんが、今の所はPresentational+Container componentsの思想でやっていこうと思います。
connect使おうが使わまいが、コンポーネント自体の再利用性、メンテナンス性をしっかり考えるべきだなと思いました。
(無駄にContainer作って、コンポーネントを増やのは嫌なので。。。)
また、記事アップデートします。
以上です。
[Webpack4.0] エラー解決集
はじめに
Webpackを使っているときのエラーとその解決方法をまとめます。徐々に増やしていく予定です。
まとめ
テンプレートエラー分 | hoge |
---|---|
解決方法 | resolve hoge |
エラー分 | ERROR in Entry module not found: Error: Can't resolve './src' in 'folder_name' |
---|---|
解決方法-1 | entryを記述する。webpack4.0では、entryを指定していない場合、webpackが自動的に'./src'にエントリーポイントを探しに行ってしまうことが原因です。 |
解決方法-2 | ファイル名の誤り。私はwebpack.config.jsがwebpack.config.dev.jsとなっていたため、発生しました。(ファイル名には気をつけましょう!!!!!!) |
エラー分 | Module build failed (from ./node_modules/ts-loader/index.js): Error: TypeScript emitted no output for 'file-name' |
---|---|
解決方法 | tsconfig.jsonで["noEmit": true]と記載していると、発生します。削除しましょう。noEmitとは、ファイルを出力しないようにするための設定で、TypeScriptからもファイルを出力する場合、削除します。 |
typescript-fsaで複数の値を渡したい時
はじめに
typescript-fsaで複数の値を渡す方法で少し考えてしまったので、解法を残します。今回は、Todoリストを追加するactionを例にして、必要な部分のみを記載します。
関連するファイルは以下の通りです。
actions.ts
// typescript-fsa import actionCreatorFactory from 'typescript-fsa'; const actionCreator = actionCreatorFactory(); export const addTodoActions = { addTodoAction: actionCreator<{ name: string, priority: string }>('ADD_PATH'), };
actionCreatorFactory()の型部分で、渡す値の型を記載します。
actionCreator()の型部分は、1つのargumentしか受け付けません。
reducers.ts
// typescript-fsa import { reducerWithInitialState } from 'typescript-fsa-reducers'; // redux import { addTodoActions } from './actions'; export const addTodoReducer = reducerWithInitialState(initialStateAddTodo) .case(addTodoActions.addTodoAction, (state, payload) => ({ ...state, paths: state.todos.concat( // addTodo()は、既存のTodoリストにconcatで新たなTodoをいれるための関数です。 addTodo(payload.name, payload.priority) ), }))
payloadにnameとpriorityが格納されているため、それぞれを既存のTodoリストに追加します。
(今回はaddTodo()がその役割です。)
AddTodoContainer.tsx
// redux import { Dispatch } from "redux"; import { addTodoActions } from '../actions' // react-redux import { connect } from "react-redux"; // components import AddTodo from '../components/AddTodo' export type AddTodoFormHandler = { handleAddTodo(todoName: string, priority: string ): void } const mapDispatchToProps = (dispatch: Dispatch) => { return { handleAddTodo: (name: string, priority: string) => { dispatch(addTodoActions .addTodoAction({ name, priority })) }, } }; export default connect( null, mapDispatchToProps )(AddTodo);
関数のそれぞれの引数を記載します。
(今回はnameとpriority)
AddTodo.tsx
<button onClick={() => { props.handleAddTodo(name, priority ); }} > Add Todo </button>
onClickしたときに、containerのhandleAddTodoに入力したnameとpriorityの値を渡します。
React+Redux+TypeScriptでサンプルアプリを作成する。
はじめに
React + Redux + TypescriptでTodoアプリを作っていきます。今回は、Todoの追加のみです。
ソースコード(GitHub)
github.com参考にしたサイト
qiita.comreact-redux.js.org
qiita.com
環境
- バージョン
node.js | -v8.12.0 |
react | -v16.9.0 |
redux | -v4.0.4 |
react-redux | -v7.1.1 |
- フォルダ構成
. |--/public | |--index.html | |--/src | |--/components | | |--AddTodoForm.tsx | | |--App.tsx | | |--TodoList.tsx | | | |--/containers | | |--AddTodoFormContainer.tsx | | |--TodoListContainer.tsx | | | |--actions.ts | |--index.tsx | |--reducers.ts | |--store.ts | |--package.json |--tsconfig.json |--webpack.config.js
Action
// src/actions.ts // typescript-fsa import actionCreatorFactory from 'typescript-fsa'; const actionCreator = actionCreatorFactory(); export const todoArrayActions = { addTodoAction: actionCreator<string>('ADD_TODO'), }; export const addTodoFormActions = { inputTextAction: actionCreator<string>('INPUT_TEXT'), initializeAddTodoFormAction: actionCreator('INITIALIZE_ADD_TODO_FORM'), };
typesctipt-fsaを使って、actionを書いていきます。
todoの配列に関するtodoArrayActionsと、todoを追加するフォームに関するaddTodoFormActionsでアクションを分けました。
reducerでTodoArrayとAddTodoFormが分かれているので、こちらも分けました。
Reducer
// src/reducers.ts // typescript-fsa import { reducerWithInitialState } from 'typescript-fsa-reducers'; // redux import { todoArrayActions, addTodoFormActions } from './actions'; export type Todo = { id: number; text: string; done: boolean; }; export type TodoArray = { todos: Todo[]; }; export const initialStateTodoArray: TodoArray = { todos: [ { id: 1, done: false, text: 'initial todo', }, ], }; export type AddTodoForm = { inputText: string }; export const initialStateAddTodoForm: AddTodoForm = { inputText: '' }; let idCounter: number = 1; const addTodo = (text: string): Todo => ({ id: ++idCounter, done: false, text, }); export const todoArrayReducer = reducerWithInitialState(initialStateTodoArray) .case(todoArrayActions.addTodoAction, (state, payload) => ({ ...state, todos: state.todos.concat( addTodo(payload) ), })) export const addTodoFormReducer = reducerWithInitialState(initialStateAddTodoForm) .case(addTodoFormActions.inputTextAction, (state, payload) => ({ ...state, inputText: payload, })) .case(addTodoFormActions.initializeAddTodoFormAction, () => ({ inputText: '', }))
type
大きく分けて、TodoArrayとAddTodoFormです。
reducers
- todoArrayReducer
addTodoAction: 受け取ったTodoをconcatにて、配列の一番うしろに追加します。
- addTodoFormReducer
inputTextAction: 入力されている文字をいれています。
initializeAddTodoFormAction: Todoを追加したあとに、ボックスの中身を初期化しています。
Store
// src/store.ts // redux import { createStore, combineReducers, compose, applyMiddleware } from 'redux'; import thunk from "redux-thunk"; import { TodoArray, todoArrayReducer, AddTodoForm, addTodoFormReducer, } from './reducers'; export type AppState = { todoArray: TodoArray addTodoForm: AddTodoForm }; const storeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore( combineReducers<AppState>({ todoArray: todoArrayReducer, addTodoForm: addTodoFormReducer }), storeEnhancers(applyMiddleware(thunk)) ); export default store;
説明できるほど、わかっておりません。
以下の記事のstore.tsを参考にしてください。
qiita.com
index.tsx
// src/index.tsx // react import React from 'react'; import ReactDOM from 'react-dom'; // redux import store from './store'; // react-redux import { Provider } from 'react-redux'; // components import App from './components/App'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('app') );
Appコンポーネントに、Providerコンポーネント経由でstoreの値を渡しています。
特段、説明はいらないと思います。
Presentational and Container Components
このアプリの設計は、reduxの以下の設計思想に沿っています。redux.js.org
AddTodoFormContainer.tsx
// src/containers/AddTodoFormContainer.tsx // redux import { Dispatch } from "redux"; import { todoArrayActions, addTodoFormActions } from '../actions' import { AppState } from '../store'; // react-redux import { connect } from "react-redux"; // components import AddTodoForm from '../components/AddTodoForm' export type AddTodoFormHandler = { handleAddTodo(value: string): void handleInputText(value: string): void handleInitializeAddTodoForm(): void }; const mapStateToProps = (appState: AppState) => { return { inputText: appState.addTodoForm.inputText, }; }; const mapDispatchToProps = (dispatch: Dispatch) => { return { handleAddTodo: (value: string) => { dispatch(todoArrayActions.addTodoAction(value)) }, handleInputText: (value: string) => { dispatch(addTodoFormActions.inputTextAction(value)) }, handleInitializeAddTodoForm: () => { dispatch(addTodoFormActions.initializeAddTodoFormAction()) }, } }; export default connect( mapStateToProps, mapDispatchToProps )(AddTodoForm);
AddTodoFormに必要なactionとstateを記載しています。
TodoListContainer.tsx
// src/containers/TodoListContainer.tsx // redux import { AppState } from '../store'; // react-redux import { connect } from 'react-redux'; // components import { TodoList } from '../components/TodoList'; const mapStateToProps = (appState: AppState) => { return { todos: appState.todoArray.todos, }; }; export default connect(mapStateToProps, null)(TodoList);
TodoListに必要なactionとstateを記載しています。
AddTodoForm.tsx
// src/components/AddTodoForm.tsx // react import React from 'react'; // redux import { AddTodoForm } from '../reducers'; // containers import { AddTodoFormHandler } from '../containers/AddTodoFormConrainer'; type Props = AddTodoForm & AddTodoFormHandler; const AddTodoForm: React.FC<Props> = (props: Props) => { return ( <div> <input type='text' value={props.inputText} onChange={(e: React.ChangeEvent<HTMLInputElement>) => { props.handleInputText(e.currentTarget.value) }} /> <button onClick={() => { props.handleAddTodo(props.inputText); props.handleInitializeAddTodoForm() }} > Add Todo </button> </div> ); }; export default AddTodoForm;
AddFormのviewです。
inputのvalueはinputTextに設定しています。
onChangeにて、入力内容をdispatchしています。
TodoList.tsx
// src/components/TodoList.tsx // react import React from 'react'; // redux import { TodoArray } from '../reducers'; type Props = TodoArray; export const TodoList: React.FC<Props> = (props: Props) => { return ( <div> {props.todos.map((todo) => ( <li key={todo.id.toString()}> {todo.id} {todo.text} </li> ))} </div> ); };
TodoListのviewです。
mapで配列を順に描画しています。
自分のブレイクポイント
はじめに
自分でアプリケーションを作るときの、ブレイクポイントを書いておこうと思います。ブレイクポイント
- 481以下
モバイル
- 481-746
モバイル大
- 746以上
- 960以上
デスクトップ
公開したもの
はじめに
作成したアプリケーションをここにまとめます。Applications
- To-do application
https://infinite-tor-66450.herokuapp.com/
はじめて作成したTo-do application
Reactを使って何かを作りたいと思い、作成しました。
Front-end: React, Redux
Back-end: Node.js, MongoDB
NEW
glacial-tundra-36406.herokuapp.com
OLD
agile-beyond-84675.herokuapp.com
自身のポートフォリオサイト。
レスポンシブデザインについて、更に成長できたと思います。
Front-end: React, Redux
Back-end: Node.js