20190503のReactに関する記事は11件です。

Material UIでProps渡しで色指定できるCustomButtonを作る

Material UIのボタンにはデフォルトで以下の様なレパートリーがあるのだけれど
img_20190503.png
デフォルトのままでは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} />
    </>
  );
}

上手くいった
img_20190503(1).png

かに見えたけど

違う色を並べてみたところ

function App() {
  return (
    <>
      <CustomButton label="Hello" themeColor={purple} />
      <CustomButton label="Hello" themeColor={green} />
    </>
  );
}

KONOZAMA☆
img_20190503(2).png

もう一度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;

見た目はこんな感じ
img_20190503(3).png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.js
import {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.js
import 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.js
export 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.typeTOGGLE_TODOの際の状態遷移の方法を記述しましょう。この中では、stateに保管されているTodoのidと横線を引きたいTodoのidを比較し、お互いに一致するようであれば、一致したidのTodoが持っているcompleted属性を逆転させます。

src/reducers/todo.js
import {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.js
import {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.js
import 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.js
import 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をクリックした際に取り消し線を引く機能を実装できました!

ezgif.com-optimize (2).gif

次回は表示するTodoを完了・未完了によって分ける「Filter Todo」機能を実装したいと思います。

リファレンス

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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()); 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.log
yarn 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}'が実行され、チェックしてくれます。

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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/787732d2bf03ed53a3ba

ReactNativeを使ってみる
https://qiita.com/kurohune538/items/fb9f5ff0b005a39fcc27

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

模写で"なんとなく"理解する React-Redux超基礎

理論そっちのけで、とりあえず簡単なアプリを作ってみます。

今回作るもの

なんてことのない、ただのカウントアプリです↓

giphy.gif

注意点

ただ模写していく事で「あ、なんとなく書けるかも」と思えることが目的です。
理論などの説明は下記リンク群が大変参考になりました。

全くつかめていない方は、これらを見てから書いてみるとわかりやすいと思います。

開発環境

カテゴリ バージョン   
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 start

Redux, 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.js
export 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.js
import { combineReducers } from 'redux'
import count from './count'

export default combineReducers(({ count }))

count.jsの実装

カウンターの数字を変更する部分となります。
storeから送られる情報の中のaction.typeによって、数字を増やすのか・減らすのかを決めています。

reducers/count.js
import { 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.js
import 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.js
import 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通信を実装してみるといいかもしれません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

模写で「なんとなく」理解する React-Redux超基礎

どうも、研究に勤しんでいる大学4年生です。

かなり前に学んでご無沙汰だった「React-Redux」を簡単におさらいしようと思います。

今回作るもの

なんの難しいこともありません。
ただのカウントアプリです↓
https://media.giphy.com/media/VbneMYUExEsBWGC8Vx/giphy.gif

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Expo 32 SDK で React Hooks を使う方法。

Feature request にコメントしたら反響あったので、リンクをシェアします。

https://expo.canny.io/feature-requests/p/support-react-1680-aka-hooks

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む