ただ日々を記すもの

意識高めを装うことができます

TODOリストを改修する

前回紹介したTODOアプリを改修していきます。

Image from Gyazo

具体的には以下の2点。

- タスクを追加するごとにテキストボックスの入力値をクリアする
- 管理しやすいようにディレクトリ分けを行う

テキストボックスの入力値をクリアする

タスクを追加したときに、Storeで保持しているtaskに空文字をセットします。

// tasksReducer
    case 'ADD_TASK':
      return {
        ...state,
        task: '', // 追加
        tasks: state.tasks.concat([action.payload.task])
      }

そして空にしたtaskがテキストボックスに反映されるようにしていきます。

// TodoApp
  return (
    <div>
      {/* value={task}を追加 */}
      <input type="text" value={task} onChange={(e) => store.dispatch(inputTask(e.target.value))} />
      <input type="button" value="ADD TASK!" onClick={() => store.dispatch(addTask(task))} />
      <ul>
        {tasks.map((task, index) => {
          return (<li key={index}>{task}</li>)
        })}
      </ul>
    </div>
  )

これでタスクを追加するごとに入力値がクリアされるようになります!

ただ、このままだと何も入力せずに「ADD TASK!」ボタンを押すと空文字がリストに追加されてしまいます。

これを直すために、空文字のときはStoreに追加されないようにしていきます。

// tasksReducer
    case 'ADD_TASK':
      if (!action.payload.task) return state // 追加
      return {
        ...state,
        task: '',
        tasks: state.tasks.concat([action.payload.task])
      }

これで完成です!

Image from Gyazo

ディレクトリ分けを行う

次にディレクトリ分けを行っていきます。
今回は以下のような構成にしていきます。

/components
/actions
/reducers
reducer
// reducers/tasksReducer.js

const initialState = {
  task: '',
  tasks: []
}

export function tasksReducer(state = initialState, action) {
  switch (action.type) {
    case 'INPUT_TASK':
      return {
        ...state,
        task: action.payload.task
      }
    case 'ADD_TASK':
      if (!action.payload.task) return state
      return {
        ...state,
        task: '',
        tasks: state.tasks.concat([action.payload.task])
      }
    default: return state
  }
}
actions
// actions/tasks.js

export const inputTask = (task) => ({
  type: 'INPUT_TASK',
  payload: {
    task: task
  }
})

export const addTask = (task) => ({
  type: 'ADD_TASK',
  payload: {
    task: task
  }
})
components
// components/TodoApp.js

import React from 'react'
import { inputTask, addTask } from '../actions/tasks'

export default function TodoApp({ store }) {
  const { task, tasks } = store.getState()
  return (
    <div>
      <input type="text" value={task} onChange={(e) => store.dispatch(inputTask(e.target.value))} />
      <input type="button" value="ADD TASK!" onClick={() => store.dispatch(addTask(task))} />
      <ul>
        {tasks.map((task, index) => {
          return (<li key={index}>{task}</li>)
        })}
      </ul>
    </div>
  )
}
index.js
import React from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux'
import TodoApp from './components/TodoApp'
import { tasksReducer } from './reducers/tasksReducer'

const store = createStore(tasksReducer)


function renderApp(store) {
  render(
    <TodoApp store={store} />,
    document.getElementById('root')
  )
}

store.subscribe(() => renderApp(store))
renderApp(store)

これでディレクトリわけも完了です!

ReactとReduxで超簡易のTODOリストを作る

ReactとReduxを使った超簡単なTodoリストを作成していきます。

対象
  • React少し触ったことある人
  • Reduxを使ったことがなくなれたい人

完成形

Image from Gyazo

準備

まずはcreate-react-appでプロジェクトを作成します。
Reactで開発を行うときに大変なのが環境づくり。

webpackいれたり、babelいれたり、、大変なので今回はそのあたりを気にせずReactの開発に集中できるcreate-react-appでプロジェクトを作成します。
インストールは簡単で↓だけ。

create-react-app redux-training

これでReactでの開発が行なえます!

今回はReduxで開発をしていきたいので、作成したredux-trainingに移動し、以下を実行しておきます。

npm install -S redux

TODOアプリを作成

それではアプリを作っていきます。
今回はsrc/index.jsを編集していきます。

