LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

新卒エンジニアが Angular と React を比較してみた!!

Last updated at Posted at 2017-07-20
1 / 41

自己紹介

会社: ローカルワークス
名前: 伊藤敦之
年齢: 24歳  ← ダブったので新卒です!!
趣味: 囲碁
仕事: パソコンを触ること


作ったもの紹介...


の前に...


言い訳タイム

  • Rails のプログラミングを始めて1年の初心者です!
  • JS を勉強し始めて半年の超絶初心者です!!
  • 開発期間はそれぞれ2週間です!!!

作ったもの紹介!!!

  • 本を登録して検索できるWEBアプリ

    • Angular 4.2.4
    • Angular Material
    • Rails 5.1
  • Evernote みたいな日記WEBアプリ

    • React 15.5.4
    • react-router-dom
    • redux
    • Material UI
    • axios
    • Rails 5.1

今日話したいこと

初心者からみた

  • 学習コスト度
  • ハマる度
  • 感動度

フレームワークとしてくらべてみました


Angular

学習コスト度: ★☆☆
ハマる度: ★★☆
感動度: ★☆☆

good

  • view, router, HTTP requestなどなど,開発に必要なものは一通り揃ってる
  • Angular Way に乗っかれば単一責務を実現しやすい
  • JS, html, CSS のファイルが別れていて分かりやすい

bad

  • TypeScript を勉強しなきゃいけない
  • Angular4 の参考文献は英語がほとんど
  • Angular内のルールが多い

勉強してみて

  • Angular Tutorial をやれば誰でも動かせるようになる
  • 応用箇所は先行事例が少ないので、公式リファレンスを読むしかない

React

学習コスト度: ★★☆
ハマる度: ★★☆
感動度: ★☆☆

good

  • プロダクトに入れ込む粒度を選択できる
  • 日本語の参考文献が多い
  • 先行事例が多い

bad

  • jsx が気持ち悪い
  • ライブラリーの依存が多くなるので簡単にアップデートできない
  • 勉強するものが多い

勉強してみて

  • React Tutorial だけやってもフロント全般を任せられる程の知識はつかない
  • ライブラリーごとに勉強が必要
  • ClassName が罠...

開発ツールでくらべてみました


Angular

学習コスト度: ★☆☆
ハマる度: ★☆☆
感動度: ★★★
- Angular Material
- angular cli
- Angury

React

学習コスト度: ★☆☆
ハマる度: ★☆☆
感動度: ★★★
- Material UI
- create react app
- React Developer Tools


勉強してみて

  • 開発ツールは Angular の方が使いやすく、分かりやすい
  • Material UI はCSSを当てたい時にインラインCSSみたいに書き込まなくちゃいけなくて、最悪の場合JSXにべた書きして気持ち悪い
  • create react app はコマンドラインインタフェースとしては貧弱

アーキテクチャでくらべてみました


勉強する前

「Angular も React も所詮コンポーネントフレームワークっしょ。
チュートリアルもやったし、余裕っしょ。(鼻、ホジホジ)」


勉強し始めて...

「設計、むずすぎだろォォォォォォォォォォオオオオ!!!!!!!!!!!!!(ぐはっ)(ばたっ)」


図解します


image.png


image.png


じゃ、くらべていきましょうか...


コンポーネントの設計

ここは Angular, React 同じ考え方

Container Component と Presentational Component

学習コスト度: ★☆☆
ハマる度: ★☆☆
感動度: ★☆☆
- データの流れを一方向にするための役割分担
- Container Component は how things work (データ収集や取り扱い方)
- Presentational Component は how things look (データの表示)


Angular

# Container Component
export class HomeComponent implements OnInit {
  books: Observable<Book[]>;

  private searchTerms = new BehaviorSubject<string>('');

  constructor(
    private getBookService: GetBookService,
    private bookSearchService: BookSearchService
  ) { }

  onSearch(term: string): void {
    this.searchTerms.next(term);
  }

  ngOnInit(): void {
    this.books = this.searchTerms
      .debounceTime(300)
      .distinctUntilChanged()
      .switchMap(term => term
        ? this.bookSearchService.search(term) : this.getBookService.all())
      .catch(error => {
        console.log(error);
        return Observable.of<Book[]>([]);
      });
  }

}

# Presentational Component
export class ListsComponent {
  @Input() books: Book[]
}

React

# Container Component
class Home extends Component {
  componentDidMount() {
    const { diariesActions } = this.props
    diariesActions.getDiaries()
  }

  render() {
    const { diariesActions, selectedIndex, diaries } = this.props
    return (
      <div className='body'>
        <div className='side'>
          <Options />
          <Lists lists={diaries.getResult} onClick={(id) => diariesActions.selectDiary(id)} />
        </div>
        <div className='main'>
          <Page page={diaries.getResult[selectedIndex]}/>
        </div>
      </div>
    );
  }
}

Home.propTypes = {
  diaries: PropTypes.object.isRequired,
  selectedIndex: PropTypes.number.isRequired,
  diariesActions: PropTypes.object.isRequired,
};

function mapStateToHomeProps(state) {
  return {
    diaries: state.diaries,
    selectedIndex: state.selectDiary.index
  };
}

function mapDispatchToHomeProps(dispatch) {
  return {
    diariesActions: bindActionCreators(DiariesActions, dispatch),
  };
}

export default connect(
  mapStateToHomeProps,
  mapDispatchToHomeProps
)(Home);

# Presentational Component
const Lists = ({ lists, onClick }) => (
  <div>
    <ul>
      {lists.map(list => (
        <li key={list.id} onClick={() => onClick(list.id)}>
          <List list={list} />
        </li>
      ))}
    </ul>
  </div>
);

