20200728のReactに関する記事は5件です。

React コンテクスト 初心者覚書

初心者がコンテクストを読んで箇条書きしています。
実際のサイトの方がわかりやすいです。わからないことも同時にメモしています。

  • コンテクストは各階層で手動でプロパティを下に渡すことなく、 コンポーネントツリー内でデータを渡す方法を提供する

コンテクストをいつ使用すべきか

  • ネストレベルが違う多くのコンポーネントからアクセスできる必要がある時。
  • 欠点:コンポーネントの再利用が難しくなる

コンテクストを使わない選択肢もある

  • 多くの階層を経由することだけを避けたいのであれば、コンポーネントコンポジションを使う
  • 最終的に Avatar コンポーネントだけがプロパティを必要とするならば、Avatar コンポーネント自身を渡すようにすると
  • コンポーネントに対して 1 つの子までという制限はありません。複数の子を渡したり、子のために複数の別々の「スロット」を持つことさえできます。
  • 使わない時の欠点:制御の反転はアプリケーション内で取り回す必要のあるプロパティの量を減らし、ルートコンポーネントにより多くの制御を与えることにより、多くのケースでコードを綺麗にすることができます。しかし、この方法は全てのケースで正しい選択とはなりません:ツリー内の上層に複雑性が移ることは、それら高い階層のコンポーネントをより複雑にして、低い階層のコンポーネントに必要以上の柔軟性を強制します。

コンテクストを使用する前に

API

React.createContext

[コンテクストオブジェクトを作成]

const MyContext = React.createContext(defaultValue);
  • コンテクストオブジェクトを作成
  • React がこのコンテクストオブジェクトが登録されているコンポーネントをレンダーする場合、ツリー内の最も近い上位の一致する Provider から現在のコンテクストの値を読み取る
  • defaultValue 引数は、コンポーネントがツリー内の上位に一致するプロバイダを持っていない場合のみ使用される。これは、ラップしない単独でのコンポーネントのテストにて役に立ちます。補足: undefined をプロバイダの値として渡しても、コンシューマコンポーネントが defaultValue を使用することはありません。

??わからなかったこと

ツリー内の最も近い上位の一致する Provider
直近の親っていう意味だろうか??
ラップしない単独でのコンポーネントのテストにて役に立ちます。
全く意味がわからない。。
ラッパーとは?
- 一時的にラップするために生成されるオブジェクトのことを『ラッパーオブジェクト』という
ラッパーオブジェクト
- StringオブジェクトをnewすることでStringオブジェクトのインスタンスを作れます。
- プリミティブ型の値を包んだ(ラップした)オブジェクトと言えます。 そのため、このようなオブジェクトをプリミティブ型の値に対してのラッパーオブジェクトと呼びます。
- 注記: undefinedとnullに対応するラッパーオブジェクトはありません。

Context.Provider

[プロバイダ (Provider) によりコンシューマコンポーネントはコンテクストの変更を購読できる]

<MyContext.Provider value = {/*何らかの値*/}>
  • プロバイダは value プロパティを受け取り、これが子孫であるコンシューマコンポーネントに渡され
  • 1 つのプロバイダは多くのコンシューマと接続することが出来る
  • プロバイダの子孫の全てのコンシューマは、プロバイダの value プロパティが変更されるたびに再レンダーされる
  • プロバイダからその子孫コンシューマ(.contextType や useContext を含む)への伝播は shouldComponentUpdate メソッドの影響を受けないため、コンシューマは祖先のコンポーネントが更新をスキップしている場合でも更新る

Class.contextType

?わからなかったこと

MyContextの値を使用し、マウント時に副作用を実行します

ってどういう意味だろう?MyContextは

class MyClass extends React.Component{
  componentDidMount(){
  let value = this.context;
   /* MyContextの値を使用し、マウント時に副作用を実行します */
  }
  componentDidUpdate(){
    let value = this.context;
  }
  componentWillUnmount(){
    let value = this.context;
  }

}
  • この API では、1 つのコンテクストだけ登録することができます。

Context.Consumer

  • コンテクストの変更を購読する React コンポーネント。関数コンポーネント 内でコンテクストを購読することができる。
<MyContext.Consumer>
  {value => /* コンテクストの値に基づいて何かをレンダーします */}