viewを作る

まずはTODOを追加するためのテキストボックスとボタンを作っていきましょう。

ボタンなどを表示するTodoAppコンポーネントを作成します。

import React from 'react';
import ReactDOM from 'react-dom';

// 新規に追加
function TodoApp() {
  return (
    <div>
      <input type="text" />
      <input type="button" value="ADD TASK!" />
    </div>
  )
}

// renderするコンポーネントをAppからTodoAppに変更
ReactDOM.render(<TodoApp />, document.getElementById('root'));

これでnpm startを実行すると↓のようになっているかと思います。
f:id:RONKUN:20190202224946p:plain:w350

Reducerの定義

次にReducerを作って行きます。
Reduxを理解する上で重要な登場人物は「Store」「Dispatcher」「Reducer」「Action」になります。

簡単に説明すると、

Store: アプリケーションの状態(State)とロジックを保持
Dispatcher: データの流れを管理。Dispatcherを通じてすべてのActionがStoreに渡される。
Reducer: Storeの状態を変化させるための関数
Action: 単純なObject。dispatchすることでStoreに渡される。

ではReducerを実装していきます。

Reducerは引数でいかの値を受け取ります。

第一引数: State
第二引数: Action(Object)
function tasksReducer(state = initialState, action) {
}

第一引数で渡す状態の初期値を設定して上げる必要があるので、initialStateも合わせて定義します。

const initialState = {
  task: ''
}

そして処理についてですが、
ReducerではActionの内容によって既存の状態を変化させます。

function tasksReducer(state = initialState, action) {
  switch (action.type) {
    case 'INPUT_TASK':
      return {
        ...state,
        task: action.payload.task
      }
    default: return state
  }
}

上記はINPU_TASKというactionが送られてきたときにtaskの値を更新しています。
更新されるのはStoreに保持している値になります。

Storeの定義

Reducerの定義が終わったので次にStoreを定義します。
ReduxはcreateStoreという関数を用意しており、これを実行することでStoreを生成することができます。
Storeを作成する際には、Reducerが必要になります。ここでは、先程定義したtasksReducerを使用してStoreを生成していきます。

import { createStore } from 'redux'

const store = createStore(tasksReducer)

ActionCreatorの定義

ActionCreatorはActionを生成するための関数になります。

const inputTask = (task) => ({
  type: 'INPUT_TASK',
  payload: {
    task: task
  }
})

taskを受け取り、Actionオブジェクトを返すだけの関数です。

さて、これで登場人物は一通り出揃いました。
viewを調整して、入力した値がStoreに渡るようにしてみましょう。

まず、TodoAppコンポーネントにstoreを渡します。

ReactDOM.render(
  <TodoApp store={store} />,
  document.getElementById('root')
);

そして渡ってきたStoreをTodoAppで使用していきます。

function TodoApp({ store }) {
  // getState()関数はStoreに保持している値を返却する
  // ここではtaskを取り出しています。
  const { task } = store.getState()
  return (
    <div>
      <input type="text" onChange={(e) => store.dispatch(inputTask(e.target.value))} />
      <input type="button" value="ADD TASK!" />
    </div>
  )
}

ReactDOM.render(<TodoApp store={store} />, document.getElementById('root'));

テキストが変更されるごとにstore.dispatchが呼び出されます。
store.dispatch(inputTask(e.target.value))を細かく見ていきましょう。

e.target.value => テキストボックスの入力値を取得
inputTask(e.target.value) => 定義したActionCreatorを呼び出しています。ActionCreatorからはActionオブジェクトが返却されてきます。
store.dispatch(inputTask(e.target.value)) => Actionオブジェクトをstoreにdispatch(送って)しています。

dispatch関数が呼ばれるとStoreに紐づけているReducerが呼ばれ、Actionオブジェクトの内容によってStoreの値を更新してくれます。

ここで一旦ブラウザで挙動を確認してみたいと思います。

少し、storeの更新をする処理を記述する必要があります。

import { render } from 'react-dom'

// 追加
function renderApp(store) {
  render(
    <TodoApp store={store} />,
    document.getElementById('root')
  )
}

store.subscribe(() => renderApp(store))
renderApp(store)
// コメントアウト
// ReactDOM.render(<TodoApp store={store} />, document.getElementById('root'));