export default Lists;

state と prop の管理

ここ、一人で勉強していくのつらかったです...


Angular RxJS

学習コスト度: ★★★
ハマる度: ★★★
感動度: ★★★

Angular は React x Redux みたいに完成された設計方法がなく、state と prop の管理の設計で悩む必要がある。
今回は Angular 開発が推奨している RxJS に基いて、state と prop の管理や非同期処理を行ってみました。


こんな感じでやってみました

  • prop をいじるのはバックエンドに任せる
  • HTTP request は全部 Service に切り出す
  • prop は Observable の形で保持する
  • state が変更された時に Observer を Push するようなメソッドを用意する

今回は Angular の双方向データバインディングを使用し、イベントの発火時に state を Container Component に知らせ、そのイベントで Observer を Push するようなメソッドを用意する


# Container Component
export class HomeComponent implements OnInit {
  books: Observable<Book[]>;

  private searchTerms = new BehaviorSubject<string>('');

  constructor(
    private getBookService: GetBookService,
    private bookSearchService: BookSearchService
  ) { }

  onSearch(term: string): void {
    this.searchTerms.next(term);
  }

  ngOnInit(): void {
    this.books = this.searchTerms
      .debounceTime(300)
      .distinctUntilChanged()
      .switchMap(term => term
        ? this.bookSearchService.search(term) : this.getBookService.all())
      .catch(error => {
        console.log(error);
        return Observable.of<Book[]>([]);
      });
  }

}

# Presentational Component
export class SearchComponent {
  @Output() onSearch = new EventEmitter<string>();
  search(term: string) {
    this.onSearch.emit(term);
  }
}

勉強してみて

  • RxJS は鬼むずい
  • 参考文献がほとんどなくい

やったことは...

  • 公式リファレンスを読みます <- 英語つらい...
  • console.log で逐一データの中身を確認する

こんな牛歩戦術で RxJS を突破しました。


おそらくこんなつらいことが将来待ち受けるでしょう

  • prop 取得後の処理を Container Component に書くので、 Container Component がものすごくファットになる
  • Component が複数入れ子になっている時、双方向データバインディングでイベントを Container Component まで持っていくのはめんどくさい
  • どこからでも Observable に Push できてしまうので、テストを書くのが大変

React Redux

学習コスト度: ★★☆
ハマる度: ★★★
感動度: ★★★

「React やるなら Redux 一択でしょ!」ってことで、思考停止で Redux を始めました。笑

Redux は「Action と Reducer を state を管理してる場所に渡す」ってことなので、
登場人物は Action と Reducer ということになります。


 こんな感じでやってみました

  • Redux の Action のファイルを、バックエンドの Rails の controller の単位に合わせる
  • prop の変更はバックエンドの処理を経由して Redux の Reducer にセットさせる
  • state の変更はバックエンドの処理を経由せず Redux の Reducer にセットさせる

Action と Reducer を Rails の Controller の一部だと思うと理解は早かったと思います。


actions/daiaries.js
# バックエンドの処理を経由するAction
export function getDiaries() {
  return dispatch => {
    dispatch(getDiaryListRequest());

    Axios.get('http://127.0.0.1:9292/diaries.json').then(
      response => dispatch(getDiaryListResult(response.data))
    ).catch(
      () => dispatch(getDiaryListResult(false))
    );
  };
}

function getDiaryListRequest() {
  return {
    type: Diary.GET_LIST_AJAX_REQUEST,
  };
}

function getDiaryListResult(result) {
  return {
    type: Diary.GET_LIST_AJAX_RESULT,
    result,
  };
}

# バックエンドの処理を経由しないAction
export function selectDiary(id) {
  return {
    type: Diary.SELECT_DIARY,
    id,
  };
}
controllers/diaries_controller.rb
lass DiariesController < ApplicationController
  before_action :set_diary, only: [:show, :update, :destroy]

  def index
    @diaries = Diary.all
  end

  def show
  end

  def create
    @diary = Diary.new(diary_params)

    if @diary.save
      render :show, status: :created, location: @diary
    else
      render json: @diary.errors, status: :unprocessable_entity
    end
  end

  private
    def set_diary
      @diary = Diary.find(params[:id])
    end

    def diary_params
      params.require(:diary).permit(:title, :content)
    end
end

勉強してみて

  • Redux はめんどくさい
  • ルールがかっちりしている分、ちょっとしたことに対する手続き的なものが多い また、非同期処理をやる場合はさらに、 redux-thunk , redux-saga , redux-promise などなど学ぶことは多い

やったことは...

  • 初心者向けの日本語記事を10個ぐらい読む
  • Youtube で説明しながらコーディングしている人がいるので、それをひたすら写経 <- 英語しかないのでつらい...

Redux は RxJS とは違い、データの慣れは一方向で輪っかを描いているので、ルールがわかればそんなに苦労しないです。(理解するまで Youtube の動画10回ぐらい見ました...)


おそらくこんなつらいことが将来待ち受けるでしょう

  • どんなに小さい state の変更でも Redux のループを回さなきゃいけないので Action と Reducer が際限なく増えていく
  • 依存ライブラリーのバージョンアップ、新しいライブラリーに切り替えで動かなくなる

まとめ

  • SPA 作りたいなら Angular の方が良さそう
  • 既存フレームワークの View の部分にJSライブラリーを入れたいなら React の方が良さそう

なぜなら...

  • Angular はそれ自体で完結したフレームワーク
  • React は自分でカスタマイズしてフレームワークにする

次は、 Rails5.1 に Webpacker が標準搭載されたので、 view ライブラリーとして React を使ってみたいと思います。笑


おしまい

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up