</MyContext.Consumer>
  • function as a child が必要です。この関数は現在のコンテクストの値を受け取り、React ノードを返す。この関数に渡される引数 value は、ツリー内の上位で一番近いこのコンテクスト用のプロバイダの value プロパティと等しくなる。
  • このコンテクスト用のプロバイダが上位に存在しない場合、引数の value は createContext() から渡された defaultValue と等しくなる。
わからなかったこと
<DataProvider render={data => (
  <h1>Hello {data.target}</h1>
)}/>

Context.displayName

  • コンテクストオブジェクトは displayName という文字列型のプロパティをもつ。 React DevTools はこの文字列を利用してコンテクストの表示のしかたを決定する

動的なコンテクスト

theme-context.js
export const themes = {
  light: {
    foreground: '#000000',
    background: '#eeeeee',
  },
  dark: {
    foreground: '#ffffff',
    background: '#222222',
  },
};

export const ThemeContext = React.createContext(
  themes.dark // デフォルトの値
);

themed-button.js
import {ThemeContext} from './theme-context';

class ThemedButton extends React.Component {
  render() {
    let props = this.props;
    let theme = this.context;
    return (
      <button
        {...props}
        style={{backgroundColor: theme.background}}
      />
    );
  }
}
ThemedButton.contextType = ThemeContext;

export default ThemedButton;

ネストしたコンポーネントからコンテクストを更新する

複数のコンテクストを使用する

注意事項

レガシーな API

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

Next.js 9.5のアップデートにより、GitHub Pagesで妥協しない動的ルーティングが可能になった

Qiita: Next.jsで作ったアプリをGitHub Pagesにデプロイする@ozaki25』や、『Qiita: Next.jsをGitHub Pagesにデプロイしたらリンクが壊れた』、『GitHub: gh-pages Hello World example』にNext.jsのWebサイトをGithub Pagesに投稿する方法が載っていますが、どれも静的ページのみへのルーティングを説明していて、動的ルーティングには深く言及されていません。

そこで、Next.js 9.4でサイトをGitHub Pagesにあげたところ、動的ルーティングでハマってしまいました。結果、対処法がわからずにVercelに移行したのですが、Next.js 9.5のアップデートベースパスをカスタマイズできる機能が追加され、自分がハマっていた動的ルーティングが解決しました!?

この記事では、Next.js 9.4の動的ルーティングのハマっていた背景とNext.js 9.5での対処法について説明します。

Next.js 9.4 × GitHub Pages ?

ご存知だと思いますが、GitHub Pagesはhttps://[username].github.io/[repository-name]といったurlにマッピングされます。これによって、以下のような普通のNext.jsのルーティングでは、https://[username].github.io/[repository-name]/itemsに行ってほしいのに、https://[username].github.io/itemsにルーティングされてしまい、リロード時にエラーとなってしまいます。

MyLink.tsx
const MyLink = () => (
  <Link href="/items">
    <a>Item</a>
  </Link>
)

なので、『Qiita: Next.jsをGitHub Pagesにデプロイしたらリンクが壊れた』などに記載されている変更が必要となります。

next.config.js
module.exports = {
  assetPrefix: process.env.NODE_ENV === 'production' ? '/[repository-name]' : ''
}
MyLink.tsx
const withRootPath = (path: string) =>
  process.env.NODE_ENV === 'production' ? `/[repository-name]/${path}` : path

const MyLink = () => (
  <Link href={withRootPath("/items")}>
    <a>Item</a>
  </Link>
)

これで、静的なリンクへはうまくいきます。が、前述している通り、動的ルーティングの場合は同様に以下のようにしてもプリフェッチされず、ブラウザのロードが挟まれてしまいます。

MyLink.tsx
const withRootPath = (path: string) =>
  process.env.NODE_ENV === 'production' ? `/[repository-name]/${path}` : path

const MyLink = () => (
  <Link href={withRootPath("/items")}>
    <a>Item</a>
  </Link>
)
const MyDynamicLink = () => (
  <Link href={withRootPath("/items/[id]")} as={withRootPath("/items/a")}>
    <a>Item</a>
  </Link>
)

また、上の記事に記載されている以下の方法で実装すると、エラーを出力します。

