- 投稿日:2021-03-15T23:33:49+09:00
とりあえず React + TypeScript で適当なサンプルページを作りたい ③
この記事は未完成の記事です。筆者の性格上、完成してから公開するよりも、公開して追記とメンテナンスするほうが書物が継続するので公開しています。
これまで
前回
https://qiita.com/KennyKTA/items/9e240cd90ecb86ea3ee5
前々回
https://qiita.com/KennyKTA/items/c05c5047953777eeb5c4今回やること
- React Boot Strap の Getting Start のLayout のセクションを理解する。
- React + Boot Strap によるグリッドシステムの実装を行う。
今回やらないこと
- React Boot Strap の Getting Start のLayout の完全な翻訳はしない。自分に必要な範囲で訳し、記録する。
- flexbox に関する調査、言及はしない。
開発内容
まずは React Boot Strap のGetting started のGrid のセクションを軽く読んでいく。
全てに関して実施しないが、備忘とMarkdownの練習を目的として上記ページの引用 + 翻訳を行う。区切りはMarkdownの水平線を利用してみる。
Grid system
Bootstrap’s grid system uses containers, rows, and columns to layout and align content. It’s built with flexbox and is fully responsive. Below is an example and an in-depth look at how the grid comes together.
Bootstrap のグリッドシステムはレイアウトと整列を行うためにコンテナ、ロウ、カラムを利用します。この技術はflexboxをもとに構築されており、完全レスポンシブです。以下が、グリッドがどのように組み合わされるかの例と詳細です。
(どうやらflexbox と呼ばれる技術の上にグリッドシステムが構築されているらしい。上述の引用からもflexboxにはリンクが張られており、理解した方がよいのだろうが深入りせず飛ばしていく)。
Container
Containers provide a means to center and horizontally pad your site’s contents. Use Container for a responsive pixel width.
コンテナはあなたのサイトコンテンツを中央に配置し水平方向に並べるための手段を提供します。レスポンシブなピクセル幅を実現するためにはコンテナを利用してください。
(日本語だけだと理解ができない。水平方向に並べるとあるので、Containerの中に何か並べるのだろう。サンプルコードではRow が1つ並べられている。つまり1行だ。)
Fluid Container
You can use for width: 100% across all viewport and device sizes.
Container fluid を利用することで全てのviewport とデバイスサイズに対して幅100% を実現できます。
(訳があっている自信がない、、、viewport ってなんだ?いずれにせよContainer にはfluid というpropが存在するらしい)You can set breakpoints for the fluid prop. Setting it to a breakpoint (sm, md, lg, xl) will set the Container as fluid until the specified breakpoint.
fluid prop にはブレークポイントを設定することが可能です。ブレークポイント(sm,md,lg,xl)を設定することでContainer は 指定したブレークポイントまで流動的になります。
(訳しても意味がわからない。推測するに、fluid にデバイスサイズ?か何かを渡すとレスポンシブに表示がなされるということなのだろう。指定サイズまではコンテナが伸びるとか、そんなのじゃないかな?後で試してみよう。)
Auto-layout columns
When no column widths are specified the Col component will render equal width columns
列の幅に対して指定がない場合、Col コンポーネントは均等な幅で列を描画します。
(同一行の列に幅指定がなければ、等間隔の列が描画される。直観的でわかりやすい。)
Setting one column width
明日はここから調べて書く。
その他
今のところ、特になし。
- 投稿日:2021-03-15T22:18:31+09:00
とりあえず React + TypeScript で適当なサンプルページを作りたい ②
前回
今回やること
- React + Boot Strap でなにがしかの実装を行う。
- React + Boot Strap によるグリッドシステムの実装を行う(次回に譲るかも)。
補足:
軽く調べるとレイアウトの配置はグリッドシステムというものを使うそうだ。別の技術もあり得るだろうが、今回は一通り走ることが大目標なので、これを採用する。Boot Strap という聞いたことのある名前の技術がReactにグリッドシステムを提供しているようなのでこれをターゲットに実装する。今回やらないこと
- 特になし
開発
- React BootStrap の公式ページのGet Start に従っていく。
React Boot Strap のパッケージをインストール
npm install react-bootstrap bootstrapアプリのソースを以下のように実装。
App.tsximport React from 'react'; import logo from './logo.svg'; import './App.css'; import { LanguageServiceMode } from 'typescript'; import { Button } from 'react-bootstrap'; function App() { return ( <div> <h1>this is sample</h1> <Button>this is sample <button type="submit"></button></Button> </div> ); } export default App;ローカルサーバの立ち上げを実施。
npm startどうやらReact Boot Strap はUIコンポーネントも提供しているらしい。かなり色々できそうだが本丸はグリッドシステムなので、そこを重点的に調べる。グリッドシステムに関しては次回に譲る。
その他
グリッドシステムを調べる過程で面白そうなものを見つけた。別の機会に調べたい。
https://github.com/react-grid-layout/react-grid-layoutReact の公式から辿って知ったのだがCodeSandboxというWebサービスがある。
https://codesandbox.io/
node.js のIDE環境で、作成したReactアプリを簡易にホストしてくれるらしい。
開発環境を構築する手間が省けるし、npm start のようなサーバ立ち上げのコマンドも不要だ。
実装の挙動だけを簡単に確認したい場合はこれでもいい気がしてきた。
- 投稿日:2021-03-15T21:50:05+09:00
とりあえず React + TypeScript で適当なサンプルページを作りたい
目的
- 記事を作成することでMarkdownの仕様に慣れる。
- React と TypeScript に慣れる。
やること
- とにかくReact + TypeScript でサンプルページを作る。
- まずGUIをレイアウトできるようする。
- 使えそうなComponentは持ってきて利用する。
やらないこと
- 適切なコンポネントの切り分けはしない。
- 適切なprops の伝搬はしない。
- Redux などの設計思想の取り込みはしない。
- GUIに紐づく処理の開発はしない。 (とにかく目に見えるものだけ作ってみる)
設計
とにかく作るといっても作るもののイメージがないことには始まらないので、作成対象を設計した。設計はQiitaのブログを表示した際のレイアウトを参考にした。
上記をもとに開発を進めていこうと思う。この記事は意思表示とレイアウト作成までとし、ここまでで終了する。記事も小分けに書いていかないと、大作化してしまい結局最後まで書かないと考えているからだ。
- 投稿日:2021-03-15T21:50:05+09:00
とりあえず React + TypeScript で適当なサンプルページを作りたい ①
目的
- 記事を作成することでMarkdownの仕様に慣れる。
- React と TypeScript に慣れる。
やること
- とにかくReact + TypeScript でサンプルページを作る。
- まずGUIをレイアウトできるようする。
- 使えそうなComponentは持ってきて利用する。
やらないこと
- 適切なコンポネントの切り分けはしない。
- 適切なprops の伝搬はしない。
- Redux などの設計思想の取り込みはしない。
- デザインの美しさは問わない。
- レスポンシブ対応はしない。
- GUIに紐づく処理の開発はしない。とにかく目に見えるものだけ作ってみる。
やらないことは事前に割り切って決めたほうがよい。走りきることが大事で、目移りしないため工夫だ。そのため妥協点をやらないこととして後で追加するかもしれない。
設計
とにかく作るといっても作るもののイメージがないことには始まらないので、作成対象を設計した。設計はQiitaのブログを表示した際のレイアウトを参考にした。
上記をもとに開発を進めていこうと思う。この記事は意思表示とレイアウト作成までとし、ここまでで終了する。記事も小分けに書いていかないと、大作化してしまい結局最後まで書かないと考えているからだ。
- 投稿日:2021-03-15T19:55:22+09:00
Reduxの基本をまとめてみた
はじめに
主に公式のチュートリアルを参照しながらReduxを勉強したので簡単に記事にまとめようと思います。
(React公式もそうですが、フロント系の公式ドキュメントは記載がとても丁寧で助かりますね。)
もし誤り等ありましたらコメントでご指摘いただけますと助かりますReduxとは?
UIが持つ状態(state)を管理するためのJSのライブラリです。(VueやAngularに使うこともできますが、Reactと最も相性が良いです。)
Reactのようなフロントのフレームワークにおいてコンポーネントのstateをどのように管理するかは、パフォーマンスやメンテナンス性にも関わる重要な命題であると思います。(僕自身よく頭を悩ませます。。)
Hooks(useReducer)を使用した管理方法などもありますが、Reduxはstoreというコンポーネントとは独立した場所でグローバルにstateを管理するライブラリです。基本的にstateの管理はローカルに行い、異なるコンポーネント間でstateを共有するときは共通の祖先コンポーネントまで遡るのが一般的なやり方かと思いますが、規模の大きなアプリケーションでstate管理がつらくなってきたときに導入を検討する類のライブラリのようです。
公式も「様々な場所に複雑な処理を行うstateが散りばめられた大きなアプリケーションで効果を発揮するライブラリである」みたいなことを言っており、Not all apps need Redux
とドキュメントに明記されています。基本的な流れ
Reduxでは、stateを管理するstoreに対し、処理に関する情報を持ったactionをdispatch(「送り込む/割り当てる」みたいなイメージ持っています)することにより、stateを更新します。
storeの中では、reducerという関数がdispatchされたactionを解釈し、更新した新しいstateを返します。action
アプリケーションに対する何かしらのイベントを表すもので、ユーザーによる操作をトリガーに生成されます。
実態はオブジェクトで、イベントの性質を表すtypeプロパティを持ちます。例えば、countというstateの数字に1を追加するようなactionであった場合、{ type: 'increment_count' }
のようなイメージです。store
stateをオブジェクトとして管理します。後述のreducerを渡して生成します。
既存のstateには、getStateメソッドをかけることでアクセスすることができます。
そしてこのstoreがdispatchメソッドを持っており、actionを引数にdispatchすることでstateの操作を行うことができます。その具体的な処理については、後述のreducerで行います。reducer
現在のstateとactionを引数として受け取り、stateを返す関数です。storeの中で機能します。
actionを解釈してstateの更新が必要であれば新しいstateを生成して返し、更新が必要なければ既存のstateをそのまま返すのが基本動作です。上述の要素がどのように関連しあってstateを更新しているかの流れは公式のフロー図がとっても分かりやすいです。
①ユーザーからの入力(ボタンを押すなど)がある
②actionがstoreにdispatchされる
③storeの中ではreducerが渡されたactionに基づいてstateを更新する
④新しいstateに基づいてUIが再レンダリングされるといった流れです。
簡単な実例
create-react-app
で作ったReactプロジェクトの簡単な実例です。
Upボタンを押せば表示の数字がカウントアップされ、Resetボタンを押せば0に初期化されるだけのごくごくシンプルなアプリケーションです。まずは
src/index.js
ファイルです。
ルートコンポーネントであるAppコンポーネントをreact-redux提供のProviderコンポーネントでラップし、Providerコンポーネントにインポートしたstoreを渡しております。このstoreに対して、既存stateの取得なりactionのdispatchなりをしていくことになります。src/index.jsimport React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import App from './App'; import store from './app/store'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );次に、そのstoreを定義している
src/app/store.js
ファイルです。
簡略的にreducerをここで定義し、store作成時に渡しています。
reducerではaction.typeを見て処理を判断し、stateを更新する必要がある場合は、新たにstateオブジェクトを生成して返しています。(既存のstate自体を変更するのでなく、新しいstateオブジェクトを生成して返すことがreducer関数では重要です。)src/app/store.jsimport { createStore } from 'redux'; const initialState = { count: 0, }; const reducer = (state = initialState, action) => { switch(action.type) { case 'increment_count': return { count: state.count + 1, }; case 'reset_count': return { count: 0, }; default: return state; } }; const store = createStore(reducer); export default store;次に、このように作成してReactと紐づけたstoreに対してどのようにアクセスするかですが、
src/App.js
を見てみましょう。
storeへのアクセスの方法のひとつとして、useSelectorとuseDispatchというHooksを利用することができます。
storeのstateの取得にはuseSelectorが使えます。引数ではどのstateが欲しいか指定する関数(selector)を渡します。またこのuseSelectorはstoreのstateの更新/差分を感知し、再レンダリングを行なってくれます。
useDispatchはstoreへのdispatchメソッドを提供してくれます。actionを引数にこれを呼べば、storeへdispatchすることができます。src/App.jsimport React from 'react'; import { useSelector, useDispatch } from 'react-redux'; function App() { const count = useSelector((state) => state.count); const dispach = useDispatch(); const increment = () => { dispach({ type: 'increment_count' }); }; const reset = () => { dispach({ type: 'reset_count' }); }; return ( <div className="App"> <p>Counter: {count}</p> <button onClick={increment}>Up</button> <button onClick={reset}>Reset</button> </div> ); } export default App;まとめ
Reduxの基本的な処理の流れを理解する良い機会になりました。React経験をもっと積んでケースに応じた適切なstate管理方法を選択できるようになりたいものです。
参考
https://redux.js.org
https://ics.media/entry/200409/
https://reffect.co.jp/react/react-redux-for-beginner
- 投稿日:2021-03-15T17:58:56+09:00
[Django REST Framework]でReactとのAPI連携
実行環境
MacOS BigSur -- 11.2.1
Python3 -- 3.8.2
Django -- 3.1.7
djangorestframework -- 3.12.2
npm -- 6.14.4
react -- 17.0.1
react-dom -- 17.0.1
axios -- 0.21.1Django REST Framework(DRF) を始めてみる
これまでDjangoのみを用いたWebアプリケーションの作成をしていましたが、フロントエンドの高度化ができず、DRFを用いてReactと組み合わせてみたい!!!と思いました。Reactに関してはまだ知識が少ないのですが、とりあえずDRFで作成したAPIをReactに渡す部分を実装をしたのでその手順をメモがてらに記述します。
DRFの続き(バックエンド)
前回の記事⇨
https://qiita.com/kachuno9/items/52a756f15207f625f358
でカスタムユーザーによるDRFプロジェクト作成は終わっているのでその続きからです。
ちなみに、ディレクトリ構成はこんな感じです。my_api ├── backend │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ ├── models.py │ ├── serializers.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── db.sqlite3 ├── manage.py ├── media └── my_api ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.pyModel
とりあえず簡単にPostモデルを作成しました。
models.pyclass Post(models.Model): title = models.CharField('タイトル', max_length=50) text = models.TextField('テキスト') created_at = models.DateField('作成日', auto_now_add=True) updated_at = models.DateField('更新日', auto_now=True) def __str__(self): return self.titleView
views.pyfrom django.shortcuts import render from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from backend import serializers from .models import Post class PostAll(APIView): def get(self, request): try: post = Post.objects.all().order_by('-created_at') res_list = [ { 'id': p.id, 'date': p.created_at, 'title': p.title, } for p in post ] return Response(res_list) except: return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)URL関連
さて、簡単なモデルとビューを作成したのでURLを設定します。
my_api/urls.pyfrom django.contrib import admin from django.urls import path, include from django.conf import settings urlpatterns = [ path('admin/', admin.site.urls), path('api/v1/', include('backend.urls')) ]backend/urls.pyfrom django.urls import path from backend import views urlpatterns = [ path('', views.PostAll.as_view()), ]動作確認
仮想環境内で、サーバーを立ち上げます。
$ python3 manage.py runserverhttp://localhost:8000/api/v1/
にアクセスすると、しっかりとAPIの動作確認が行えました。
ちなみにデータはadminサイトであらかじめサンプルようにいくつか追加しています。
Reactプロジェクト作成(フロント)
先程までとは別のターミナルを立ち上げて環境構築、プロジェクト作成を行います。アプリ名は「frontend」にしました。
$ npx create-react-app $ cd frontend $ npm install axios $ npm install react-router-dom $ npm startするとReacrのロゴが表示されるページが出てきて、正常にプロジェクト作成できた事がわかります。
ちなみに、frontend/srcのディレクトリ構成はこの通りです。frontend/src ├── App.css ├── App.js ├── App.test.js ├── index.css ├── index.js ├── reportWebVitals.js └── setupTests.jsReactとDRFの連携
さて、いよいよDRFとの連携を行います。DRFでは
http://localhost:8000/api/v1/
でデータを取得できるようにしているので、React側でここにGetリクエストを送るように実装します。axiosを用いることで簡単にリクエストを実装できるということで、インストールしました。App.jsimport React, { Component } from 'react'; import axios from 'axios'; class App extends Component { state = { posts: [] }; componentDidMount() { this.getPosts(); } getPosts() { axios .get('http://localhost:8000/api/v1/') .then(res => { this.setState({ posts: res.data }); }) .catch(err => { console.log(err); }); } render() { return ( <div> {this.state.posts.map(item => ( <div key={item.id}> <h1>{item.title}</h1> <p>{item.date}</p> </div> ))} </div> ); } } export default App;http://localhost:3000/
にアクセスするとしっかりDRFからデータを受け取っている事が分かります!!
今回はDRFとReactの連携が確認できたところまでです。
これまでバックエンドとフロントエンドを分けて開発するといった高度な開発経験がなかったので、DRFとReactが連携できただけですごく嬉しかったです(笑)
Reactに関してはまだまだ知識が少なく、見よう見まねですがこれから開発を進めていきたいと思います!!参考
以下のページが非常に分かりやすく、参考にさせていただきました。
- https://qiita.com/__init__/items/f5a5a64a05541fcda713#todo-api-%E3%81%AE%E6%A7%8B%E7%AF%89
- https://qiita.com/Piyopanman/items/5ffb9c290d452e0a5782
- https://qiita.com/Piyopanman/items/0a757a7b2dd412e07135
- 投稿日:2021-03-15T17:17:49+09:00
[react-calendar-heatmap] ReactでGitHubの草(カレンダー)を作る
react-calendar-heatmapというプラグインを使ってGitHubのcommitカレンダーグラフのようなものを実装しました
環境
OS macOS Big Sur 11.2.3 11.2.3
node v14.8.0
npm 7.5.4
React 17.0.1Reac.jsの環境構築
- ここではreact-heatmapという名前でプロジェクトを作成しています
//Create React App npx create-react-app react-heatmapreact-calendar-heatmapのインストール
yarn add react-calendar-heatmap npm install react-calendar-heatmap
- エラーが起きた場合
npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: react-heatmap@0.1.0 npm ERR! Found: react@17.0.1 npm ERR! node_modules/react npm ERR! react@"^17.0.1" from the root project npm ERR! npm ERR! Could not resolve dependency: npm ERR! peer react@"^16.8.0" from react-github-heatmap@1.0.7 npm ERR! node_modules/react-github-heatmap npm ERR! react-github-heatmap@"*" from the root project npm ERR! npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force, or --legacy-peer-deps npm ERR! to accept an incorrect (and potentially broken) dependency resolution.※ reactのバージョンが対応していないことが原因
npm i react-calendar-heatmap --legacy-peer-deps
- npm installする際に、インストールするライブラリのバージョンが、インストール先のプロジェクトのバージョンに対応していない場合、 オプションで、--legacy-peer-depsを使うことで、半強制的に?installできるようになるようです。
react-tiiltipのインストール
npm install react-tooltip
ソースコード
app.jsimport React from "react"; import "./App.css"; import CalendarHeatmap from "react-calendar-heatmap"; import "react-calendar-heatmap/dist/styles.css"; import ReactTooltip from "react-tooltip"; const App = () => { return ( <div className="container"> <h1>react-calendar-heatmap</h1> <div> <CalendarHeatmap // 表示させる月 startDate={new Date("2016-07-01")} endDate={new Date("2016-12-01")} values={[ { date: "2016-07-03", count: 1 }, { date: "2016-08-22", count: 2 }, { date: "2016-07-29", count: 4 }, { date: '2016-10-01', count: 1 }, { date: '2016-10-03', count: 2 }, { date: '2016-10-06', count: 3 }, { date: '2016-10-10', count: 4 }, { date: '2016-10-07', count: 1 }, { date: '2016-09-15', count: 3 }, // ...and so on ]} // color classForValue={(value) => { if (!value) { return "color-empty"; } return `color-scale-${value.count}`; }} tooltipDataAttrs={(value) => { if (!value || !value.date) { return null; } // react-tooltipの構成 return { "data-tip": `${value.date} has count: ${ value.count }`, }; }} /> </div> <ReactTooltip /> </div> ); }; export default App;app.css.react-calendar-heatmap .color-scale-1 { fill: #d6e685; } .react-calendar-heatmap .color-scale-2 { fill: #8cc665; } .react-calendar-heatmap .color-scale-3 { fill: #44a340; } .react-calendar-heatmap .color-scale-4 { fill: #1e6823; }参考
- 投稿日:2021-03-15T16:49:28+09:00
ReactHooksで映画検索アプリを作る
コード
https://github.com/kenta0313/react-hooked
コード解説
1.Header.js
components/Header.jsimport React from "react"; const Header = (props) => { return ( <header className="App-header"> <h2>{props.text}</h2> </header> ); }; export default Header;親要素からレンダリングしているだけです。
index.jsのファイルをインポートするのを忘れないでください。
index.jsimport App from './components/App';2.Movie.js
conponents/Movie.jsimport React from "react"; const DEFAULT_PLACEHOLDER_IMAGE = "https://m.media-amazon.com/images/M/MV5BMTczNTI2ODUwOF5BMl5BanBnXkFtZTcwMTU0NTIzMw@@._V1_SX300.jpg"; const Movie = ({ movie }) => { const poster = movie.Poster === "N/A" ? DEFAULT_PLACEHOLDER_IMAGE : movie.Poster; return ( <div className="movie"> <h2>{movie.Title}</h2> <div> <img width="200" alt={`The movie titled: ${movie.Title}`} src={poster} /> </div> <p>({movie.Year})</p> </div> ); }; export default Movie;こちらはAPIから取ってきた変数を引数に取っています。
3.Search.js
conponents/Search.jsimport React, { useState } from "react"; const Search = (props) => { const [searchValue, setSearchValue] = useState(""); const handleSearchInputChanges = (e) => { setSearchValue(e.target.value); } const resetInputField = () => { setSearchValue("") } const callSearchFunction = (e) => { e.preventDefault(); props.search(searchValue); resetInputField(); } return ( <form className="search"> <input value={searchValue} onChange={handleSearchInputChanges} type="text" /> <input onClick={callSearchFunction} type="submit" value="SEARCH" /> </form> ); } export default Search;まず、useStateで検索欄の初期値を空に設定してます。
handleSearchInputChangesで検索欄へ入力できるようにしています。(これがなかったら入力できないです。)
resetInputFieldが呼ばれると検索欄が空になりなす。
- 投稿日:2021-03-15T15:35:29+09:00
【JavaScript】別ファイルに関数をまとめてexportsを利用して呼び出す。
開発環境
React.js
概要
JavaScriptで関数を共通化して別ファイルにまとめたときに、HTMLのscriptタグを使い呼び出すのは面倒だと思いました。JavaScriptのexportsを使い呼び出すことができることを知りましたので記事にしておきます。
import.jsとexport.jsファイルを作成
import.jsからexport.jsの関数を呼び出していきます。
export.jsexports.criminalIsKogoro = function () { console.log("犯人は毛利小五郎"); } exports.detectiveCriminal = function (name) { console.log("犯人は" + name); } const criminalIsAgasa = function () { console.log("犯人は阿笠だ"); }比較するためにcriminalIsAgasaだけはexportsしないようにしておきます。
import.jsimport exportFunction from 'export.jsのパスを記述' // または // var exportFunction = require('export.jsのパスを記述'); exportFunction.criminalIsKogoro; // "犯人は毛利小五郎" exportFunction.detectiveCriminal("元太"); //"犯人は元太" exportFunction.criminalIsAgasa; // error. exportFunction.criminalIsAgasa is not a functionこのようにexportsをしておかないと外部のファイルから読み込むことができないことが分かりました。
参考
- 投稿日:2021-03-15T15:35:29+09:00
【React.js】別ファイルに関数をまとめてexportsを利用して呼び出す。
開発環境
React.js
概要
React.jsで関数を共通化して別ファイルにまとめたときに、HTMLのscriptタグを使い呼び出すのは面倒だと思いました。JavaScriptのexportsを使い呼び出すことができることを知りましたので、備忘録として記事に残しておきます。
import.jsとexport.jsファイルを作成
import.jsからexport.jsの関数を呼び出していきます。
export.jsexports.criminalIsKogoro = function () { console.log("犯人は毛利小五郎"); } exports.detectiveCriminal = function (name) { console.log("犯人は" + name); } const criminalIsAgasa = function () { console.log("犯人は阿笠だ"); }比較するためにcriminalIsAgasaだけはexportsしないようにしておきます。
import.jsimport exportFunction from 'export.jsのパスを記述' // または // var exportFunction = require('export.jsのパスを記述'); exportFunction.criminalIsKogoro; // "犯人は毛利小五郎" exportFunction.detectiveCriminal("元太"); //"犯人は元太" exportFunction.criminalIsAgasa; // error. exportFunction.criminalIsAgasa is not a functionこのようにexportsをしておかないと外部のファイルから読み込むことができないことが分かりました。
参考
- 投稿日:2021-03-15T15:07:00+09:00
laravelとreact 一緒に使うけど 厳密に言うと APIじゃない件について
めっちゃ時間無駄にしたので戒めのためのメモ
状況
laravelで作ったサービスをあとからreact化しようとした際 遭遇
axiosにて記事情報を post すると 何故か リレーションしているuser_idがnillになり処理が完了しない。結論
・routes/api.phpにかかない
普通にweb.phpに書くここに書くとpostするとauthのガードに引っかかってuser_idがnillになってエラー
※
ちなみに私は トークン とかいろいろ 迷子になって laravel passportまでいれて結局関係にことにあとで気づきました・・。 勉強にはなったが。。。
- 投稿日:2021-03-15T13:58:03+09:00
React 入門 (#2) ~Babel&JSX~
1,Babelとは
ES6以降のスクリプトを、ES2015基準のスクリプトにトランスパイルする機能です。
下記のタグをheadタグに記述すれば準備完了です。
index.html<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>2,JSXを使う理由
Reactはマークアップとロジックを両方含む疎結合の「コンポーネント」という単位で構成されます。
「コンポーネント」は、次回説明します。
そこで活躍するのが、JSX(「JavaScript XML」の略)です。
Reactのコンポーネント内で、マークアップ言語を記述するためのXML風の構文です。3、ソースコードを記述
前回からの続きになります。
まず、index.htmlの準備です。
toUpperCase()は、すべて大文字にするメソッドです。
4,ブラウザ表示
次回は、
コンポーネントについて扱っていきます。
次回はここへ
- 投稿日:2021-03-15T13:50:57+09:00
React入門 環境構築(for mac)(nodebrew)
まず、Homebrewをインストールします。
Homebrew公式サイト[https://brew.sh/index_ja]公式から引用$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" $ brew -v #バージョンが出ればインストールできています。Homebrewを使って、nodebrewをインストール
$ brew install nodebrew $ nodebrew -v #バージョンが出ればインストールできています。$ nodebrew install-binary stable
stable
は安定バージョンです。
latest
は最新バージョンです。
今回は安定バージョンを使用しています。$ nodebrew ls v14.16.0 current: v14.16.0
current:
は使用しているバージョンです$ nodebrew use (バージョン)
nodebrew ls
実行し、反映されていたら大丈夫です。
$ vi ~/.bash_profile
でしたの行を追加export PATH=$HOME/.nodebrew/current/bin:$PATH
$ node -v
と$ npm -v
でバージョンが出たら完了です。$ npx create-react-app ファイル名 $ cd ファイル名 $ yarn start #起動コマンドこれで開発環境完成です。
- 投稿日:2021-03-15T13:11:48+09:00
色々めんどくさいのでDjango REST API+React/TypeScriptでアプリ作ってみる2
統合開発環境
VSC
VSCに拡張機能を追加していきます。
・Prettier - Code formatter
・ES7 React/Redux/GraphQL/React-Native snippetsReactのプロジェクトを作成していきます。
ターミナルに以下を入力していきます。
npx create-react-app . --template redux-typescript --use-npm
ダウンロードが完了すればHappy hacking!と帰ってきます。
Inside that directory, you can run several commands: npm start Starts the development server. npm run build Bundles the app into static files for production. npm test Starts the test runner. npm run eject Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back! We suggest that you begin by typing: cd C:\Users\xxx\Desktop\xxx npm start Happy hacking!続いて使用するモジュールをダウンロードしていきます。
axios,
ブラウザや node.js で動く Promise ベースの HTTP クライアントである。 REST-API を実行したいときなど、これを使うと実装が簡単にできる。
npm i axios結果.axios@0.21.1 added 1 package from 1 contributor and audited 1993 packages in 12.982s 133 packages are looking for funding run `npm fund` for details found 0 vulnerabilitiesReactのラウターということでログイン用のページとタスク管理のページをラウターで線を引いてきますので
react-rotuer-dom をインストールしていきます。
npm i react-rotuer-dom @types/react-rotuer-dom結果.found 0 vulnerabilitiesマスターをインストール
npm i @material-ui/icore @material-ui/lab結果.found 0 vulnerabilitiesモジュールがインストールができたらReactサーバーをスタートします。
npm start立ち上げが完了しました。
社内でReactを立ち上げる際にnpx create-react-appでエラーができるときまたは、npmが通らないとき
原因=プロキシサーバー
対策↓
npm -g config set proxy プロシキ:xxx npm -g config set https-proxy プロシキ:xxx npm -g config set registry http://registry.npmjs.org/ npm -g config set strict-ssl=falseこのようにconfigを変えてあげると create-react-appが実行できるようになります。
- 投稿日:2021-03-15T13:05:33+09:00
Node.js開発者なら知っておきたい便利なパッケージ12選
本記事は、Indrek Lasn氏による「12 Useful Packages Every Node.js Developer Should Know」(2020年9月2日公開)の和訳を、著者の許可を得て掲載しているものです。
Node.js開発者なら知っておきたい便利なパッケージ12選
毎日の生産性を上げるNodeパッケージ
はじめに
Node.jsはコードの再利用にぴったりです。コードを再利用するための根幹となるのはNPMパッケージです。
NPMパッケージは、時間と労力を大幅に節約してくれます。日付ライブラリが必要ですか?パッケージがあります。ユーティリティライブラリが必要ですか?問題ありません。コードの問題解決が必要な時はいつでも、必要に応じたパッケージがあるでしょう。
これは、すべてのNode.js開発者が知っておくべきパッケージのリストです。このNPMパッケージは、時間を節約し、魔法のように解決する助っ人のようなものです。
1. husky
huskyはgitフックの実装を簡単にしてくれます。チームで仕事をしていて、チーム全体にコーディング規約を適用したいと思うことはありませんか?問題ありません!huskyを使えば、リポジトリにコミットしたりプッシュしたりする前に、コードを自動的にlintしてテストするように全員に要求できます。
husky ― https://github.com/typicode/huskyインストール方法
yarn add husky
使い方
huskyフックの実装例です。
// package.json { "husky": { "hooks": { "pre-commit": "npm lint", "pre-push": "npm test" } } }huskyexample.json
huskyフック例
pre-commit
フックは、リポジトリにコミットする前に実行されます。
pre-push
フックは、コードをリポジトリにプッシュする前に実行されます。2. dotenv
dotenvは、環境変数を
.env
ファイルからprocess.env
にロードするゼロ依存モジュールです。コードとは別の環境に設定を保存することは、The Twelve-Factor Appの方法論に基づいています。
dotenvインストール方法
yarn add dotenv
使い方
アプリケーションのできる限り早い段階で、dotenvを要求して設定します。
require('dotenv').config()
プロジェクトのルートディレクトリに
.env
ファイルを作成します。NAME=VALUE
の形式で、新しい行に環境固有の変数を追加します。例:
DB_HOST=localhost DB_USER=root DB_PASS=s1mpl3
process.env
で、.env
ファイルで定義したキーと値が使えるようになりました。const db = require('db') db.connect({ host: process.env.DB_HOST, username: process.env.DB_USER, password: process.env.DB_PASS })3. date-fns
lodashに似ていますが、date-fnsは日付のためのものです。日付の操作をもっと簡単にするユーティリティ関数がたくさんあります。
date-fnsは、ブラウザやNode.jsでJavaScriptの日付を操作するため、総合的かつシンプルで一貫性のあるツールセットを提供します。
date-fns
date-fns ― https://github.com/date-fns/date-fnsインストール方法
yarn add date-fns
使い方
date-fnsライブラリの簡単な例です。
import { compareAsc, format } from 'date-fns' format(new Date(2014, 1, 11), 'yyyy-MM-dd') //=> '2014-02-11' const dates = [ new Date(1995, 6, 2), new Date(1987, 1, 11), new Date(1989, 6, 10), ] dates.sort(compareAsc) //=> [ // Wed Feb 11 1987 00:00:00, // Mon Jul 10 1989 00:00:00, // Sun Jul 02 1995 00:00:00 // ]その他の事例や使用例については、ドキュメントを確認してください。
4. bunyan
bunyan は、分かりやすくてパフォーマンスが高いNode用のJSONロギングライブラリです。
bunyan ― https://github.com/trentm/node-bunyanインストール方法
yarn add bunyan
コツ:
bunyan
CLIツールは、すべてのバージョンのbunyanのログと(合理的な範囲内で)互換性があるようになっています。そのため、yarn add global bunyan
でグローバルbunyanをインストールしてbunyan CLIをPATHに追加してから、ローカルbunyanをインストールして、アプリでbunyanのNode.jsライブラリを使うと良いでしょう。使い方
bunyanはシンプルで高速なNode.jsサービス用のJSONロギングライブラリです。
// hi.js const bunyan = require('bunyan'); const log = bunyan.createLogger({name: "myapp"}); log.info("hi");
node hi.js
を実行するとコンソールに返される内容は、次の通りです。5. ramda
rambda は JavaScript プログラマ向けの実用的で機能的なユーティリティライブラリです。rambdaは、より純粋な機能性を重視しています。
不変性と副作用のない関数は、rambdaの設計哲学の中心です。これにより、シンプルで洗練されたコードで仕事を成し遂げられます。
rambda ― https://github.com/ramda/ramdaインストール方法
$ yarn add ramda
使い方
import * as R from 'ramda' const greet = R.replace('{name}', R.__, 'Hello, {name}!'); greet('Alice'); //=> 'Hello, Alice!'6. debug
debugはNode.jsコアのデバッグ手法をモデルにした、小さなJavaScriptデバッグユーティリティです。
debug ― https://github.com/visionmedia/debugインストール方法
$ yarn add debug
使い方
debug
には、モジュール名を渡すだけでconsole.error
の装飾版を返し、debugステートメントを渡す関数があります。const debug = require('debug'); const log = debug('http:server'); const http = require('http'); const name = 'My App name'; log('booting %o', name); http.createServer((req, res) => { log(req.method + ' ' + req.url); res.end('debug examplen'); }).listen(3200, () => { log('listening'); }); // run this command in the terminal // DEBUG=http:server node app.jsapp-debug-example.js
debug例これによりデバッグ出力を、モジュール全体だけでなく、モジュールのさまざまな部分で切り替えられます。
7. flat
flat は、ネストされたJavascriptオブジェクトを取得して平坦化します。区切りキーを使って、オブジェクトの平坦化を解除することもできます。
flat ― https://github.com/hughsk/flatインストール方法
$ yarn add flat
使い方
const flatten = require('flat') flatten({ key1: { keyA: 'valueI' }, key2: { keyB: 'valueII' }, key3: { a: { b: { c: 2 } } } }) // { // 'key1.keyA': 'valueI', // 'key2.keyB': 'valueII', // 'key3.a.b.c': 2 // }8. JSON5
JSON5 データ交換フォーマットはJSON* のスーパーセットで、ECMAScript 5.1のプロダクションの一部を含めるために構文を拡張し、JSONの制限の一部を緩和します。
JSON5
json5 ― https://github.com/json5/json5インストール方法
yarn add json5 const JSON5 = require('json5')使い方
ファイル拡張子に注意してください。JSON5は、JSONの拡張機能とスーパーセットです。
{ // comments unquoted: 'and you can quote me on that', singleQuotes: 'I can use "double quotes" here', lineBreaks: "Look, Mom! \ No \\n's!", hexadecimal: 0xdecaf, leadingDecimalPoint: .8675309, andTrailing: 8675309., positiveSign: +1, trailingComma: 'in objects', andIn: ['arrays',], "backwardsCompatible": "with JSON", }9. ESLint
ESLintは、バグを回避し、開発チームにコーディング規約を適用する素晴らしいツールです。ECMAScript/JavaScriptコードで見つかったパターンを識別して報告します。
ESLint ― https://github.com/eslint/eslintインストール方法・使い方
$ yarn add eslint
次に、設定ファイルの作成が必要です。
$ ./node_modules/.bin/eslint --init
その後、任意のファイルやディレクトリでESLintを実行できます。
$ ./node_modules/.bin/eslint yourfile.js
詳しくは、公式ドキュメントを確認してください。始め方と設定の例がたくさんあります。
10. PM2
PM2は、Node.jsアプリケーション用のプロダクションプロセスマネージャーで、ロードバランサーを内蔵しています。これにより、アプリケーションを永続化させ、ダウンタイムなしでリロードし、一般的なシステム管理タスクを容易にできます。
pm2 ― https://github.com/Unitech/pm2インストール方法
$ yarn add global pm2
使い方
任意のアプリケーション(Node.js、Python、Ruby、$PATHのバイナリ等)を起動できます。
$ pm2 start app.js
アプリはデーモン化され、監視され、永続化します。プロセス管理の詳細はこちら。
アプリケーション管理
起動したアプリケーションを簡単に管理できます。実行中のすべてのアプリケーションを一覧表示する方法は次の通りです。
$ pm2 ls
機能と活用方法の全リストは、公式ドキュメントを確認してください。
11. helmet
helmetライブラリは、さまざまなHTTPヘッダを設定することでExpressアプリを保護するのに役立ちます。「特効薬ではないが、助けにはなる!」
helmet ― https://github.com/helmetjs/helmetインストール方法
yarn add helmet
使い方
helmet はConnectスタイルのミドルウェアで、Expressなどのフレームワークと互換性があります(Koaのサポートが必要な場合は、
koa-helmet
を確認してください)。const express = require("express"); const helmet = require("helmet"); const app = express(); app.use(helmet());トップレベルの
helmet
の関数は、11個の小さなミドルウェアのラッパーです。言い換えれば、この2つは同等です。// This... app.use(helmet()); // ...is equivalent to this: app.use(helmet.contentSecurityPolicy()); app.use(helmet.dnsPrefetchControl()); app.use(helmet.expectCt()); app.use(helmet.frameguard()); app.use(helmet.hidePoweredBy()); app.use(helmet.hsts()); app.use(helmet.ieNoOpen()); app.use(helmet.noSniff()); app.use(helmet.permittedCrossDomainPolicies()); app.use(helmet.referrerPolicy()); app.use(helmet.xssFilter());12. compression
compressionライブラリはNode.jsの圧縮ミドルウェアです。
compression ― https://github.com/expressjs/compressionインストール方法
$ yarn add compression
使い方
このモジュールをexpressやconnectで使うには、expressミドルウェアでcompressionを呼び出すだけです。ミドルウェアを通過したリクエストは圧縮されます。
const compression = require('compression') const express = require('express') const app = express() // compress all responses app.use(compression()) // ...おわりに
私のニュースレターでは、コンテンツの最新情報の通知を、いち早く受け取ることができます。ぜひ登録してください。
Zack Shapiroに謝意を表します。
翻訳協力
この記事は以下の方々のご協力により公開する事ができました。改めて感謝致します。
Original Author: Indrek Lasn (@lasnindrek)
Original Article: 12 Useful Packages Every Node.js Developer Should Know
Thank you for letting us share your knowledge!選定担当: @gracen
翻訳担当: @gracen
監査担当: -
公開担当: @gracenご意見・ご感想をお待ちしております
今回の記事はいかがでしたか?
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。
頂いたお声は、今後の記事の質向上に役立たせて頂きますので、お気軽に
コメント欄にてご投稿ください。Twitterでもご意見を受け付けております。
皆様のメッセージをお待ちしております。
- 投稿日:2021-03-15T12:20:49+09:00
色々めんどくさいのでDjango REST API+React/TypeScriptでアプリ作ってみる1
環境構築
こちらを参考に構築していただければと思います(WIN構築)
Djangoの画面が確認できたところから作っていきたいと思います。
はじめに、バックエンドAPIを作成していくためにAPIの設定とフロントへのつなぎ口を記述していきます。
settingの中身を書き換えていきます。
""" Django settings for xxx_api project. Generated by 'django-admin startproject' using Django 3.1. For more information on this file, see https://docs.djangoproject.com/en/3.1/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/3.1/ref/settings/ """ from pathlib import Path import os from datetime import timedelta # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'v)yfl4pl$p=y2t+@c3!0*%2w-&m%sp8j-g#g-1o-!n%sl=5s+*' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'corsheaders', #add 'rest_framework', #add 'api.apps.ApiConfig', #add 'djoser', #add ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', CORS_ORIGIN_WHITELIST = [ "http://localhost:3000" #reactの通路を開ける設定 ] ROOT_URLCONF = 'xxx_api.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'xxx_api.wsgi.application' REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ], 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_simplejwt.authentication.JWTAuthentication', ], } SIMPLE_JWT = { 'AUTH_HEADER_TYPES': ('JWT',), 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30), } # Database # https://docs.djangoproject.com/en/3.1/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Password validation # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/3.1/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'Asia/Tokyo' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.1/howto/static-files/ STATIC_URL = '/static/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/'INSTALLED_APPS内の説明
djoserを使ったDjango REST FrameworkでのJWT認証機能の実装を行っています
api.apps.ApiConfig = api アプリケーション()データベース
今回はsqliteを使用しています。
xxx_api/urls.py
""" The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.1/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path, include from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('api.urls')), path('authen/', include('djoser.urls.jwt')), ] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)api/urls.py
from django.urls import path, include from rest_framework import routers router = routers.DefaultRouter() urlpatterns = [ path('', include(router.urls)), ]api/model.py
from django.db import models from django.contrib.auth.models import User from django.core.validators import MinValueValidator import uuid def upload_avatar_path(instance, filename): ext = filename.split('.')[-1] return '/'.join(['avatars', str(instance.user_profile.id) + str(".") + str(ext)]) class Profile(models.Model): user_profile = models.OneToOneField( User, related_name='user_profile', on_delete=models.CASCADE ) img = models.ImageField(blank=True, null=True, upload_to=upload_avatar_path) def __str__(self): return self.user_profile.username class Category(models.Model): item = models.CharField(max_length=100) def __str__(self): return self.item class Task(models.Model): STATUS = ( ('1', 'Not started'), ('2', 'On going'), ('3', 'Done'), ) id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False) task = models.CharField(max_length=100) description = models.CharField(max_length=300) criteria = models.CharField(max_length=100) status = models.CharField(max_length=40, choices=STATUS, default='1') category = models.ForeignKey(Category, on_delete=models.CASCADE) estimate = models.IntegerField(validators=[MinValueValidator(0)]) owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owner') responsible = models.ForeignKey(User, on_delete=models.CASCADE, related_name='responsible') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return self.taskC:\Users\xxx\PycharmProjects\xxx_api>python manage.py makemigrations Migrations for 'api': api\migrations\0001_initial.py - Create model Category - Create model Task - Create model Profile C:\Users\xxx\PycharmProjects\xxx_api>python manage.py migrate Operations to perform: Apply all migrations: admin, api, auth, contenttypes, sessions Running migrations: Applying api.0001_initial... OKadmin.pyを設定すると
from django.contrib import admin from .models import Category, Task, Profile admin.site.register(Category) admin.site.register(Task) admin.site.register(Profile)上記が追加されます。
これで削除・編集・追加・更新が可能となりました
serializers(返値の詳細を決めれるやつ)
1.apiの直下にNEWファイルserializers.pyファイルを作成します。
2.必要なモジュールをimportします
serializers.pyfrom resr_framework import serializers from .models import Task,Category Profile from django.contrib.auth.models import User class UserSerializer(Serializer.ModeSerializer): class Meta: model = User fields = ['id','username','password'] extra_kwargs = {'password':{'write_only':True, 'required': True}} def create(self, validated_date): user = User. class UserSerializer(Serializer.ModeSerializer): class Meta: model = User fields = ['id','username','password'] extra_kwargs = {'password':{'write_only':True, 'required': True}} def create(self, validated_date): user = User.objects.create_user(**validated_date) return user class Profileserializers(serializers.Modelserializer): class Meta: model = profile fields = ['id', 'user_profile', 'img'] extra_kwargs = {'user_profile':{'read_only': True}} class Categoryserializers(serializers.Modelserializer): class Meta: model = Category fields = ['id','item'] class Taskserializers(serializers.Modelserializer): category_item = serializers.ReadOnlyField(source='category.item', read_only=True) owner_username = serializers.ReadOnlyField(source='owner.username', read_only=True) responsible_username = serializers.ReadOnlyField(source='responsible.username', read_only=True) status_name = serializers.CharField(source='get_status_display', read_only=True) class Meta: model = Taskpython manage.py migrate でデータベースに情報を落とししていく。
- 投稿日:2021-03-15T11:54:39+09:00
Material-UIで一覧画面を作ってみる(React)
はじめに
今回は、Material-UIの使い方や使ってみた所感を書いていきたいと思います。
Material-UIとは
Material-UIとは、Googleのマテリアルデザインの仕様を取り入れているReact用のUIコンポーネントライブラリです。Material-UIを利用することで手軽に見栄えの良いコンポーネントを作成することができます。
マテリアルデザインとは
マテリアルデザインとは、Googleが提唱している物質的なデザインのガイドラインです。スマートフォンやタブレットなどのタッチデバイスの普及により直感的に操作ができるUIへの需要が高まってきた中で生まれた概念です。
環境
今回の使用バージョンはそれぞれ以下の通りです。
- Node.js v12.19.0
- React v16.13.1
- @material-ui/core v4.11.0
Material-UIの導入
次のコマンドを実行し、Material-UIをインストールします。
# npmの場合 npm install @material-ui/core # yarnの場合 yarn add @material-ui/coreディレクトリ構成
ディレクトリ構成は以下のようになります。今回はあくまでも簡単なページを作成することを目的としているため、Reactを使用しシステムを作成する場合は、様々な構成を調査し作成したいシステムに合った構成を探してみてください!
src/ ├ components/ │ └ header.js │ └ card.js ├ pages/ │ └ _app.js │ └ _document.js │ └ index.js └ public/ │ └ image/ │ └ ika.png └ package.json早速使ってみる
今回は公式ドキュメントのソースコードを参考に一覧画面を作成しながら、Material-UIによって作成できるコンポーネントを紹介していきます。
ページの骨組みを用意する
これから作成するコンポーネント達を配置するために、ページの骨組みを用意します。
pages/index.jsimport { Header } from '../components/header'; import { Card } from '../components/card'; const Index = () => ( <div> <Header /> <Card /> </div> ) export default Index表示させてもまだ何もないので真っ白のページが表示されますが、確認方法を説明します。
以下のコマンドでローカルホストを立ち上げ、http://localhost:3000/
にアクセスすることで確認できます。# npmの場合 npm run dev # yarnの場合 yarn dev※
components/header.js
などインポート宣言しているファイルを作成していないとエラーになるのでご注意ください。ヘッダーを作成してみる
まずはWebサイトには欠かせないヘッダーを作成していきます。早速書いてみましょう!
実際のコードは以下になります。components/header.jsexport const Header = () => { const classes = useStyles(); return ( <div className={classes.root}> <AppBar position="static"> <Toolbar> <IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu"> <MenuIcon /> </IconButton> <Typography variant="h6" className={classes.title}> TOP </Typography> <Button color="inherit">Login</Button> </Toolbar> </AppBar> </div> ); }
Appbar
やTypography
などのタグはインポートをすることで使用できます。
className={classes.root}
の記述ではタグにクラス属性を付与し、見た目を調整することができます。結果は以下になります。シンプルなヘッダーを作成することができました。
せっかくなのでメニューアイコンを動くようにしてみましょう!以下のように書いていきます。
components/header.jsexport const Header = () => { const classes = useStyles(); const theme = useTheme(); // stateとstateを更新するための関数を宣言 const [open, setOpen] = React.useState(false); // メニューを開く関数 const handleDrawerOpen = () => { setOpen(true); }; // メニューを閉じる関数 const handleDrawerClose = () => { setOpen(false); }; return ( <div className={classes.root}> <CssBaseline /> <AppBar position="fixed" className={clsx(classes.appBar, { [classes.appBarShift]: open, })} > <Toolbar> {/* メニューアイコンクリック時に呼び出す関数を定義 */} <IconButton color="inherit" aria-label="open drawer" onClick={handleDrawerOpen} edge="start" className={clsx(classes.menuButton, open && classes.hide)} > <MenuIcon /> </IconButton> <Typography variant="h6" noWrap> TOP </Typography> </Toolbar> </AppBar> {/* メニュー部分 */} <Drawer className={classes.drawer} variant="persistent" anchor="left" open={open} classes={{ paper: classes.drawerPaper, }} > <div className={classes.drawerHeader}> {/* 閉じるアイコンクリック時に呼び出す関数を定義 */} <IconButton onClick={handleDrawerClose}> {theme.direction === 'ltr' ? <ChevronLeftIcon /> : <ChevronRightIcon />} </IconButton> </div> <Divider /> <List> {links.map((link) => ( <ListItemLink href={link.link} key={link.id}> <ListItemText primary={link.label} /> </ListItemLink> ))} </List> </Drawer> <main className={clsx(classes.content, { [classes.contentShift]: open, })} > </main> </div> ); }先ほどのシンプルなヘッダーに比べて記述量は増えましたが、簡単ですね。
Reactではコンポーネントの状態を管理するためにstate
を使用します。stateの更新にはsetState
を使用します。この例ではメニューアイコンをクリックしたときにメニューを開くために、open
というstateで状態を管理しています。無事動かすことができました!
コンテンツを作成する
続いてコンテンツを作成します。今回はカードを並べるような感じでコンテンツを一覧表示させますので、カードのコンポーネントを作成していきます。
components/card.jsexport const Card = () => { const classes = useStyles(); return ( <div className={classes.main}> <Card className={classes.root}> <CardActionArea> <CardMedia className={classes.media} image="イメージパス" title="Contemplative Reptile" /> <CardContent> <Typography gutterBottom variant="h5" component="h2"> タイトル </Typography> <Typography variant="body2" color="textSecondary" component="p"> 説明 </Typography> </CardContent> </CardActionArea> <CardActions> <Button size="small" color="primary"> Share </Button> <Button size="small" color="primary"> Learn More </Button> </CardActions> </Card> </div> ); }以下のような一覧画面ができました。(上記のコードは1枚のカードを生成するコードです。)
レスポンシブ対応について
ちなみに今回作成したページはレスポンシブ対応になっています。スマートフォンで表示したときは以下のような表示になります。驚きなのが、特にレスポンシブ対応のための実装はしていないことです。便利ですね
今回はMaterial-UIを使用し、このような一覧画面を作成することができました。簡単に見た目の良いページを作成でき扱いやすさを感じました!
あとがき
Webシステムのクオリティを上げるには処理の精度を上げることと並行してデザインも重要ですよね。私自身、最近の業務でデザイナーさんの力を全力で感じています。
ただ、システム作成の際に見栄えを良くしたいと思ってもデザインに割く時間が無かったり、デザイナーさんに頼めないという場面もあるかと思います。そんな時は今回紹介したMaterial-UIなどのUIフレームワークを利用してみるのもいいかもしれません。Material-UI以外にも多種多様なUIフレームワークが用意されていますので気になった方はぜひ一度使ってみてください。最後までお読みいただき、ありがとうございました
参考資料
- 投稿日:2021-03-15T08:01:27+09:00
M1 MacでLIFFとReactを使う際の環境構築
初めに
2021年3月の現在、Open Hack U 2020 Online Vol.4に挑戦しています。
チームの制作物で、LIFF (LINE Front-end Framework)を使ったものを作成することにしました。
M1 Macbook AirでLIFFを使うのは、初めてです。
そこで、環境構築などで詰まったところを書いておき、再度M1 MacでLIFFを使うときにつまらないようにするための備忘録です。本記事の目的
本記事は、ハッカソンなどで、M1 Macbookを使う人のために書きました。
色々なアプリを作る時の候補として、LIFFを使ったアプリ開発に挑戦してみては、いかがでしょうか?詰まったところ
参考記事1を進めていたところ、
yarn
がうまく使えないことがわかりました。
そのため、現時点でのM1チップのMacでは、yarn
を使うのをやめましょう。最終的なコード
最終的に作成したアプリは、こちらです。
メッセージを送信し、GoogleをChrome(デフォルトに設定してあるアプリ)で開き、友達に
メッセージを送ることができるようにしています。進める中でインストールしたアプリ
https://dashboard.ngrok.com/get-started/setup
デプロイ先作成したアプリ
参考記事
- 投稿日:2021-03-15T06:01:19+09:00
React 入門 (#1) ~DOM操作とReactライブラリ導入~
この記事では、Reactの基礎について学んでいきます。
ソースコードとブラウザ表示を中心に進めていきます。
ソースコードには、そのコードが何を表しているのかを話し口調(下の赤枠)で書いているので
そこに注目して読むとより理解が深まると思います。楽しんで学習をすすめていきましょう。
1,JavaScriptを記述してDOMの操作を行ってみます。
index.htmlにリンクしているindex.js(JavaScript)です。
2,実際に上のソースコードの動きを確認してみましょう。
とてもシンプルな動きですね。
これが、JavaScript によるDOM操作になります。3,Reactライブラリの導入
上のサイトから、追記したソースコードをコピーしてください。
もしくは、こちらをコピーしてください。index.html//追記 ReactライブラリとReactDOMライブラリ <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>Reactを使うには、
ReactライブラリとReactDOMライブラリを使います。
これで、準備完了です。4,ブラウザ表示
index.htmlにはdivタグしかないですが、ちゃんと表示されていますね。
次回は、
今回は、Reactの機能の部分を簡単に紹介しました。
次回は、Reactを学ぶうえで大事なBabelとJSXに触れたいと思います。
リンク
- 投稿日:2021-03-15T04:28:28+09:00
material-ui DataGridのpaginationラベルをローカライズしたい
DataGridのテキストローカライズ
DataGrid用のローカライズpropは
localeText
にオブジェクト入れればできるんですが、デフォルトのソースを見る限りではフッターのパジネーション部分のキーがありませんでした。TablePaginationが利用されている
DataGrid内部ではmaterial-uiのcoreで提供されている
TablePagination
を使っているみたいでした。なので、単純に
createMuiTheme
からデフォルトpropを変更すれば良さそうです。labelDisplayedRows propの上書き
createMuiTheme > props > MuiTablePagination > labelDisplayedRowsにカスタマイズしたいように置くだけです。
const theme = createMuiTheme({ props: { MuiTablePagination: { labelDisplayedRows: ({ from, to, count, }: LabelDisplayedRowsArgs) => { return `${from}-${to} / ${count !== -1 ? count : `${to}以上`}`; }, }, }, });
- 投稿日:2021-03-15T02:09:55+09:00
Laravel8 ReactHooks & MySQL Create処理
やりたいこと
フロントはReactHooksを使用して、LaravelはAPIサーバーでバックエンド処理をおこなう。
バックエンド処理はaxiosを使用。完成図
開発環境
- Laravel 8.0
- php 7.3
- MySQL 8
State
- const [ name, setName ] = useState(null);
入力値name(名前)のState
- const [ email, setEmail ] = useState(null);
入力値email(メールアドレス)のState
- const [ city, setCity ] = useState(null);
入力値city(住所)のState
- const [ address, setAddress ] = useState(null);
入力値address(市区町村)のState
- const [ phone, setPhone ] = useState(null);
入力値phone(電話番号)のState
入力フォーム
map処理はkeyを明示する必要があるので注意
keyの明示についてはVirtualDOMのdiffから実際のDOMに反映させるときに最小限の変更にするために使われる。
formimport React, { useEffect, useState } from 'react'; import employeeServices from "../services/Employee" function Form(){ const [ name, setName ] = useState(null); const [ email, setEmail ] = useState(null); const [ city, setCity ] = useState(null); const [ address, setAddress ] = useState(null); const [ phone, setPhone ] = useState(null); const [ rol, setRol ] = useState(null); const [ listRol, setListRol ] = useState([]); useEffect(() => { async function fetchDataRol() { // load data from API const res = await employeeServices.list(); setListRol(res.data) } fetchDataRol(); },[]); const saveEmployee = async () => { const data = { name, email, city, address, phone, rol } const res = await employeeServices.save(data); if (res.success) { alert(res.message) } else { alert(res.message) } } return( <div> <div className="row"> <div className="col-md-6 mb-3"> <label htmlFor="firstName">Name employee </label> <input type="text" className="form-control" placeholder="Name" onChange={(event)=>setName(event.target.value)} /> </div> </div> <div className="row"> <div className="col-md-6 mb-3"> <label htmlFor="email">Email</label> <input type="email" className="form-control" placeholder="you@example.com" onChange={(event)=>setEmail(event.target.value)} /> </div> </div> <div className="row"> <div className="col-md-6 mb-3"> <label htmlFor="phone">City </label> <select id="inputState" className="form-control" onChange={(event)=> setCity(event.target.value)}> <option selected>Choose...</option> <option value="London">London</option> <option value="Madrid">Madrid</option> <option value="New York">New York</option> </select> </div> </div> <div className="row"> <div className="col-md-6 mb-3"> <label htmlFor="address">Address</label> <input type="text" className="form-control" placeholder="1234 Main St" onChange={(event)=>setAddress(event.target.value)} /> </div> </div> <div className="row"> <div className="col-md-6 mb-3"> <label htmlFor="phone">Phone </label> <input type="text" className="form-control" placeholder="123467890" onChange={(event)=>setPhone(event.target.value)} /> </div> </div> <div className="row"> <div className="col-md-6 mb-3"> <label htmlFor="phone">Rol </label> <select id="inputState" className="form-control" onChange={(event)=> setRol(event.target.value)}> <option selected>Choose...</option> { listRol.map((item)=>{ return( <option key={item.rol_id} value={item.rol_id}>{item.rol_name}</option> ) }) } </select> </div> </div> <div className="row"> <div className="col-md-6 mb-3"> <button className="btn btn-primary btn-block" type="submit" onClick={()=>saveEmployee()}>Save</button> </div> </div> </div> ) } export default Form;saveEmployee押化後、axiosのemployee.saveが呼び出されてlocalhost:8000/api/employee/createにPOSTする。
axios通信
axiosconst baseUrl = "http://localhost:8000/api/employee" import axios from "axios"; const employee = {}; employee.save = async (data) => { const urlSave= baseUrl+"/create" const res = await axios.post(urlSave,data) .then(response=> {return response.data }) .catch(error=>{ return error; }) return res; } export default employeeapi.php<?php use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; Route::middleware('auth:api')->get('/user', function (Request $request) { return $request->user(); }); Route::post('/employee/create', 'App\Http\Controllers\API\EmployeeController@create');Laravel側のControllerが呼び出され、実際に処理をするcreateアクションを呼び出します。
保存処理の最後にはresponseを返してあげる。今回は動作確認のため、失敗時にエラーメッセージのみを返しています。
コントローラー
EmployeeController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Employee; class EmployeeController extends Controller { public function index(){ return view("employee"); } public function create(Request $request){ try { $insert['name_lastname'] = $request['name']; $insert['email'] = $request['email']; $insert['city'] = $request['city']; $insert['direction'] = $request['address']; $insert['phone'] = $request['phone']; Employee::insert($insert); $response['message'] = "Save succesful"; $response['succes'] = true; } catch (\Exception $e) { $response['message'] = $e->getMessage(); $response['error'] = true; } return $response; } }createアクションはこのような流れで実装できます
指摘などがございましたらコメントで教えていただけると幸いです^_^
おわり
次はレコードをmapで繰り返し表示する方法など記事にしていこうと思います〜!
- 投稿日:2021-03-15T02:09:55+09:00
Laravel8+ReactHooks+MySQL Create処理
やりたいこと
フロントはReactHooksを使用して、LaravelはAPIサーバーでバックエンド処理をおこなう。
バックエンド処理はaxiosを使用。開発環境
- Laravel 8.0
- php 7.3
- MySQL 8
ModelはItem カラムはtext/commentと仮定しています。
State
- const [ text, setText ] = useState("");
入力値textのState
- const [ comment, setComment] = useState("");
入力値commentのState
入力フォーム
入力値をSetStatで更新。submitでsaveEmployeeを呼び出す。
formreturn ( <form className="add-form"> <div className="add-text"> <label>内容</label> <input type="text" value={text} onChange={(event)=>setText(event.target.value)}/> </div> <div className="add-comment"> <label>コメント</label> <input type="number" value={amount} onChange={(event)=>setComment(event.target.value)}}/> </div> <div className="form-row"> <color="primary" aria-label="add" type="submit" onClick={()=>saveEmployee()}>追加</div> </form> )呼び出されたsaveEmployeeはdataに定義された値を保持してemployeeServices.saveにアクセス。
この際、dataに定義されているtextとcommentはuseStateを参照しています。axiosconst saveEmployee = async () => { const data = { text, comment, }; const res = await employeeServices.save(data); setItemlist(res.data) }saveEmployeeから渡された値(data)を引数に、LaravelのAPIサーバーにPOSTする。
employeelet url = location.href; const baseUrl = url + 'api/employee'; const employee = {}; employee.save = async (data) => { const urlSave = baseUrl+"/save" const res = await axios.post(urlSave,data) .then(response=>{ return response.data; }) .catch(error=>{ return error; }) return res; }Laravel側のapi.phpが呼び出され、実際に処理をするcreateアクションを呼び出します。
api.phpuse App\Http\Controllers\EmployeeController; Route::match(['get', 'post'],'/employee/itemcreate', [EmployeeController::class, 'itemcreate']);itemcreateメソッド内で保存処理を行い、responseに$itemsを渡してreturnしてあげる。
ItemController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Item; class EmployeeController extends Controller { public function itemcreate(Request $request){ try { $items = new Item(); $items->text = $request->text; $items->amount = $request->comment; $items->save(); $response['data'] = $items; $response['message'] = '成功'; $response['success'] = true; } catch (\Exception $e) { $response['message'] = $e->getMessage(); $response['success'] = false; } return $response; } }createアクションはこのような流れで実装できます
指摘などがございましたらコメントで教えていただけると幸いです^_^
次はレコードをmapで繰り返し表示する方法など記事にしていこうと思います〜!