新たにrender関数をimportし、今まで使用してReactDom.renderの代わりに使用します。 画面に描画してくれるという面では同じ役割です。

store.suscribe()関数はstoreに更新があるたびに呼び出されます。 ここではstoreの更新のたびにTodoAppコンポーネントがレンダリングされるようにしています。

では、npm startで動作を確認してみます。 動き自体は今までと変わっていませんが、入力値がStoreに渡されています。

Todoをリスト表示

さぁ、次はボタンを押してTodoを追加していきます。

まずtaskを複数保持できるようにtasksという名前の配列を用意します。
加えて、task追加用のActionCreatorも新規に追加します。

const initialState = {
  task: '',
  tasks: [] // 追加!!
}

// 追加
const addTask = (task) => ({
  type: 'ADD_TASK',
  payload: {
    task: task
  }
})

ActionCreatorが用意できたら、このActionオブジェクトがdispatchされたときにStateを更新するためのReducerの処理を追加します。

function tasksReducer(state = initialState, action) {
  switch (action.type) {
    case 'INPUT_TASK':
      return {
        ...state,
        task: action.payload.task
      }
    // 追加
    case 'ADD_TASK':
      return {
        ...state,
        tasks: state.tasks.concat([action.payload.task])
      }
    default: return state
  }
}

ここでポイントなのは、
tasksを追加するときの処理。
tasks: state.tasks.concat([action.payload.task])
ここはpushではなくconcatやspread operatorを使うようにします。

理由は、pushは現在の状態であるstate自体に変更が加わってしまい、予期せぬ副作用を起こすことがあるからです。
そのため新しい配列を生成する、concatやSpread Operator(...を使うやつ)を使用します。

最後に、TodoAppコンポーネントを変更していきます。

function TodoApp({ store }) {
  const { task, tasks } = store.getState() // リスト表示するためにtasksを追加
  return (
    <div>
      <input type="text" onChange={(e) => store.dispatch(inputTask(e.target.value))} />
      {/* 追加 */}
      <input type="button" value="ADD TASK!" onClick={() => store.dispatch(addTask(task))} />
      <ul>
        {tasks.map((task, index) => {
          return (<li key={index}>{task}</li>)
        })}
      </ul>
    </div>
  )
}

これでTodoリストの完成です。
今回はReactとReduxでTodoリストを作成しました。

おまけ1

ここからは理解を深める意味も込めて、簡単な課題になります。

今回のTodoリストだと、タスクを追加したあとテキストボックスに入力値が残ってしまっています。少し気持ち悪いですね。

ここをテキストボックスの入力値がクリアされるようにしてみてください!

おまけ2

今回はすべてindex.jsにドバっと書いていきました。 けどこれってすごく管理しづらいですよね。 この量だからまだいいですが、複雑なアプリケーションを作っていくとなると可読性も下がり、管理しづらくなってしまいます。

そこで、いかのようにディレクトリを分けるようにしてみましょう!

/components
/actions
/reducers

