- 投稿日:2020-09-09T23:27:37+09:00
Expo x React Native DebuggerでUIデバッグ
概要
SimulatorでWeb開発でやるようなInspectを出来るようにする方法を書いておきます。
React Native Debuggerをインストール
caskで
react-native-debugger
をインストールします。$ brew update && brew cask install react-native-debuggerReact Native Debuggerの設定をExpo用に変更
React Native Debuggerを開いて、
Debugger
>Open Config File
を選択します。
.rndebuggerrc
という設定ファイルが開かれるので、defaultRNPackagerPorts
をExpo用に19001
に変更します。- defaultRNPackagerPorts: [8080] + defaultRNPackagerPorts: [19001],デバッグ方法
上記までが終わったら、一度expoを再起動します。
これしなくてエラーが出た
再起動したら、Simulatorを立ち上げます。
以下はiOS Simulatorで進めます。SimulatorでDebug JS RemotelyをONに
Simulator上で
Cmd + D
でメニューを開きます。
すると以下のようにメニューが出るので、Debug Remote JS
をタップします。React Native Debuggerを起動
React Native Debuggerを起動して、iOS Simulatorをリフレッシュすると以下のような小さいメニューが出るので、
Inspect
をタップするとWeb開発のようなInspectが出来るようになります。
- 投稿日:2020-09-09T23:25:28+09:00
Reactファイルをwebpackでバインドしてlocalhostで確認してみる
Reactとwebpackとyarnを試しに使ってみる
本記事はタイトルの通り、様々なサイトや記事を参考にReactで作ったファイルをwebpackでバインドしてlocalhostで確認してみた一連の流れを記述してあります。使用するReactファイルはReact公式チュートリアルを
パクって参考にして作成したものになります。create-react-appは使用していません。
参考にさせていただいたサイトや記事は最後に記載してあります。
yarn(npm)でモジュールを準備する
yarn add コマンドは、npm install --saveに対応しています。
yarn init yarn add react react-dom yarn add toastr yarn add webpack webpack-cli webpack-dev-server yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react今回は便宜上3回に分けてインストールしましたが、一度にインストールすることも可能です。
- 3行目
- toastrは今回使用するreactファイルでtoastrというライブラリを使用しているためインストールしています
- 5行目
- babel-loaderはwebpackでbabelを使用するために必要になるようです。cssを扱うならばcss-loaderが、sassならsass-loaderが必要になります
- @babel/core は、babelの本体になります
- @babel/preset-envはECMAScript用presetで、書くブラウザのターゲットバージョンなどを指定できます。今回は未指定なのでes5の構文に変換されています
- @babel/preset-reactはReact用presetです。TypeSctiptを扱う場合は@babel/preset-typescriptが必要になります
webpackの設定ファイルを作成する
これまででとりあえず必要なモジュールのインストールが完了しました。使用するjsファイル、htmlファイルもあとでまとめてダウンロードするので、次はwebpackの設定ファイルであるwebpack.config.jsを作成します。
webpack.config.jsmodule.exports = { // 本番はproduction 開発環境はdevelopment mode: 'production', // entryポイント(相対パス) entry: './src/javascripts/index.js', // 出力先(絶対パス) output: { path: `${__dirname}/dist`, filename: 'main.js' }, module: { rules: [ { // loaderの適応ファイルを指定する正規表現 test: /\.js$/, use: [ { // Babelを使う loader: 'babel-loader', // Babelのオプションの設定 options: { presets: [ //presetの設定 '@babel/preset-env', '@babel/preset-react', ] } } ] } ] } };各設定の詳細はソースのコメントのとおりです。
次章はwebpack.config.jsの記載内容と矛盾が出ないようエントリーポイントに正しくjsファイルを配置します(本来はwebpack.config.jsに記載するパスを合わせる)。
Reactファイルの配置
githubにおいてあるファイルを./src/javascripts/にコピーするか、./src/に移動して以下のコマンドを打ち込んでください。
git clone git@github.com:Asa-to/javascripts.git以上のコマンドを打ち込むことで、カレントディレクトリにjavascriptsフォルダがコピーされます。
最後に、下記のindex.htmlを作業ディレクトリに配置したら準備は完了です。
index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="root"></div> <script src="./dist/main.js"></script> </body> </html>バインドして結果を確認する
ここまでで以下のようなファイル配置になっていれば準備は完了です。早速バインドしてみましょう。
./ ├ index.html ├ src ├ javascripts ├ node_modules ├ webpack.config.js ├ package.jsonバインドコマンドは以下です。
./node_modules/.bin/webpack以上でコマンドが正常に実行されれば、./distにバインドされたファイルが出力されているはずです。./dist/main.jsが生成されていることを確認してください。
./node_modules/.bin/webpack-dev-server続いて以上のコマンドを実行してブラウザからlocalhost:8080にアクセスしてみます。
以上のような表示が確認できれば完璧です。
参考文献
- 投稿日:2020-09-09T22:32:34+09:00
超初心者のReact(create-react-app)基礎学習覚え書き③(Hooks)
ReactHooksでstateを扱う
Hook(フック)とは
・クラスの機能(stateやライフサイクル)をFunctional Componentでも使えるというもの
・100%後方互換で、古い書き方のコンポーネントにReactHooksを使用したとしても影響を与えないHook使用のメリット
シンプルさを保てる為
クラスコンポーネントが複雑(難しい)
1.this.が入ることで他言語と違った挙動で使いづらい為、トレンド的に排除されようとしている
2.stateのロジックが複雑(stateだらけだと意味不明になる)
3.複数のライフサイクルメソッドにまたがる処理をまとめて記述できるFunctional Componentでstateを使ってみる
・ステートフックと呼ばれる
・クラスコンポーネントでの
this.stateとthis.setstate()の役割
・複数のstateを扱うときはstate毎に宣言する必要があるuseState()の使い方例
1.関数のインポート
import React, {useState} from 'react';2.宣言
const [state変数名, state変更関数名] = usestate(state初期値); //実際には↓ const [isHoge, setIsHoge] = useState(false);3.JSX内で使う
<input /**中略 */ onClick={() => setIsHoge(!isHoge)} />Functional Componentでstateが使えると何がいいのか?
classコンポーネントを減らす為に上の階層がclassコンポーネントになることが多かった。それによりpropsをどんどん渡していかなければいけなかった為にコードが複雑化しやすかった。
Hookにより末端のコンポーネントでstateを持つことにより管理がしやすくなった。ReactHooks 関数コンポーネントでライフサイクルを扱う
useEffect()を使用する
メリット
・ライフサイクルの代替が可能
・Functional Componentでライフサイクルを使える(記述が減らせる)
・コードを(classComponentよりも分かりやすく)まとめれる
→時系列ベースではなく機能ベースでまとめが可能useEffect()の仕組み
・レンダーごとにuseEffect()内の処理が走るようになる
・メソッドの代替が可能
compnentDidMount()
compnentDidUpdate()
compnentWillUnmount()基本的な使い方
①レンダーごと
・基本形でuseEffect()内にCallback関数で書く
・Callbackはレンダーごとに呼ばれる
・returnするCallback関数はアンマウント時に呼ばれる
(クリーンアップ関数とも言う)useEffect(() => { console.log('Render!') return () => { //アンマウント時のみ console.log('Unmounting!') } })②マウント時のみ実行させる
・compnentDidMount()の時にだけ書いていた処理を実行するパターン
・第2引数に空の配列を渡すとマウント時(最初の一回)だのみ実行される
→前回レンダーと今回レンダーで比較している
(変更があった場合のみCallback関数を実行)useEffect(() => { console.log('Render!') }, [])③マウント、アンマウント時に実行する
・①と②の複合系
useEffect(() => { console.log('Render!') //マウント時のみ実行される return () => { //アンマウント時はクリーンアップ関数として実行される console.log('Unmounting!') } }, []) //Updatingの期間は配列が空の為、実行されない④特定のレンダー時
・useState()と使われることが多い
const [limit, release] = useState(true); useEffect(() => { console.log('Render!') //limitの値を変更(true→false)時に実行される }, [limit])いいねボタンの実装
LikeButton.jsximport React, {useState, useEffect } from 'react'; const LikeButton = () => { const [count, counter] = useState(0); const [limit, release] = useState(true); const countUp = () => { counter(count + 1) } useEffect(() => { document.getElementById('counter').addEventListener('click', countUp) if (count >= 1000) { counter (0) } return () => { document.getElementById('counter').removeEventListener('click', countUp) } }, [limit]); return( <> <button id={"counter"}> ? {count}</button> <button onClick={() => release(!limit)}>もっと!!</button> {/*limitを解除するためのボタン*/} </> ) } export default LikeButton
- 投稿日:2020-09-09T22:32:34+09:00
超初心者のReact(create-react-app)基礎学習覚え書き③
ReactHooksでstateを扱う
Hook(フック)とは
・クラスの機能(stateやライフサイクル)をFunctional Componentでも使えるというもの
・100%後方互換で、古い書き方のコンポーネントにReactHooksを使用したとしても影響を与えないHook使用のメリット
シンプルさを保てる為
クラスコンポーネントが複雑(難しい)
1.this.が入ることで他言語と違った挙動で使いづらい為、トレンド的に排除されようとしている
2.stateのロジックが複雑(stateだらけだと意味不明になる)
3.複数のライフサイクルメソッドにまたがる処理をまとめて記述できるFunctional Componentでstateを使ってみる
・ステートフックと呼ばれる
・クラスコンポーネントでの
this.stateとthis.setstate()の役割
・複数のstateを扱うときはstate毎に宣言する必要があるuseState()の使い方例
1.関数のインポート
import React, {useState} from 'react';2.宣言
const [state変数名, state変更関数名] = usestate(state初期値); //実際には↓ const [isHoge, setIsHoge] = useState(false);3.JSX内で使う
<input /**中略 */ onClick={() => setIsHoge(!isHoge)} />Functional Componentでstateが使えると何がいいのか?
classコンポーネントを減らす為に上の階層がclassコンポーネントになることが多かった。それによりpropsをどんどん渡していかなければいけなかった為にコードが複雑化しやすかった。
Hookにより末端のコンポーネントでstateを持つことにより管理がしやすくなった。ReactHooks 関数コンポーネントでライフサイクルを扱う
useEffect()を使用する
メリット
・ライフサイクルの代替が可能
・Functional Componentでライフサイクルを使える(記述が減らせる)
・コードを(classComponentよりも分かりやすく)まとめれる
→時系列ベースではなく機能ベースでまとめが可能useEffect()の仕組み
・レンダーごとにuseEffect()内の処理が走るようになる
・メソッドの代替が可能
compnentDidMount()
compnentDidUpdate()
compnentWillUnmount()基本的な使い方
①レンダーごと
・基本形でuseEffect()内にCallback関数で書く
・Callbackはレンダーごとに呼ばれる
・returnするCallback関数はアンマウント時に呼ばれる
(クリーンアップ関数とも言う)useEffect(() => { console.log('Render!') return () => { //アンマウント時のみ console.log('Unmounting!') } })②マウント時のみ実行させる
・compnentDidMount()の時にだけ書いていた処理を実行するパターン
・第2引数に空の配列を渡すとマウント時(最初の一回)だのみ実行される
→前回レンダーと今回レンダーで比較している
(変更があった場合のみCallback関数を実行)useEffect(() => { console.log('Render!') }, [])③マウント、アンマウント時に実行する
・①と②の複合系
useEffect(() => { console.log('Render!') //マウント時のみ実行される return () => { //アンマウント時はクリーンアップ関数として実行される console.log('Unmounting!') } }, []) //Updatingの期間は配列が空の為、実行されない④特定のレンダー時
・useState()と使われることが多い
const [limit, release] = useState(true); useEffect(() => { console.log('Render!') //limitの値を変更(true→false)時に実行される }, [limit])いいねボタンの実装
LikeButton.jsximport React, {useState, useEffect } from 'react'; const LikeButton = () => { const [count, counter] = useState(0); const [limit, release] = useState(true); const countUp = () => { counter(count + 1) } useEffect(() => { document.getElementById('counter').addEventListener('click', countUp) if (count >= 1000) { counter (0) } return () => { document.getElementById('counter').removeEventListener('click', countUp) } }, [limit]); return( <> <button id={"counter"}> ? {count}</button> <button onClick={() => release(!limit)}>もっと!!</button> {/*limitを解除するためのボタン*/} </> ) } export default LikeButton
- 投稿日:2020-09-09T21:09:34+09:00
MATERIAL-UIのMultiple SelectでChipから選択を解除する
はじめに
React + Typescript + MaterialUIでフロントエンドを作成していたときに実現したいことができなかったので参考程度に投稿します。
実現できなかった原因
Chipの×ボタンを押してもSelectのメニューが出てきてしまう
実現したいこと
MaterialUIの公式ドキュメントに書かれていた「Multiple Select(Chip)」でChipの×ボタンからも選択を解除したい!
結論
Chipコンポーネントに以下プロパティを追加
onMouseDown={(event) => {event.stopPropagation();}}前提条件
- typescript,React,MaterialUiについてある程度の知識がある。
- create-react-appでアプリケーションが作成済み
npx create-react-app {your_app_name} --template typescript
- material-uiがインストール済み
npm install @material-ui/coreMultiple SelectのChipを動かしてみる
まずは何も考えずコードをすべてコピーして
App.tsx
に貼り付ける。
次にChip以外のところは邪魔なのでChipに関連するものだけを残す。
そうするとコードは以下のようになります。App.tsximport React from 'react'; import { createStyles, makeStyles, useTheme, Theme } from '@material-ui/core/styles'; import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; import MenuItem from '@material-ui/core/MenuItem'; import FormControl from '@material-ui/core/FormControl'; import Select from '@material-ui/core/Select'; import Chip from '@material-ui/core/Chip'; const useStyles = makeStyles((theme: Theme) => createStyles({ formControl: { margin: theme.spacing(1), minWidth: 120, maxWidth: 300, }, chips: { display: 'flex', flexWrap: 'wrap', }, chip: { margin: 2, }, noLabel: { marginTop: theme.spacing(3), }, }), ); const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; const MenuProps = { PaperProps: { style: { maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, width: 250, }, }, }; const names = [ 'Oliver Hansen', 'Van Henry', 'April Tucker', 'Ralph Hubbard', 'Omar Alexander', 'Carlos Abbott', 'Miriam Wagner', 'Bradley Wilkerson', 'Virginia Andrews', 'Kelly Snyder', ]; function getStyles(name: string, personName: string[], theme: Theme) { return { fontWeight: personName.indexOf(name) === -1 ? theme.typography.fontWeightRegular : theme.typography.fontWeightMedium, }; } export default function MultipleSelect() { const classes = useStyles(); const theme = useTheme(); const [personName, setPersonName] = React.useState<string[]>([]); const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => { setPersonName(event.target.value as string[]); }; return ( <div> <FormControl className={classes.formControl}> <InputLabel id="demo-mutiple-chip-label">Chip</InputLabel> <Select labelId="demo-mutiple-chip-label" id="demo-mutiple-chip" multiple value={personName} onChange={handleChange} input={<Input id="select-multiple-chip" />} renderValue={(selected) => ( <div className={classes.chips}> {(selected as string[]).map((value) => ( <Chip key={value} label={value} className={classes.chip} /> ))} </div> )} MenuProps={MenuProps} > {names.map((name) => ( <MenuItem key={name} value={name} style={getStyles(name, personName, theme)}> {name} </MenuItem> ))} </Select> </FormControl> </div> ); }そしてこれを
npm start
してhttp://localhost:3000
でみると
よさそう!※拡大してますChipの×ボタンを表示する
Chipに×ボタンを表示するにはChipコンポーネントに
onDelete
プロパティを追加すればいい。Apptsx<Chip key={value} label={value} className={classes.chip} onDelete={() => { alert(value) }} /> #ここを追加今回は×ボタンをがクリックされたことを確認するために、alertでクリックしたChipのラベルを表示するようにした。
そして再度npm start
あれ...?何度押しても×ボタンがクリックできずにSelectのメニューが出てきてしまう。
対処法
Chipコンポーネントに以下プロパティを追加
App.tsx<Chip key={value} label={value} className={classes.chip} onDelete={() => { alert(value) }} onMouseDown={(event) => {event.stopPropagation()}} #ここを追加 />今度はきちんとクリックされてアラートが出ていますね。
Chip削除の処理を追加する
先ほど入れたalertの処理をChip削除(personName内の名前を削除)する処理に変える。
新しく
chipDelete
という関数を用意するconst chipDelete = (name: string) => { setPersonName(personName.filter(value => value !== name)) }そうすると
App.tsx
のfunction MultipleSelect()
は以下のようになるApp.tsxexport default function MultipleSelect() { const classes = useStyles(); const theme = useTheme(); const [personName, setPersonName] = React.useState<string[]>([]); const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => { setPersonName(event.target.value as string[]); }; const chipDelete = (name: string) => { setPersonName(personName.filter(value => value !== name)) }; return ( <div> <FormControl className={classes.formControl}> <InputLabel id="demo-mutiple-chip-label">Chip</InputLabel> <Select labelId="demo-mutiple-chip-label" id="demo-mutiple-chip" multiple value={personName} onChange={handleChange} input={<Input id="select-multiple-chip" />} renderValue={(selected) => ( <div className={classes.chips}> {(selected as string[]).map((value) => ( <Chip key={value} label={value} className={classes.chip} onDelete={(event) => chipDelete(value)} onMouseDown={(event) => { event.stopPropagation(); }} /> ))} </div> )} MenuProps={MenuProps} > {names.map((name) => ( <MenuItem key={name} value={name} style={getStyles(name, personName, theme)}> {name} </MenuItem> ))} </Select> </FormControl> </div> ); }うまくいった!!!!
終わりに
今思うとこんなにすっとできてしまうなんて。。。
ただ単にコピペするだけではなくてどのような処理が行われていて、どんなオプションのプロパティがあるのかを確認しないといけないですね。
- 投稿日:2020-09-09T21:03:10+09:00
技術記事を書く時に意識していること
自分のために書く
「思考の整理 + 未来の自分のための資料作りが目的で、周りからの反応はおまけ」
というスタンスでいると雑な記事をバンバン書ける。自分は執筆時間が5分かかっていない記事の方が多いと思う。そして記事数に対してLGTM等は少ない。自分の言葉で書く
普段自分が使う言い回しをした方が、後から振り返った時に理解しやすいです。カッコつけない方が良い。
文章は、きれいさや構造の正しさより、テンポを意識。Qiigleの検索に引っかかるようにする
将来検索に使いそうなワードは入れておく
https://qiigle.com/さっさと本題に入る
「記事の対象者」「この記事でわかること」「この記事で触れないこと」とかが必要なのは超長文記事か、反感を買いかねない踏み込んだ記事を書くときだけで良い。
あいさつとかギャグ的なものは技術記事には必要ない。その命名じゃないといけないのか、任意の名前で良いのかを明確にする
任意に名前をつけられる部分がアプリ名にちなんだ名前だったりすると、命名規則があるように見えてしまう。多少ダサくなってもわかりやすい方が良い。
参考記事を書く
モラル的な話だけじゃなくて、後から参照する時に執筆当時の状況を思い出しやすくなる。
記事投稿画面をブックマークバーにセット
1クリックで執筆開始できます。
伸ばしたい記事は拡散の努力をする
Qiitaではトレンドに入ると一気に伸びるので、サービス公開記事など伸ばしたい記事はTwitterやオンラインコミュニティ等でコメント付きで共有するなど、最大限拡散の努力をします。やりまくると嫌われるので、本当に伸ばしたい時だけ。
記事を伸ばすために学習するジャンルを変えない
経験上、Railsの記事を書くよりReact等の記事を書く方が全然伸びます。でもそれはそれなので、、
「記事が伸びる分野 = 自分が人柱になる確率が高い分野」で、今の自分は確実に技術力の土台を固めるフェーズなので、そこは履き違えないように注意してます。
- 投稿日:2020-09-09T17:12:41+09:00
超初心者のReact(create-react-app)基礎学習覚え書き②
項目
・ライフサイクルメソッド
・importとexportモジュールの使用ライフサイクルメソッド
3種(Mounting,Updating,Unmounting)
・それぞれコンポーネントの配置、成長、破棄を示す
・それぞれの期間で使えるメソッドがいくつか存在するそもそもなんでつかうの?
関数の外(Reactコンポーネントの外)に影響を与える関数を記述する場合に使用するため
ライフサイクル内で行う一般的項目として
バーチャルDOMの内容変更、データベース通信のようなAPI通信の際、ログ出力、setState()などどういったものかは下記の通り
配置(WebページへのMount)
Webページにアクセスした時にReactで作ったコンポーネントが配置(生まれる)までの期間
変更(Update)
特定の箇所をクリックすると色が変わる(ユーザーの操作)、データが書き換わることでUIが変更されるなどが発生する期間
破棄(Unmount)
現在ページから別ページへのアクセスをした時
もとのページのコンポーネントは不要になるためコンポーネントを破棄する期間
?期間というかタイミング?主要なメソッドと時間軸ごとの動き方
Mounting→ Updating→ Unmounting→ constructor()
初期化(state)↓ ↓ ↓ ↓ ↓ render()
VDOMを描画
(JSXをリターン)render()
VDOMを描画↓ ↓ ↓ ↓ conponentDidMount()
render()の後に1度だけ呼ばれる
リスナーの設定やAPI通信に使用↓ ↓ - conponentDidUpdate()再レンダー後に呼ばれるイベント ↓ - - componentWillUnmount()破棄される直前に呼ばれるもの
リソース解放、リスナー解除他…実装例 ?buttonの実装
※コンポーネント中の関数名はファイル名で合わせていく
Hoge.jsが主要メソッド使用の例Foo.jsximport React from 'react'; import Bar from "./Bar"; const Article = (props) => { return ( <div> <h2>{props.title}</h2> <LikeButton count={props.count}/> </div> ) };Bar.jsximport React from 'react'; const LikeButton = (props) => { return( <button id={"counter"}> ? {props.count}</button> ) } export default BarHoge.jsximport React from 'react'; import Foo from "./Foo"; class Hoge extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } //componentDidMount componentDidMount() { //ボタンがクリックされたらGoodをカウントアップする document.getElementById('counter').addEventListener('click',this.countUp) } //componentDidUpdate componentDidUpdate() { if (this.state.count >= 100) { //100になったら this.setState({count:0}) //0に戻る } } //componentWillUnmount componentWillUnmount() { //無駄なリソースの解放によサーバー負荷が軽減される document.getElementById('counter').removeEventListener('click',this.countUp) //countUpのリスナーをremoveする } countUp = () => { //関数が呼び出されたら this.setState({count: this.state.count +1 }) //stateを変更します(現在のcountに+1します) } render() { return ( <> <Article title={"ライフサイクルメソッドの使い方"} count={this.state.count} /> </> ) } } export default Hogeimportとexportモジュールの使用
Reactで使用するモジュールの概念をうまく使うために必須項目
モジュール化
モジュール・・・?
→大きなものをいくつかに分割して管理していく方法のこと
→基本1ファイル1モジュールとする
→任意の場所で読み込んで使用できるメリット
1.大規模アプリケーションになっても管理しやすい
2.任意の場所で読み込み、かつ最小限で済む為読み込み速度にも影響する
3.プログラムの使いまわし(再利用)が可能な為、何度も同じコードを書く必要が無い1つのコンポーネントを作成したら、ひとつのモジュールになっているので必要なところで読み込む
また、コンポーネントをいくつかに分けることにより管理しやすくしているexport
名前付きexport
・1モジュールから複数の関数をexportできる
※クラスはexportできないFooBar.jsexport function Foo() { return (<h1>Fooo</h1>) }//通常関数 export const Bar = () => { return (<h1>Baar</h1>) }//アロー関数名前無しexport(default)
※ES6推奨の書き方
・1ファイル(1モジュール)1export
・アロー関数は宣言後にexportする
・クラスをexportできるFoo.jsexport default function Foo() { return (<h1>Fooo</h1>) }Bar.jsconst Bar = () => { return (<h1>Baar</h1>) } export default BarHoge.jsexport default class Hoge exteds Fuga { render() { return (<h1>Hoge</h1>) } }モジュールのインポート
方法は3種類
1.全体のインポート
2.一部(関数ごと)だけのインポート
3.別名でのインポート1.全体のインポート
・名前無し(default)exportしたモジュールをimportする
・モジュール全体をimportFoo.jsimport React from 'react'; //npmで管理しているreactというパッケージの中のReactというモジュールをimportしているよの意味 import Bar from "./Bar"; //BarというファイルからBarというモジュールをimportしているよという意味Bar.jsconst Bar = (props) => { //アロー関数でBarコンポーネントを宣言 return (<div>Barです</div>) }; export default Bar //コンポーネントのexport2.一部(関数ごと)だけのインポート
・名前付きexportされたモジュールのimport
・{}内にimportしたい関数名Hoge.jsimport { Foo, Bar } from "./FooBar"; //FooBarというファイルからFooとBarをimportするという書き方になるFooBar.jsexport function Foo() { return (<h1>Foooo</h1>) } export const Bar = () => { return (<h1>Baaar</h1>) } //1ファイルだけど2つのモジュールで構成される3.別名でのインポート
・別名(エイリアスとも言う)をつけてimportできる
→モジュール全体の場合:* as name
→モジュール一部の場合:A as BHogeHoge.jsimport React from 'react'; //↓モジュール全体の場合:* as name import * as FooBar from './FooBar' //FooBarって名前で./conponents/FooBarに保管のモジュールをimportしますという書き方 //↓モジュール一部の場合:A as B import { Foo as MyFoo } from './FooBar' //FooBarというファイルにあるFooという関数をMyFooという名前でimportするという書き方 render() { return ( <> <FooBar.Foo /> //FooBarの中のFoo関数 <FooBar.Bar /> //FooBarの中のBar関数 <Hoge /> </> ) } } export default HogeHoge次回③はReactHooks state
- 投稿日:2020-09-09T13:22:17+09:00
【React・ReactNative】任意の場所まで自動スクロールさせる方法
はじめに
任意の場所まで自動スクロールするには、標準の
WebAPI
で提供されているElement.scrollIntoView()
が便利です。
チャットアプリで送受信に合わせて最新のメッセージまでスクロールしたい時などに使えます。DOMの
Element
はReactであればReact.useRef()
で取得することができます。実装の例
任意の場所にスクロールしたい場合、あらかじめその場所に
透明な<div/>
を仕込んでおくと便利です。
透明な<div/>
を長いリストの最後に仕込んでおくReact.useRef()
で透明な<div/>
の参照を取得透明な<div/>の参照に対して
Element.scrollIntoView()`を使用する関数コンポーネントconst messageEndRef = React.useRef(); const scrollToLatest = (behavior = 'smooth') => messageEndRef.current.scrollIntoView({ behavior }); return ( <List> {renderMessages()} <div style={{ float:"left", clear: "both" }} ref={messagesEndRef} /> </List>まとめ
- 標準の
WebAPI
で提供されているElement.scrollIntoView()
を使うと簡単に自動スクロールできます。Element.scrollIntoView()
を使う対象として、透明な<div/>
を使う方法があります。参考
https://developer.mozilla.org/ja/docs/Web/API/Element/scrollIntoView
- 投稿日:2020-09-09T11:15:44+09:00
React(フロント)からHasuraのgraphqlを叩く
前回hasuraを使ってgraphqlサーバを立てたので、今回はフロントと繋げたいと思います。
繋げるために利用したライブラリはapolloです。ドキュメント
https://www.apollographql.com/docs/tutorial/client/
1. npm install
まずはライブラリをインストールしましょう。
npm install @apollo/client
2. ApolloProviderでアプリをラップ(アプリのどこでも利用できるように)
次に、ApolloProviderコンポーネントでアプリをラップし、ApolloClientインスタンスを渡しましょう。
index.jsximport { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client"; import React from "react"; import ReactDOM from "react-dom"; import Pages from "./pages"; import injectStyles from "./styles"; const client = new ApolloClient({ uri: "http://localhost:4000/", cache: new InMemoryCache() }); injectStyles(); ReactDOM.render( <ApolloProvider client={client}> <Pages /> </ApolloProvider>, document.getElementById("root") );3.クエリを投げる
準備はできました。
以下のようにクエリを投げれば結果を確認することができます。sample.jsximport { gql, useQuery } from "@apollo/client"; const GET_SAMPLE = gql` query getSample { sample { id message } } `; const { data, loading, error } = useQuery(GET_SAMPLE); console.log(data); //データの取得が確認できる注意
gqlの中身ですが、Hasura上でクエリを投げる分には以下のみでよかったと思います。
{ sample { id message } }しかし、フロントから投げる時は「query "クエリ名"(キャッシュ用)」をつける必要があります。
query getSample { sample { id message } }
- 投稿日:2020-09-09T07:01:02+09:00
無料でSSR・ホスティング・API鯖を立てれるVercel。無料でホスティングするサンプル。Parcel・ReactでSPA。
Vercel
https://vercel.comバックナンバー
無料でSSR・ホスティング・API鯖を立てれるVercel。TypeScript・ExpressでAPI鯖を立てる。ソースコード
package.json{ "scripts": { "start": "rimraf local && parcel src/index.html -d local", "build": "rimraf public && parcel build src/index.html -d public --no-source-maps" }, "dependencies": { "connected-react-router": "^6.8.0", "history": "^5.0.0", "react": "^16.13.1", "react-dom": "^16.13.1", "react-redux": "^7.2.1", "react-router": "^5.2.0", "redux": "^4.0.5", "vercel": "^20.1.0" }, "devDependencies": { "parcel-bundler": "^1.12.4", "rimraf": "^3.0.2" } }src/index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vercelホスティング</title> </head> <body> <div id="app"></div> <script src="/index.js"></script> </body> </html>src/index.jsimport * as React from 'react'; import { render } from 'react-dom'; import { combineReducers } from 'redux'; import { Provider } from 'react-redux'; import { Route, Switch } from 'react-router'; import { ConnectedRouter, routerMiddleware, connectRouter, } from 'connected-react-router'; import { applyMiddleware, compose, createStore } from 'redux'; import { createBrowserHistory } from 'history'; const App = () => { return ( <> <h1>Hello world!</h1> </> ); }; const history = createBrowserHistory(); const store = createStore( combineReducers({ router: connectRouter(history), }), {}, compose(applyMiddleware(routerMiddleware(history))) ); render( <Provider store={store}> <ConnectedRouter history={history}> <Switch> <Route exact path={'/'} component={App} key="home" /> <Route exact path={'/sub'} component={App} key="sub" /> </Switch> </ConnectedRouter> </Provider>, document.getElementById('app') );vercel.json{ "routes": [ { "handle": "filesystem" }, { "src": "/.*", "dest": "/index.html" } ] }コマンド
ローカルで実行 ポート番号3000で鯖が立ち上がる
$ npx vercel dev
デプロイ
$ npx vercel --prodワイの成果物
https://qiita.com/yuzuru2/items/b5a34ad07d38ab1e7378
①コード共有サイト(SPA) React
https://code.itsumen.com②画像共有サイト(SPA) React
https://gazou.itsumen.com③チャット(SSR) Nuxt.js
https://nuxtchat.itsumen.com④チャット(SPA) React
https://chat4.itsumen.com⑤掲示板(SSR) Next.js
https://board.itsumen.com⑥掲示板(SPA) Vue
https://board.itsumen.com⑦レジの店員を呼ぶスマホアプリ(Android)
https://play.google.com/store/apps/details?id=com.itsumen.regi&hl=ja⑧ブログ(静的サイトジェネレータ) Hugo
https://yuzuru.itsumen.comワイのLINE: https://line.me/ti/p/-GXpQkyXAm
- 投稿日:2020-09-09T02:38:45+09:00
gatsby入門 チュートリアルをこなす ソースプラグインの作成(1)
チュートリアルをこなす!
以前にgatsbyの基本のチュートリアルをこなしたのですが、まだチュートリアルが残っているので最後までやっていこうと思いました。
今回実施するgatsbyのチュートリアルはこちら
https://www.gatsbyjs.com/tutorial/plugin-and-theme-tutorials/
https://www.gatsbyjs.com/tutorial/source-plugin-tutorial/
早速やっていきましょう。Plugin & Theme Tutorials
https://www.gatsbyjs.com/tutorial/plugin-and-theme-tutorials/
ここではプラグインとテーマのチュートリアルの概略が記載されていました。
ざっくり言うと
プラグインは、Gatsby APIを実装するNode.jsパッケージ。
テーマは、事前設定された機能やデータソーシング、UIコードをギャツビーサイトに追加するプラグインの一種。
要はサイト構築に便利な物が作れまっせ(しかも共有出来まっせ)ってことで理解しました。
次行きましょう。Creating a Source Plugin
https://www.gatsbyjs.com/tutorial/source-plugin-tutorial/
ここでは独自のソースプラグインを作成するようです。
ソースプラグインについてはチュートリアルにこう書かれています。ソースプラグインは、任意のソースからのデータをGatsbyが処理できる形式に変換します。 Gatsbyサイトでは、いくつかのソースプラグインを使用して、興味深い方法でデータを組み合わせることができます。
つまり構築サイト内のソースからデータを抜き出して、良い感じのデータに変換できるってことかな?
とにかく次次!How to create a source plugin
なんだか色々な事を書いてあるけど英語よくわかんねぇから、とりあえず実技に進もう。
Set up an example site
以下コマンドでサンプルサイトを作成
gatsby new example-site https://github.com/gatsbyjs/gatsby-starter-hello-world
Set up a source plugin
以下コマンドでソースプラグインを作成
gatsby new source-plugin https://github.com/gatsbyjs/gatsby-starter-plugin
Install your plugin in the example site
サンプルサイトにソースプラグインをインストールします。
example-site/gatsby-config.jsを以下のように修正します。example-site/gatsby-config.jsmodule.exports = { /* Your site config here */ plugins: [require.resolve(`../source-plugin`)],←ここ修正 }example-siteを起動します。example-siteディレクトリに移動して以下を実行
gatsby develop
ロードされてる!
このログはsource-plugin/gatsby-node.jsに出力コマンドがあります。source-plugin/gatsby-node.jsexports.onPreInit = () => console.log("Loaded gatsby-starter-plugin")Source data and create nodes
source-plugin/gatsby-node.jsを以下のように書き換え
source-plugin/gatsby-node.js// constants for your GraphQL Post and Author types const POST_NODE_TYPE = `Post` exports.sourceNodes = async ({ actions, createContentDigest, createNodeId, getNodesByType, }) => { const { createNode } = actions const data = { posts: [ { id: 1, description: `Hello world!` }, { id: 2, description: `Second post!` }, ], } // loop through data and create Gatsby nodes data.posts.forEach(post => createNode({ ...post, id: createNodeId(`${POST_NODE_TYPE}-${post.id}`), parent: null, children: [], internal: { type: POST_NODE_TYPE, content: JSON.stringify(post), contentDigest: createContentDigest(post), }, }) ) return }再起動
graphqlを見ると
allPostという項目が増えています。
チュートリアル通りのクエリを実行するとこんな感じ。
うん。source-plugin/gatsby-node.jsに書かれたPost情報が記載されてる。
postもあるね。
なるほどね。サイトのディレクトリとファイルの内容だけでSQLみたいなクエリ作って取得するようにイメージしておこう。だめだ超眠い。
今回はここまで。
ありがとうございました。
gatsby 過去の作業履歴
gatsby入門 チュートリアルをこなす 0.開発環境をセットアップする
gatsby入門 チュートリアルをこなす 1. ギャツビービルディングブロックについて知る(1)
gatsby入門 チュートリアルをこなす 1. ギャツビービルディングブロックについて知る(2)
gatsby入門 チュートリアルをこなす 2. ギャツビーのスタイリングの概要
gatsby入門 チュートリアルをこなす 3. ネストされたレイアウトコンポーネントの作成
gatsby入門 チュートリアルをこなす 4. ギャツビーのデータ
gatsby入門 チュートリアルをこなす 5. ソースプラグインとクエリされたデータのレンダリング
gatsby入門 チュートリアルをこなす 6. 変圧器プラグイン※Transformer pluginsのgoogle翻訳
gatsby入門 チュートリアルをこなす 7. プログラムでデータからページを作成する
gatsby入門 チュートリアルをこなす 8. 公開するサイトの準備
gatsby入門 ブログ作ってサーバーにアップしてみる