MyLink.tsx(差分)
const MyDynamicLink = () => (
  <Link href="/items/[id]" as={withRootPath("/items/a")}>
    <a>Item</a>
  </Link>
)

error.PNG

これは、hrefasが対応していない事によるエラーです。詳しい内容はNext.jsのリポジトリに記入してあります。vercel/next.js-Incompatible href and as values

…ということで、自分の知る限りではGitHubでNext.jsの動的ルーティングを実装するには、プリフェッチとブラウザへのロードを妥協するしかありませんでした。

Next.js 9.5 × GitHub Pages ?

最初に説明している通り、Next.js 9.5でベースパスを設定できるようになりました。対処法も簡単で、next.config.jsに追加するだけでOKです。

next.config.js
module.exports = {
  basePath: process.env.NODE_ENV === 'production' ? '/[repository-name]' : ''
}

これだけで、妥協しない動的ルーティングが可能になります?

おわりに

自分の認識不足で、Next.js 9.4でも動的ルーティングでプリフェッチできる方法がありましたら、教えてください。

デモとして使用したリポジトリ
- https://github.com/syakoo/next_gh-pages

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

GatsbyJSの魅力を知った...

こんにちは(๑╹ω╹๑ )

実は私...

恥ずかしながら.....

つい数ヶ月までJavascriptと言えば

  • Javascript(jQuery補助程度
  • jQuery(長いこと書いていた
  • Node.js(ほんの少々
  • Vue.js(数年前に入門一周した程度

でした?

根っからのバックエンドエンジニアで、
LAMP構成大好きでした?

でもでもでもでも!!

早く技術スタック見直さないと!

特にJavascript?

という訳で2ヶ月ほどPHP書くのをお休みしてました!

// ?
sleep(60 * 60 * 24 * 60);

代わりにReact始めました?

(技術スタックが少しモダンになった気がします?

今では「LAMP構成愛してた?よ?」と言わんばかりの浮気?心移り?

分かんないですが魅了されています?

React

尊いです?

バインディング is 神!?‍♂️

実際にバインディングは内部で実装されていると思うのですが、

C言語のポインタ??

PHPで言うとリファレンス渡し??

そんな気分です?

GatsbyJS

地球は青かった?(๑╹ω╹๑ )

いえいえ?

GatsbyJSは爆速だった?

実は以前からGatsbyJSで実装されている爆速SPAがとても魅力的で仕方有りませんでした?

※GatsbyJSを始めてまだ数日程なので、誤った認識があるかもしれないです?

GatsbyJSの特徴

わくわくしながらLighthouseやGTmetrixで計測できる!

画面サイズ毎に画像を書き出している

ビルド後のファイル群を直接触ることはないですが、

GatsbyJSビルド後ファイル構成

画面幅毎に最適化されたサイズの画像を書き出していました!

GatsbyJSビルド後iconsディレクトリ.png

Data URLスキームの画像も書き出している

深い仕様までは分かっていないのですが、
画像によってはData URLスキームなインラインで出力されている画像も多く見受けられました!

基本的にMinify

ビルド後に出力されたindex.htmlファイルを見ると確認できるのですが、
基本的には何もかもMinifyされていました?

  • CSSはstyleタグを用いたインライン化
  • Javascriptは別ファイルでMify化

凄いです!!!!

gatsby-config.js

Non WebPack構成でもビルド出来る!?

GatsbyJSの設定ファイル(gatsby-config.js)であんなこと?やこんなこと?が出来ます?

他にも!

gatsby-plugin-alias-importsというプラグイン重宝しています!

{
    resolve: `gatsby-plugin-alias-imports`,
    options: {
        alias: {
            '@components': 'src/components',
            '@images': 'src/images',
            '@styles': 'src/styles',
            '@stores': 'src/stores',
        },
        extensions: ['js'],
    },
},

上記のような設定のみで、

import main from "../../../src/components/main/";

のような記述も、

import main from "@components/main/";

のように実装できます!

※ gatsby-config.jsファイルからの相対パスを予めエイリアス登録出来る

まとめ

JAMstack構成でもっとReactやGatsbyJSを触ってみます?

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

react-scrollでトップページに戻るアニメーションを実装してみた

はじめに

今回、よくサイトでページ下部に固定表示されている「ページトップへ戻る」という機能をreactで実装する機会があったのでアウトプットとしてこの記事を残します。

アニメーションの調査

ページトップに戻るアニメーションを実装しようとした際に最初に思い浮かんだのは、jQueryでの実装でした。
しかし、そもそもjQueryはライブラリのサイズが大きくて古いということだったので他のreactに対応しているアニメーションパッケージを調査することにしました。
そこで見つけたのがreact-scrollというパッケージ。
react-scrollは様々なfunctionがパッケージに含まれていて、scrollToTopやscrollToBottomなどの関数で簡単にページ上下へのスクロールが実装できます。

react-scroll
https://www.npmjs.com/package/react-scroll

完成形

アニメーションの挙動はこんな感じです。

画面収録 2020-07-28 0.53.43.mov.gif

実装方法

①react-scrollをインストール

②react-scrollからanimateScroll as scrollをimportする

③functionとしてscrollToTopを定義する

④ボタンをクリックした時にイベントが発火するように
onClick={scrollToTop} を記述。

実際に書いたコードがこちら↓

/**
 * そのページの先頭に戻る
 */

export const BackTop: React.FC<Props> = ({ onClick }: Props) => {
  return (
    <div className="bg-gray-100">
      <div className="container mx-auto py-4 max-w-screen-md">
        <div className="px-20">
          <TextButton
            text={'⬆ このページの先頭へ'}
            onClick={onClick}
            buttonClassName="w-full"
            textClassName=" text-gray-400 font-bold"
          />
        </div>
      </div>
    </div>
  );
};

これはまだコンポーネントの状態でonClick={scrollToTop}でボタンをクリックしたした際のアニメーションが実装されていません。実際に今回作成したBackTopコンポーネントを使うページでfunctionとしてscrollToTopを定義するとアニメーションが実装できます。

※また今回はTextButtonのコンポーネントを使用しています

まとめ

functionとしてscrollToTopを定義してonclickで発火させるだけで意外と簡単に実装できました。
react-scrollの他にもscroll用パッケージが何個ありましたが、僕はこれが一番シンプルで簡単に実装できると思いました。
またreactに関する知識(JavaScript自体)がまだまだだなと感じたのでまだまだ勉強が必要です笑

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

フロントエンド初心者がReactを触ってみた

環境

Mac OS Catalina

プロジェクトの作成

create-react-appで作成できる

// プロジェクトを作成したいディレクトリで
$ npx create-react-app react-example-app

// いろいろパッケージがダウンロードされる

プロジェクトのディレクトリへ移動

$ cd react-example-app
$ npm start

(一部略)
Compiled successfully!

You can now view react_app_practice in the browser.

  Local:            http://localhost:3000

以下の画像のようなページに遷移できるはず。

Screen Shot 2020-07-27 at 23.31.43.png

index.jsindex.cssApp.jsに変化を加えてみる

別のものを表示してみる。index.jsを以下のように書き換える。

App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';

function Moneybook() {
  return (
    <div>
      <h1>
        小遣い帳
      </h1>
      <table className="book">
        <thead>
          <tr>
            <th>
              日付
            </th>
            <th>
              項目
            </th>
            <th>
              入金
            </th>
            <th>
              出勤
            </th>
          </tr>
        </thead>
        <tbody>
          <tr><td>1/1</td><td>お年玉</td><td>10000</td><td></td></tr>
          <tr><td>1/3</td><td>ケーキ</td><td></td><td>500</td></tr>
          <tr><td>2/1</td><td>お小遣い</td><td>3000</td><td></td></tr>
          <tr><td>2/5</td><td>漫画</td><td></td><td>600</td></tr>
        </tbody>
      </table>

    </div>
  );
}

export default Moneybook;

index.cssも書き換える

index.css
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

.book {
  border-collapse: collapse;
}

.book th, .book td {
  border: solid 1px;
  padding: 1px 15px;
}

最後にindex.jsも書き換える

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import MoneyBook from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <MoneyBook />,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

これで npm startとすれば、以下のように表が表示されるはず。

Screen Shot 2020-07-28 at 0.36.37.png

これからもいろいろ他のものも触っていきたい。

参考

作りながら学ぶReact入門

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