次回のブログでおまけ1,2のコードを載せておきますね。 (おまけの実装はこちら

それでは。

最終的なコード

import React from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux'

const initialState = {
  task: '',
  tasks: []
}

const inputTask = (task) => ({
  type: 'INPUT_TASK',
  payload: {
    task: task
  }
})

const addTask = (task) => ({
  type: 'ADD_TASK',
  payload: {
    task: task
  }
})

function tasksReducer(state = initialState, action) {
  switch (action.type) {
    case 'INPUT_TASK':
      return {
        ...state,
        task: action.payload.task
      }
    case 'ADD_TASK':
      return {
        ...state,
        tasks: state.tasks.concat([action.payload.task])
      }
    default: return state
  }
}

const store = createStore(tasksReducer)

function TodoApp({ store }) {
  const { task, tasks } = store.getState()
  return (
    <div>
      <input type="text" onChange={(e) => store.dispatch(inputTask(e.target.value))} />
      <input type="button" value="ADD TASK!" onClick={() => store.dispatch(addTask(task))} />
      <ul>
        {tasks.map((task, index) => {
          return (<li key={index}>{task}</li>)
        })}
      </ul>
    </div>
  )
}

function renderApp(store) {
  render(
    <TodoApp store={store} />,
    document.getElementById('root')
  )
}

store.subscribe(() => renderApp(store))
renderApp(store)

スマホで見たときはてなブログのMarkdown記法テーブルが見切れてしまうときの対処法

起こっていた現象

Markdown記法でテーブルを書いていたのですが、 スマホでみてみると右側が見切れてしまっていました。 今回はその時に行った対処法を紹介します!

f:id:RONKUN:20181116205131j:plain:w300

対処法

スマホで見たときはテーブルを横方向にスクロールできるように設定していきます。

テーブルをdivタグで囲む

Markdown記法でテーブルを書いた場合、単純にdivで囲ってしまうとテーブルがテーブルと認識されなくなってしまいます。
なので、jQueryでテーブルをdivタグで囲むように設定します。

デザイン > カスタマイズ > ヘッダ内にあるタイトル下 に以下のコードを追加します。

$(function(){ 
  $('table').wrap('<div class="scrolled-table"></div>'); 
});

スクロールされるようにCSSを追記

デザイン > カスタマイズ > ヘッダ内のデザインCSS で見切れを防ぐため、テーブルがスクロールするようにCSSを追記します。
今回の場合は、スマホのみが対象になるのでメディアクエリを使っています。

@media (max-width: 680px) {
  .scrolled-table {
    overflow: scroll;
  }
}

結果

スマホで表示してみると、 しっかりと横方向にスクロールできるようになっています。
これで今まで見えなかった 好きな数字 列が見えるようになりました。

f:id:RONKUN:20181116210531j:plain:w300

はてなブログで「続きを読む」を入れてみる!

長い記事を書いた場合や続きはトップページではなく詳細ページで表示させたいときに使えるのが「続きを読む」記法。

今回はその使い方を調べたので書いて行きたいと思います!

続きを読む

TACの講座を受講し、応用情報技術者試験に受かりました

応用情報技術者試験について

言わずもがななITの資格。 基本情報技術者試験の上位資格に該当。

転職を考えていたので取っておくと有利かなと思い受験。

  • 受験日 2018年4月15日

  • 費用 5700円

  • 合格率 平成30年度春期 22.7% (6,917人 / 30,435人)

Oracleなどのベンダー資格だと2万円以上するのでお得

出題形式や今後の日程などはこちら

学習方法

TAC

今まで何度か受験を試みたのですが、 なかなか学習のモチベーションが続かなかったので今回はTACの講座を受講しました。

受講したのは 本科生B というコース。
テクノロジ系よりマネジメント系のほうが学習時間が少なく点も取りやすいかなと判断しこちらのコースにしました。
他にもいくつかコースが用意されているので検討してみると良いかと思います。

私の場合は、web通信講座を
早割や再受講割(以前に全く違う分野の講座を受講していたため)などを利用し
65000円ほどで受講しました。

www.tac-school.co.jp

どんな感じで利用したか

通信講座なので、好きな端末で時間があいたときに見ていた感じです。
私の場合は、通勤中に再生速度を早めながら見ていました。

だいたい通勤時間が30分くらいだったので、
1日に1講座見終わるくらいのペースで見ていました。

もちろん問題を解く時間もあったりするので1講座見終わるのが2日や3日かかってしまう日もありました。

2月までは動画を中心に学習しつつ、 3月からは過去問を中心に問題を解く時間を増やしました。 問題集も教材に含まれていたので、あらたに本を買ったりすることはありませんでした。

結果

無事に合格しました。
午前午後ともに100点満点中60点以上を取れれば合格となります。

自己採点をしたときは、60点行くか微妙だったのですが
無事、ギリギリ受かっていました。

まとめ

時間を効率的に使いたい人や、基本情報技術者試験受かってある程度知識はあるけどさっと知識の振り返りがしたいという人にはTACの講座を受講するのはいい選択肢なんじゃないかと思います。

他にも講座を提供しているところはあるので、いくつか見比べてみるといいかと思います!
とりあえずTACの講座は講義がわかりやすかったです。

あと、応用情報の結果は発表までに2ヶ月くらいかかり
だいぶ焦らされるのでしっかり勉強して余裕をもって受かるくらいな実力にしておくことを強くおすすめします!