20191125のReactに関する記事は7件です。

プライベートリポジトリをパスワードで限定公開するアプリを作った

GitHubのプライベートリポジトリを不特定多数に公開したい時ってありません? 私はあります、書類選考など。
不特定多数だから一人一人招待は無理だし、パスワード認証程度でいいんだけどなあと思いながら、
GitHubの設定でどうにかできないかと調べてみたんですが、ダメですね、なかったです。かなしいです。

クソみたいなリポジトリなんてどうせ誰も見ないんだからパブリックにしちゃえば?と思われるかもしれません。
パブリックはなんか嫌だし、私が作ったものはクソじゃないし、百歩譲ってクソだったとしても自分のクソを全世界に公開する趣味はないです

なので作りました。他になさそうだったので。

http://35.233.244.144/
(クリックしても飛べない場合URLをコピーしてみてください)

GitHubのリポジトリはこちら

ss.png

MineSweeper3Dのみパスワード公開してます。「unity」

これなに?

Webアプリケーションです。
使用技術は
フロント:React
サーバー:Golang echo
DB:Mongo
これはGCEのインスタンスの中のDockerで動いてます。
Webサービスではないので自分のリポジトリに適用させる場合はサーバー立ててCloneして云々が必要です。

なぜWebサービスにしなかったのか

これはGitHubのアクセストークンを使用し、プライベートリポジトリを取得してきています。
悪意のある運営者であれば、サービスを使用した人のプライベートリポジトリを取得できます。
それって気持ち悪くない? 私だったら利用しません。なのでWebサービスにはしませんでした。

どのように動いているのか

GitHub APIではアクセストークンを使用してリポジトリのファイルを取得できます。トークンは生成する必要があります。
https://api.github.com/repos/ユーザー名/リポジトリ/contents?access_token=トークン
みたいな。最初のディレクトリしか出ないので全て取得するにはディレクトリかを判別して再帰的に繰り返す必要があります。

サーバーを立てる前にGolangで対象のリポジトリをクローリングするところから始まります。
./repo -repo yourrepo -expire 2020-02-02 -password yourpassword
こんなコマンドをサーバー内で実行します。
これはプロジェクトのファイル一覧を再帰的に取得してDBに入れています。

あとはサーバーを立ててパスワード認証をして、認証に成功したらファイルを表示させてます。
ファイルは逐一GitHub APIを介してます。
用途としては、プライベートリポジトリの完全なミラーが目的ではなく、パスワード認証して限定公開が主目的だからです。
コマンド実行時のディレクトリ構造を保存し、そのパスをもとにファイルにアクセスしています。

全体的に難しいことはしてません。

ss2.png

まとめ

本当に技術的に気になりましたらソースを見てください。
私のようにプライベートリポジトリを限定公開したいという人がいましたら、これを使うなり、使わなくともこれが参考になればと思い、記事をしたためました。
調べても同様のものが見つからなくて絶望した過去の私のような人間が一人でも救われるのであれば幸いです。

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

ReactでVimライクなInputを書いた

こんにちは

今年入社しました @tom-ock です。
昨日terraformの記事を上げてくれた @Sadalsuud さんと同じチームで開発しております。
担当ほどはっきりしたモノは今まだないですが、最近Reactが面白いです。

自己紹介はこれくらいにして早速本題に。

TL;DR

Reactでviっぽいinputコンポーネントを作りました(type="text"です)。

ScreenShot 8.jpg

実演

注意

  • VimiumなどはOffにしてください
  • 仕様上英語入力しか受け付けません
  • 入力にはFocusする必要があるためクリックしてから入力してください
  • 幅も有限なので、入力しすぎたらノーマルモードでdを押してください
  • スマホからは操作できません!ごめんなさい

See the Pen Vinput by Tomoki Oke (@litalico-tomokioke) on CodePen.

(あるいは:octocat: こちら(Github Pages))

実装概説

テキストエディタっぽいカーソルをどうしても表現したかったのですが、
inputを使用して実装する方法が思い浮かばなかったので今回は全てdivで実装し、
inputはhiddenでstateで渡すことにしました。

stateはreducerで管理しています。

state. 内容
value 入力文字列
cursorIndex カーソルポジション
mode モード

今回はノーマルモードとインサートモードの切り替え、文字列の入力、ノーマルモードでのいくつか移動を実装しました。
これらの3つの属性のstate + 入力されるキーから、次のstateが決定されるためそれをreducerに書きました。

