- 投稿日:2019-05-03T20:44:42+09:00
Material UIでProps渡しで色指定できるCustomButtonを作る
Material UIのボタンにはデフォルトで以下の様なレパートリーがあるのだけれど
デフォルトのままではBootstrapと比べて色数が少なく
Material UIにはせっかく豊富なカラーパレットが用意されているのでこれをprops渡しで色指定できるボタンを何とか作れないかと試行錯誤公式ドキュメントにはCustomized buttonsの作り方が説明されているけれども固定色の為なんとか色指定できる汎用的なコンポーネントにしようと試したところコンパイルエラーの嵐
これを
const ColorButton = withStyles(theme => ({ root: { color: theme.palette.getContrastText(purple[500]), backgroundColor: purple[500], '&:hover': { backgroundColor: purple[700], }, }, }))(Button);こうしようとしたらNGだった
const ColorButton = (props)=> withStyles(theme => ({ root: { color: theme.palette.getContrastText(props.themeColor[500]), backgroundColor: props.themeColor[500], '&:hover': { backgroundColor: props.themeColor[700], }, }, }))(Button);色々書き換えて試してみたがうまくいかず
別のテーマ指定の方法を書き換えてみたところ
const theme = createMuiTheme({ palette: { primary: green, }, }); function CustomizedButtons() { return ( <> <ThemeProvider theme={theme}> <Button variant="contained" color="primary"> Theme Provider </Button> </ThemeProvider> </> ); }↓
const CustomButton = (props) => ( <ThemeProvider theme={createMuiTheme({palette:{primary:props.themeColor}})}> <Button variant="contained" color="primary" className={props.className}> {props.label} </Button> </ThemeProvider> ) function App() { return ( <> <CustomButton label="Hello" themeColor={purple} /> </> ); }かに見えたけど
違う色を並べてみたところ
function App() { return ( <> <CustomButton label="Hello" themeColor={purple} /> <CustomButton label="Hello" themeColor={green} /> </> ); }もう一度withStylesでやる路線に
前の書き換え試行錯誤で以下はconst ColorButton = withStyles(theme => ({ root: { color: theme.palette.getContrastText(purple[500]), backgroundColor: purple[500], '&:hover': { backgroundColor: purple[700], }, }, }))(Button);このように書き換えられるところまでは分かり
withStyles(customTheme)の戻り値はコンポーネントを引数とする関数
withStyles(customTheme)(Button)の戻り値はコンポーネントそのものという事
何かあと一歩足りないconst customTheme = theme => ({ root: { color: theme.palette.getContrastText(purple[500]), backgroundColor: purple[500], '&:hover': { backgroundColor: purple[700], }, }, }) const CustomButton = withStyles(customTheme)(Button)もう一度withStylesにpropsを渡す方法がないかQiitaで探してたら
…あった
Material-UIのwithStylesで指定するstylesCreatorの中で親からpropsとして受け取った値を動的に適応させるHOCあるじゃないか
> const withStylesProps = styles => Component => props => { > const Comp = withStyles(styles(props))(Component); > return <Comp {...props} />; > };jsxってこう書くのか…
というわけで欲しかった方法はこんな感じでした(見易さのためmargin関連省略)
import React from 'react'; import Button from '@material-ui/core/Button'; import { withStyles } from '@material-ui/core/styles'; import { purple, green, red, blue } from '@material-ui/core/colors'; const CustomButton = (props) => { const customTheme = theme => ({ root: { color: theme.palette.getContrastText(props.themeColor[500]), backgroundColor: props.themeColor[500], '&:hover': { backgroundColor: props.themeColor[700], }, }, }) const ComponentName = withStyles(customTheme)(Button) return <ComponentName {...props} /> } function App() { return ( <> <CustomButton themeColor={green}>Hello</CustomButton> <CustomButton themeColor={purple}>Hello</CustomButton> <CustomButton themeColor={red}>Hello</CustomButton> <CustomButton themeColor={blue}>Hello</CustomButton> </> ); } export default App;
- 投稿日:2019-05-03T17:25:51+09:00
React + ReduxでTodoアプリを作ってみよう!『Toggle Todo編』
概要
前回の記事ではTodoアプリにTodoを追加する『Add Todo』機能を実装しました。今回は、追加されたTodoをクリックした際に斜線を引けるようにし、Todoの未・済を判別出来る機能を実装したいと思います!
前回の記事
React + ReduxでTodoアプリを作ってみよう!『Add Todo編』completed属性を付与する
completed属性を付与することで、Todoが完了済みなのか未完了なのかを判別できるようにしましょう!Todoを追加する際にcompleted属性にfalseをデフォルトとして設定します!
src/reducers/todos.jsimport {ADD_TODO, TOGGLE_TODO} from '../actions'; const todos = (state = [], action) => { switch (action.type) { case ADD_TODO: return [...state, {id: action.id, text: action.text, completed: false}]; default: return state; } }; export default todos;completed属性によってTodoのstyleを変更する
completedの属性がtrueかfalseかによってTodoに斜線を引けるようにstyleを反映させましょう!
src/components/Todo.jsimport React from 'react'; import PropTypes from 'prop-types'; const Todo = ({onClick, completed, text}) => { return ( <li style={{textDecoration: completed ? 'line-through' : 'none'}}> {text} </li> ); }; Todo.propTypes = { completed: PropTypes.bool.isRequired, text: PropTypes.string.isRequired, }; export default Todo;Action経由でcompleted属性を操作する
Action経由でcompleted属性を操作するために、まずはAction Creatorを作成しましょう。横線を引くTodoを判別するために、idを取得します。
src/actions/index.jsexport const ADD_TODO = 'ADD_TODO'; export const TOGGLE_TODO = 'TOGGLE_TODO'; let nextTodoId = 0; export const addTodo = text => { return { type: ADD_TODO, id: nextTodoId++, text, //text: text, }; }; export const toggleTodo = id => { return { type: TOGGLE_TODO, id, //id: id }; };またreducersに戻り
action.type
がTOGGLE_TODO
の際の状態遷移の方法を記述しましょう。この中では、stateに保管されているTodoのidと横線を引きたいTodoのidを比較し、お互いに一致するようであれば、一致したidのTodoが持っているcompleted属性を逆転させます。src/reducers/todo.jsimport {ADD_TODO, TOGGLE_TODO} from '../actions'; const todos = (state = [], action) => { switch (action.type) { case ADD_TODO: return [...state, {id: action.id, text: action.text, completed: false}]; case TOGGLE_TODO: return state.map(todo => todo.id === action.id ? {...todo, completed: !todo.completed} : todo ); default: return state; } }; export default todos;Todoをクリックしてcompleted属性を変更する
まずは、
mapDispatchToProps
を作成してdispatchを
propsとして使えるようにしましょう。toggleTodoという名前でdispatchをstoreに格納します。src/containers/VisibleTodoList.jsimport {connect} from 'react-redux'; import TodoList from '../components/TodoList'; import {toggleTodo} from '../actions'; const mapStateToPorops = state => { return {todos: state.todos}; }; const mapDispatchToProps = dispatch => { return { toggleTodo: id => { dispatch(toggleTodo(id)); }, }; }; const VisibleTodoList = connect( mapStateToPorops, mapDispatchToProps )(TodoList); export default VisibleTodoList;これでTodoListでtoggleTodoが使えるようになったので、TodoコンポーネントのonClick属性にtodoのidを引数としてtoggleTodoを渡します。
src/components/TodoList.jsimport React from 'react'; import PropTypes from 'prop-types'; import Todo from './Todo'; const TodoList = ({todos, toggleTodo}) => { return ( <ul> {todos.map(todo => ( <Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} /> ))} </ul> ); TodoList.propTypes = { todos: PropTypes.arrayOF( PropTypes.shape({ id: PropTypes.number.isRequired, text: PropTypes.string.isRequired, }).isRequired ).isRequired, }; }; export default TodoList;Todoコンポーネント内でpropsとして渡されたtoggleTodoをonClick属性に付与します。
src/components/Todo.jsimport React from 'react'; import PropTypes from 'prop-types'; const Todo = ({onClick, completed, text}) => { return ( <li onClick={onClick} style={{textDecoration: completed ? 'line-through' : 'none'}}> {text} </li> ); }; Todo.propTypes = { completed: PropTypes.bool.isRequired, text: PropTypes.string.isRequired, }; export default Todo;以上でTodoをクリックした際に取り消し線を引く機能を実装できました!
次回は表示するTodoを完了・未完了によって分ける「Filter Todo」機能を実装したいと思います。
リファレンス
- 投稿日:2019-05-03T17:17:35+09:00
Redux入門
Reduxってなに?
ReduxとはReactと相性が良いフレームワークのことです。
Redux単体で利用することも可能ですが、ReactとReduxの組み合わせは鉄板でしょう。
stateを容易に管理することの出来るReduxですが、大規模なアプリケーションになればなるほど効果を発揮してくれそうです。Reduxアプリを構成する機能ってなに?
Reduxを使ったアプリはAction,Reducer、Storeによって構成されています。
Actionとは
何がおきたのかという情報を持つオブジェクトです。
ActionをStoreへ送信(dispatch)すると、Storeのstateが変更されます。
stateの変更ではActionが必ず必要となります。
stateへ通じるルートを攻略する第一段階、まるで門番のような立ち位置の機能ですね。const action = { type: 'SET_wanko', text: 'トイプードル' };Actionではどういうタイプのアクションなのかを明示するためtypeプロパティが必要となります、他と区別できないと何がなんだかわからなくなりますもんね。
逆に言えばこのActionはその程度の情報しか持っておらず、どのようにstateを変更するのか知らない存在なのです。
Reducerとは
上記したSET_wankoというタイプのアクション受けて、storeから受け取ったstateを変更して返す純粋関数です。
Reducer内では引数変更したり、API呼び出したり、Math.random()等の純粋関数以外の関数を呼び出してはいけません。
結果が毎回同一になるような操作しか扱えないのです。stateをどう変更するのかactionでは決めれなかったことを指定しています。
function triming(state = [], action) { switch (action.type) { case 'SET_wanko': return state.concat([{ text: action.text, completed: false }]); default: return state; } }Storeとは
Storeとはアプリケーションの全てのstateを保持するオブジェクトです。
dispatchされたActionと保持するstateをreducerに渡してstate変更に一役買う立場の存在で、ボスのような風格ですね。
Storeの複製はダメです、ボスは一人だけなのです。
又、stateの変更は必ずActionを経由してください、バグの特定が困難になるのを防ぐためです。
ボスに会うためにはまず名乗って(Action type)からが礼儀ってもんです。// Action const action = { type: 'SET_wanko', text: 'トイプードル' }; // Reducer function triming(state = [], action) { switch (action.type) { case 'SET_wanko': return state.concat([{ text: action.text, completed: false }]); default: return state; } } // Store const store = Redux.createStore(triming); // Actionをdispatchする // Reducerであるtodosが実行され、Storeが保持しているstateが変更される。 store.dispatch(action); // stateを取得する console.log(store.getState());
- 投稿日:2019-05-03T17:14:52+09:00
Create React App + TypeScriptでESLintとPrettierを使う&Gitコミット時にチェックする
Create React App + TypeScriptを作成
npx create-react-app my-ts-app --typescript cd my-ts-app
ESLintとPrettierの設定
必要なパッケージをインストール。
yarn add -D prettier eslint-config-prettier eslint-plugin-prettier
.eslintrc.yml
を作成。extends: - react-app - plugin:prettier/recommended rules: prettier/prettier: # - error以下はお好みで - error - semi: false singleQuote: true
package.json
の以下の部分を削除(上記.eslintrc.yml
との重複を避けるため)- "eslintConfig": { - "extends": "react-app" - },
同じく
package.json
にESLintとfixのタスクを追加。"scripts": { + "lint": "eslint './src/**/*.{ts,tsx}'", + "lint:fix": "eslint --fix './src/**/*.{ts,tsx}'" }
Create React App + TypeScriptでESLintとPrettierを使うことができるようになりました。
Gitコミット時にチェックする
必要なパッケージをインストール。
console.logyarn add -D pre-commit lint-staged && yarn add -D husky
package.json
にコミット時のチェックを追加。+ "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "*.{ts,tsx}": [ + "eslint './src/**/*.{ts,tsx}'" + ] + }
Gitコミット時に
eslint './src/**/*.{ts,tsx}'
が実行され、チェックしてくれます。以上。
- 投稿日:2019-05-03T16:50:57+09:00
react-native-cli導入の覚書
概要
react-native-cliをMacで使えるようにした時の手順メモ.
AndroidStudioとXcodeは事前に導入済み.実施環境
- System:
- OS: macOS 10.14.
- CPU: (4) x64 Intel(R) Core(TM) i7-7660U CPU @ 2.50GHz
- Binaries:
- Node: 10.15.1
- npm: 6.9.0
インストール手順
watchmanとreact-native-cliをインストール
brew install watchman npm install -g react-native-cliプロジェクトの初期化
react-native init プロジェクト名プロジェクトの実行
react-native run-iosプロジェクトのデバッグ
ブラウザで以下の場所のコンソールを開く
http://localhost:8081/debugger-ui/その他メモ
react-nativeのバージョンは--versionオプションで指定して初期化できる.
react-native init プロジェクト名 --version 0.57.8
- 投稿日:2019-05-03T16:50:57+09:00
React-nativeをMacに導入した時のやったことメモ
概要
React-nativeをMacで使えるようにした時の手順メモ.
AndroidStudioとXcodeは事前に導入済み.実施環境
- System:
- OS: macOS 10.14.
- CPU: (4) x64 Intel(R) Core(TM) i7-7660U CPU @ 2.50GHz
- Binaries:
- Node: 10.15.1
- npm: 6.9.0
インストール手順
watchmanとreact-native-cliをインストール
brew install watchman npm install -g react-native-cliプロジェクトの初期化
react-native init プロジェクト名プロジェクトの実行
react-native run-iosプロジェクトのデバッグ
ブラウザで以下の場所のコンソールを開く
http://localhost:8081/debugger-ui/その他メモ
react-nativeのバージョンは--versionオプションで指定して初期化できる.
react-native init プロジェクト名 --version 0.57.8
- 投稿日:2019-05-03T16:50:57+09:00
React-nativeをMacに導入した時にやったことメモ
概要
React-nativeをMacで使えるようにした時の手順メモ.
AndroidStudioとXcodeは事前に導入済み.実施環境
- System:
- OS: macOS 10.14.
- CPU: (4) x64 Intel(R) Core(TM) i7-7660U CPU @ 2.50GHz
- Binaries:
- Node: 10.15.1
- npm: 6.9.0
インストール手順
watchmanとreact-native-cliをインストール
brew install watchman npm install -g react-native-cliプロジェクトの初期化
react-native init プロジェクト名プロジェクトの実行
react-native run-iosプロジェクトのデバッグ
ブラウザで以下の場所のコンソールを開く
http://localhost:8081/debugger-ui/その他メモ
react-nativeのバージョンは--versionオプションで指定して初期化できる.
react-native init プロジェクト名 --version 0.57.8
- 投稿日:2019-05-03T15:45:43+09:00
JSエンジニア必見!アプリ開発の際のReact Nativeことはじめ
開発環境や前提の知識など
事前環境
• Android, iOS のクロスプラットフォーム・アプリ開発フレームワークです。
画面デザインとロジックのコードを共通で利用することができます。
JavaScript でコーディングし、React で画面をデザインできます。・Node.jsやライブラリ管理にnpmなどが活用されます。
・Homebrew
・*watchmanをインストール(よく、忘れがちです)brew install watchmanメリット
Android、iOSでコードが共通化できるので、両方開発する場合は開発効率が良い
JavaScript で開発するため、、Web開発者の学習コストが低い
Facebook, Instagram, CookPad, メルカリ など大手で実績がある。デメリット
アップデート、保守管理が大変
業務で、少し触れていますが、React Native はソースの管理が難しく、
バージョンをあげたりすると、コマンドが通らなくなったりして、意外と神経を使いますおすすめツール
Visual Studio Code
PowerShell (Windowsのみ)
Android Studio (Android アプリのビルドに必須)
Android アプリの IDE
Xcode (iOS アプリのビルドに必須)
iOS や macOS アプリ の IDE
Node.js (必須)
React Native アプリのビルドやデバッグに必要。
yarn (必須)
Node.js のパッケージ・マネージャ。npm の改良版で、置き換えが可能。
必須、と書いたが、npm でも代替は可能。ただしメリットはない。参考URL
React Native開発のすすめ
・https://qiita.com/janus_wel/items/787732d2bf03ed53a3baReactNativeを使ってみる
https://qiita.com/kurohune538/items/fb9f5ff0b005a39fcc27
- 投稿日:2019-05-03T13:02:28+09:00
模写で"なんとなく"理解する React-Redux超基礎
理論そっちのけで、とりあえず簡単なアプリを作ってみます。
今回作るもの
なんてことのない、ただのカウントアプリです↓
注意点
ただ模写していく事で「あ、なんとなく書けるかも」と思えることが目的です。
理論などの説明は下記リンク群が大変参考になりました。全くつかめていない方は、これらを見てから書いてみるとわかりやすいと思います。
開発環境
カテゴリ バージョン OS macOS Mojave 10.14.4 Node.js 10.15.3 Yarn 1.13.0 React 16.8.6 Redux 4.0.1 模写の準備
開発環境の構築
Node.js, Yarnのインストール
ここの説明は省略します。
わからない人は、このQiitaが懇切丁寧です。create-react-appのインストール
Facebook社が作ってくださった「create-react-app」という雛形をダウンロードします。
$ yarn global add create-react-app ※"./path/to/applciation"の部分で作成するアプリケーションへのパスを指定 $ create-react-app ./path/to/applicationこのような、React自身やその他諸々のライブラリをまとめて、雛形を作成してくれるツールを「boilerplate」と言います。
色々な種類がありますので、気になる方はこちらを参考に。
実際に雛形が作成され、下記のようなフォルダ・ファイル群が生成されます↓
. ├── README.md ├── node_modules ├── package.json ├── public ├── src └── yarn.lockとりあえず起動してみましょう。Reactのロゴがブラウザで表示されれば成功です。
$ yarn startRedux, react-reduxのインストール
ちなみにreact-reduxはReactとReduxの仲介役を担っているモジュールです。
$ yarn add redux react-reduxこれで開発環境は構築できました。
ファイル構成を整える
src
ディレクトリの配下をこんな感じにしておきましょう。
あらかじめフォルダやファイルを作っていくことで、模写がラクになります。├── App.css ├── App.test.js ├── actions │ └── index.js ├── components │ └── App.js ├── index.js ├── reducers │ ├── count.js │ └── index.js └── serviceWorker.jsレッツ模写!
Actionの定義
storeにメッセージを送るためのActionを定義します。
カウントアプリは「+」と「-」ボタンによって状態を変化させるだけですので、必要なアクションは2つのみとなります。
acitons/index.jsexport const INCREMENT = 'INCREMENT' export const DECREMENT = 'DECREMENT' // 書き方が2通りありますが、どちらでも問題ないです export const increment = () => { return { type: INCREMENT } } export const decrement = () => ({ type: DECREMENT )}Reducerの実装
storeから送られた情報をもとにstateを実際に変更する「Reducer」を実装しましょう。
index.jsの実装
Reducer群を管理する
index.js
を実装します。今回作成するアプリは1つのReducerしか持たないので、count.jsと分離する必要はありません。
ただ、規模の大きいアプリの場合は必要となりますので、今後の為にもやっておきましょう。reducers/index.jsimport { combineReducers } from 'redux' import count from './count' export default combineReducers(({ count }))count.jsの実装
カウンターの数字を変更する部分となります。
storeから送られる情報の中のaction.type
によって、数字を増やすのか・減らすのかを決めています。reducers/count.jsimport { INCREMENT, DECREMENT } from '../actions' //コンポーネントの初期値を設定 const initialState = { value: 0 } export default (state = initialState, action) => { switch (action.type) { case INCREMENT: return { value: state.value + 1 } case DECREMENT: return { value: state.value - 1 } default: return state } }storeの実装
実装されたReducerをもとに、storeを作成します。
index.jsimport React from 'react' import ReactDOM from 'react-dom' import { createStore } from 'redux' import { Provider } from 'react-redux' import reducer from './reducers' import App from './components' import * as serviceWorker from './serviceWorker' // 作成されたReducerをもとにstoreを作成 // アプリケーション内部の全てのstateは、このstateに集約される const store = createStore(reducer) // Providerによって、storeがどのコンポーネントからも参照できるようになる ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); serviceWorker.unregister();コンポーネントの実装
index.js
で呼び出している「App」コンポーネントを実装しましょう。components/App.jsimport React, { Component } from 'react' import { connect } from 'react-redux' import { increment, decrement } from '../actions' class App extends Component { render() { const props = this.props return ( <React.Fragment> <div>count:{props.value}</div> <button onClick={props.increment}>+</button> <button onClick={props.decrement}>-</button> </React.Fragment> ); } } // stateから必要な情報をコンポーネントにマッピングする関数 const mapStateToProps = state => ({ value: state.count.value }) // dispatch関数をコンポーネントにマッピングする関数 const mapDispatchToProps = dispatch => ({ increment: () => dispatch(increment()), decrement: () => dispatch(decrement()) }) // こんな書き方もある↓ // const mapDispatchToProps = ({ increment, decrement }) // stateとacitonをコンポーネントに関連づける export default connect(mapStateToProps, mapDispatchToProps)(App)次は...
TODOリストや、Ajax通信を実装してみるといいかもしれません。
- 投稿日:2019-05-03T10:15:32+09:00
模写で「なんとなく」理解する React-Redux超基礎
どうも、研究に勤しんでいる大学4年生です。
かなり前に学んでご無沙汰だった「React-Redux」を簡単におさらいしようと思います。
今回作るもの
なんの難しいこともありません。
ただのカウントアプリです↓
https://media.giphy.com/media/VbneMYUExEsBWGC8Vx/giphy.gif
- 投稿日:2019-05-03T02:39:16+09:00
Expo 32 SDK で React Hooks を使う方法。
Feature request にコメントしたら反響あったので、リンクをシェアします。
https://expo.canny.io/feature-requests/p/support-react-1680-aka-hooks