:file_folder: useVi.ts

const normalReducer: React.Reducer<State, Action> = (state, action) => {
  switch (action.key) {
    case "d": {
      return { ...state, value: "", cursorIndex: getIndex.start(state) };
    }
    case "i": {
      return { ...state, mode: "INSERT" };
    }
    case "a": {
      return { ...state, mode: "INSERT", cursorIndex: getIndex.append(state) };

至る所で移動する次のstateを計算するとごちゃごちゃしたので、カーソル移動とテキスト編集をそれぞれ別のファイルに分けて関数化したものをreducerでは使用しています。

:file_folder: getIndex.ts

const right: IndexGetter = ({ value, mode, cursorIndex }) => {
  if (value.length === 0 || cursorIndex !== value.length - 1) {
    return cursorIndex + 1;
  } else {
    return cursorIndex;
  }
};

const left: IndexGetter = ({ value, mode, cursorIndex }) => {
  if (cursorIndex > 0) {
    return cursorIndex - 1;
  } else {
    return cursorIndex;
  }
};

:file_folder: getValue.ts

const backspace: ValueGetter = ({ value, mode, cursorIndex }) => {
  return (
    value.slice(0, cursorIndex - 1) + value.slice(cursorIndex, value.length)
  );
};

const insert: ValueGetter = ({ value, mode, cursorIndex, key }) => {
  return (
    value.slice(0, cursorIndex) + key + value.slice(cursorIndex, value.length)
  );
};

ここに苦労しました

ボックス形のCaret

Caret(入力時にカーソルの位置を示す部分)を操作するCSSは現在caret-colorが提供されています。
これは色の操作のみ操作できるプロパティで、viライクなボックス形のCaretは表現出来ません。
そこでハック感ありますが、inputタグは使わずにdivタグで入力フォームを表現する事にしました。

キー入力をReducerのActionとしたかったのでonKeydownを使用した結果、英数字の入力のみ行える(日本語入力できない)仕様になったのはかなり心残りです。。

3.gif

Reducer

カーソル位置は前述のcursorIndexで保持し、NORMALモードとINSERTモードのカーソル移動を実現しました。

入力値、カーソル位置、モードなどの状態は

これらの3つの属性のstate + 入力されるキーから、次のstateが決定されるためそれをreducerに書きました。

次のstateを前のstateから副作用のない関数として返せるような構造(getValue.ts, getIndex.ts)に分けています。
Vimならではのモーションとオペレーターのイメージで分けたからか、意外と見やすいReducerになった気がします。

機能

そこまで多くないのであえて書きません。
READMEに書いてあるので、気になる方はこちらへ!
:octocat: Github(https://github.com/ok8omk/Vinput)

文字の入力をkeydownにしてしまったので日本語入力を受け付けられなかったり、
正規表現パワー足りず実装できてない部分あったり、
本当は複数行のテキストエリアを実装したかったり…
…色々やり残してるのでPR絶賛お待ちしています :bow:

終わりに

ブラウザとかSlackとかで入力してる時に、全部Vimみたいにカーソル移動できたらいいのに!と思う瞬間が度々あるのが発端でした。(たまにありませんか?)

jsでCLIを表現するのは不毛な実装感がありますが、Reactとreducerのいい練習になりました。

npmで公開したので興味持って頂けた方は是非使って下さい!
npm(@ok8omk/vinput)

課題だらけと思うのでissue大歓迎です、気長に直していくのでぜひお願いします :bow:

ReactをVimで書く記事はあっても、
ReactでVimを書く記事は見たことないなあと思って書いたので、
パイオニアであることを祈っております… :aries::gemini::scorpius:

明日は @litalico-takamasa-mizukami さんのAMP Storyです。
お楽しみに!

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

ReactでVimライク(H←L→)なInputを書いた

こんにちは

今年入社しました @tom-ock です。
昨日terraformの記事を上げてくれた @Sadalsuud さんと同じチームで開発しております。
担当ほどはっきりしたモノは今まだないですが、最近Reactが面白いです。

自己紹介はこれくらいにして早速本題に。

TL;DR

Reactでviっぽいinputコンポーネントを作りました(type="text"です)。
NORMALモードでHで左に、Lで右にカーソルが移動します。

ScreenShot 8.jpg

実演

注意

  • VimiumなどはOffにしてください
  • 仕様上英語入力しか受け付けません
  • 入力にはFocusする必要があるためクリックしてから入力してください
  • 幅も有限なので、入力しすぎたらノーマルモードでdを押してください
  • スマホからは操作できません!ごめんなさい
  • Safariでの不具合が現在確認されています。ご了承ください。

See the Pen Vinput by Tomoki Oke (@litalico-tomokioke) on CodePen.

(あるいは:octocat: こちら(Github Pages))

実装概説

テキストエディタっぽいカーソルをどうしても表現したかったのですが、
inputを使用して実装する方法が思い浮かばなかったので今回は全てdivで実装し、
inputはhiddenでstateで渡すことにしました。

stateはreducerで管理しています。

state. 内容
value 入力文字列
cursorIndex カーソルポジション
mode モード

今回はノーマルモードとインサートモードの切り替え、文字列の入力、ノーマルモードでのいくつか移動を実装しました。
これらの3つの属性のstate + 入力されるキーから、次のstateが決定されるためそれをreducerに書きました。

:file_folder: useVi.ts

const normalReducer: React.Reducer<State, Action> = (state, action) => {
  switch (action.key) {
    case "d": {
      return { ...state, value: "", cursorIndex: getIndex.start(state) };
    }
    case "i": {
      return { ...state, mode: "INSERT" };
    }
    case "a": {
      return { ...state, mode: "INSERT", cursorIndex: getIndex.append(state) };

至る所で移動する次のstateを計算するとごちゃごちゃしたので、カーソル移動とテキスト編集をそれぞれ別のファイルに分けて関数化したものをreducerでは使用しています。

:file_folder: getIndex.ts

const right: IndexGetter = ({ value, mode, cursorIndex }) => {
  if (value.length === 0 || cursorIndex !== value.length - 1) {
    return cursorIndex + 1;
  } else {
    return cursorIndex;
  }
};

const left: IndexGetter = ({ value, mode, cursorIndex }) => {
  if (cursorIndex > 0) {
    return cursorIndex - 1;
  } else {
    return cursorIndex;
  }
};

:file_folder: getValue.ts

const backspace: ValueGetter = ({ value, mode, cursorIndex }) => {
  return (
    value.slice(0, cursorIndex - 1) + value.slice(cursorIndex, value.length)
  );
};

const insert: ValueGetter = ({ value, mode, cursorIndex, key }) => {
  return (
    value.slice(0, cursorIndex) + key + value.slice(cursorIndex, value.length)
  );
};

ここに苦労しました

ボックス形のCaret

Caret(入力時にカーソルの位置を示す部分)を操作するCSSは現在caret-colorが提供されています。
これは色の操作のみ操作できるプロパティで、viライクなボックス形のCaretは表現出来ません。
そこでハック感ありますが、inputタグは使わずにdivタグで入力フォームを表現する事にしました。

キー入力をReducerのActionとしたかったのでonKeydownを使用した結果、英数字の入力のみ行える(日本語入力できない)仕様になったのはかなり心残りです。。

3.gif

Reducer

カーソル位置は前述のcursorIndexで保持し、NORMALモードとINSERTモードのカーソル移動を実現しました。

入力値、カーソル位置、モードなどの状態は

これらの3つの属性のstate + 入力されるキーから、次のstateが決定されるためそれをreducerに書きました。

次のstateを前のstateから副作用のない関数として返せるような構造(getValue.ts, getIndex.ts)に分けています。
Vimならではのモーションとオペレーターのイメージで分けたからか、意外と見やすいReducerになった気がします。

機能

そこまで多くないのであえて書きません。
READMEに書いてあるので、気になる方はこちらへ!
:octocat: Github(https://github.com/ok8omk/Vinput)

文字の入力をkeydownにしてしまったので日本語入力を受け付けられなかったり、
正規表現パワー足りず実装できてない部分あったり、
本当は複数行のテキストエリアを実装したかったり…
…色々やり残してるのでPR絶賛お待ちしています :bow:

終わりに

ブラウザとかSlackとかで入力してる時に、全部Vimみたいにカーソル移動できたらいいのに!と思う瞬間が度々あるのが発端でした。(たまにありませんか?)

jsでCLIを表現するのは不毛な実装感がありますが、Reactとreducerのいい練習になりました。

npmで公開したので興味持って頂けた方は是非使って下さい!
npm(@ok8omk/vinput)

課題だらけと思うのでissue大歓迎です、気長に直していくのでぜひお願いします :bow:

ReactをVimで書く記事はあっても、
ReactでVimを書く記事は見たことないなあと思って書いたので、
パイオニアであることを祈っております… :aries::gemini::scorpius:

明日は @litalico-takamasa-mizukami さんのAMP Storyです。
お楽しみに!

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

React Hooksの魅力

ようこそ、React Hooks Advent Calendar 2019へ!まずは1日目ということで、React Hooksの魅力について語ってみます。

React Hooksの魅力

関数コンポーネントでも広がる機能性

もともとReactのコンポーネントはクラスコンポーネントしかなく、そしてrenderだけで済むものが関数コンポーネントで書けるようになりました。ただ、関数コンポーネントを拡張していって、stateなどが必要になると、改めてクラスコンポーネントに書き換える必要が出てしまいました1

React Hooksでは、関数コンポーネントのまま、stateや更新時のフックを実現できるようになります。

カスタムフックによるモジュール化

クラスコンポーネントでは、クラス内部にcomponentDidMountcomponentDidUnmountといったコールバックは1つしか作れなかったので、前準備と後始末を分けて書くしかない、ということがありました。

React Hooksでは、コールバック類をいくつでも書けます。さらに、複数のHooksをまとめて呼び出すカスタムフックを作ることで、準備と後片付けをまとめて再利用することも可能としています。

粒度の細かな制御

クラスコンポーネントには、全体をメモ化して、propsstateが変化しない限り再描画を抑える機能があります。また、componentDidUpdateは更新のたびに実行されます。

React Hooksの場合、useMemoを使えば「特定の変数群が変わらない限り」という条件でメモ化ができますし、useEffectでも同様に「特定の変数群の変化」をきっかけとしてコールバックを実行できます。


  1. React 16.12時点でも、componentDidCatchgetSnapshotBeforeUpdateといった一部のコールバックは関数コンポーネントで再現できません。 

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

TypeScript 共有型の配列の型推論

TypeScript v3.6.3
では改善されている模様です。

こちらに記述がなかったと思ったので
https://qiita.com/uhyo/items/6acb7f4ee73287d5dac0

共有型(パイプ|で区切った指定した型のいずれかに一致する値の変数を代入できる型)
の配列の要素を取り出したとき型推論がうまくいかない。

なんらかの変数に一旦代入しておかないといけない。

export type hoge = FOO | BAR;

export typo FOO ={
  kind :"FOO";
  sawa : stinrg;
}
export type BAR={
   kind: "BAR";
   erika:string;
}

//NG
if (hoge[0].kind==='FOO' as const)
{
}
//OK
const homare = hoge[0]
if (homare.kind==='FOO' as const)

}

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

Reactコンポーネントに状態を持たせる方法の比較

Reactのコンポーネントに状態を持たせる方法をいくつかがあるが以下を紹介する。
* ReactのuseState
* React Redux
* ReactのuseReducer
* React ReduxのHooks

サンプルの内容はinputでテキストを編集してinputの中身を別の場所で表示する単純なもの。

ReactのuseState

ReactのuseStateを使う。一番簡潔に書ける。一つのコンポーネント内で完結するのならば一番楽。

不便な点は複雑なコンポーネントになるとコールバックを子供の引数に渡してあちこち引き回すことになってややこしいこと。

const UseState: React.FC = () => {
  const [text, setText] = useState("");
  return (
    <div>
      value={text}
      <input
        type="text"
        value={text}
        onChange={event => setText(event.target.value)}
      />
    </div>
  );
};

React Redux

reduxを使った普通の書き方。グローバルに定義されたストアから状態を参照できる。状態の書き換えはreducerに集約される。お約束の定義がそれなりにあるのでこのサンプル程度のことをやるにはめんどくさい。あとコンポーネントのpropsをマッピングを定義するのがボイラープレートぽくて大量に書くと嫌になる。

const SET_TEXT = "SET_TEXT";

interface SetTextAction {
  type: typeof SET_TEXT;
  payload: string;
}

type Action = SetTextAction;

interface State {
  text: string;
}

const reducer = (state: State = { text: "" }, action: Action): State => {
  switch (action.type) {
    case "SET_TEXT":
      return { text: action.payload };
    default:
      return state;
  }
};

const store = createStore<State, Action, {}, {}>(reducer);

interface AppStateProps {
  text: string;
}

interface AppDispatchProps {
  setText: (s: string) => void;
}

const App: React.FC<AppStateProps & AppDispatchProps> = props => {
  const { text, setText } = props;
  return (
    <div>
      value={text}
      <input
        type="text"
        value={text}
        onChange={event => setText(event.target.value)}
      />
    </div>
  );
};

export const DemoReduxReactRedux = () => {
  const RApp = connect(
    (initialState: State): AppStateProps => ({
      text: initialState.text
    }),
    (dispatch: Dispatch<Action>): AppDispatchProps => ({
      setText: (i: string) => dispatch({ type: SET_TEXT, payload: i })
    })
  )(App);
  return (
    <Provider store={store}>
      <RApp />
    </Provider>
  );
};


ReactのuseRecuer

Reactの新しいAPIのHooksに導入されてuseReducerを使うやりかた。
子コンポーネントにコールバックを引き回す必要があるがdispatchだけを渡せばいいのでそこはuseStateに比べて簡素になった。
それでもdispatch引き回しがあるのは面倒だと思われる。

const SET_TEXT = "SET_TEXT";

interface SetTextAction {
  type: typeof SET_TEXT;
  payload: string;
}

type Action = SetTextAction;

interface State {
  text: string;
}

const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case "SET_TEXT":
      return { text: action.payload };
    default:
      throw new Error("illegal action");
  }
};

const initialState: State = { text: "" };

export const DemoReduxUseReducer: React.FC = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div>
      value={state.text}
      <input
        type="text"
        value={state.text}
        onChange={event =>
          dispatch({ type: SET_TEXT, payload: event.target.value })
        }
      />
    </div>
  );
};

React ReduxのHooks

react-reduxにもHooks APIを使う方法が導入された。

useSelectoruseDispatchを使う。useSelectorで状態を読み出しuseDispatchで状態を書き換える。reducerなどは普通のreact-reduxと同じ。

connectでpropsのマッピングがする必要がなくなったのは楽になった思う。

const SET_TEXT = "SET_TEXT";

interface SetTextAction {
  type: typeof SET_TEXT;
  payload: string;
}

type Action = SetTextAction;

interface State {
  text: string;
}

const reducer = (state: State = { text: "" }, action: Action): State => {
  switch (action.type) {
    case "SET_TEXT":
      return { text: action.payload };
    default:
      return state;
  }
};

const store = createStore<State, Action, {}, {}>(reducer);

const App: React.FC = () => {
  const text = useSelector((state: State) => state.text);
  const dispatch = useDispatch();
  return (
    <div>
      value={text}
      <input
        type="text"
        value={text}
        onChange={event =>
          dispatch({ type: SET_TEXT, payload: event.target.value })
        }
      />
    </div>
  );
};

export const DemoReduxReduxHooks = () => {
  return (
    <Provider store={store}>
      <App />
    </Provider>
  );
};

まとめ

React ReduxのHooksを使うのが一番わかりやすいと思う。最初に一々マッピングを定義するのがボイラープレートぽくてめんどくさいし必要な状態が変わったときにコンポーネントの定義やマッピングの定義をいちいち書き換える手間が減ったのは楽になったように見える。

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

Material UI を使って出会う Warning: validateDOMNesting(...): <div> cannot appear as a descendant of  

Material UI を使うと大量に発生する warning

Warning: validateDOMNesting(...): <div> cannot appear as a descendant of <p>.

かなりうざいです。最新版にアップデートしても消えなくて辛い。

エラーの意味

DOM の Nesting には

じゃなくて div を使って という警告です。

毎度思うけど、React の警告厳しい。(でもReact好き)
React 的にそんなにまずいのでしょうかね。このエラーの意義はなんなんだろう?

警告対象

return (<p>
  aaaaaa
</p>)

正しい

return (<div><p>
  aaaaaa
</p></div>)

Material UI を使うと結構出る

これは一例です。

component={"p"} を指定してたらだめ。

エラー

<Typography component={"p"} variant="h4">Jobs</Typography>

修正コード

<Typography component={"div"} variant="h4">Jobs</Typography>

検証環境

mui 4.7.0

以上

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