20200706のReactに関する記事は6件です。

忙しい人のreactルーティング

reactに手を出したけどサクッと見つからなかったので
やり方だけ秒殺で知りたい時向け

npx使ってプロジェクト作る方向

npx create-react-app sukina-project-name

出来たフォルダに入ってreact-route-domを入れる

cd sukina-project-name
npm install react-route-dom

/todo というURLを指定した時に表示したいページを(srcに)作成

src/todo.js
import React,{ Component } from 'react'

export default class Todo extends Component {
    render(){
        return (
            <div>
                <input type="text" />
                <ul>
                    {[ '1' , '2' , '3' , 'daaa' ].map(  x => <li> {x}</li>)}
                </ul>
            </div>
        )
    }
}

/todo で表示するコンポーネントをapp.jsに指定

app.js
import React from 'react';
import './App.css';

 // react-routerの読み込みと /todoで表示するコンポーネントの読み込みを追加
 import { BrowserRouter as Router , Route } from 'react-router-dom'
 import Todo from './todo'

 function App() {
   return (
    // /todoではTodo.jsの内容を描画すると指定する
     <Router>
       <Route path="/todo"><Todo /></Route>
     </Router>
   );
 }

 export default App; 

起動

npm start

/todo にアクセス

image.png

todo.jsの内容が表示される

image.png

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

React hooks で複数のcheckboxを実装してみる

useStateとuseEffectを使って複数のcheckboxを実装してみる

いろいろ手探りで書いてみたのでメモに残しておく。

仕様について

  • チェックボックスが一つ以上checkedになった場合のみ送信ボタンを表示させたい。
  • checkedアイテムのidを、送信ボタンが押されたタイミングで配列で送信したい。
checkBox.jsx
import React, { useState, useEffect } from "react"

//checkboxのvalueリスト
const checkLists = [
  "パン",
  "おにぎり",
  "焼き肉",
  "ラーメン",
  "たこ焼き",
  "アイスクリーム",
]

//checkboxコンポーネント
const CheckBox = ({id, value, checked, onChange}) => {
  return (
    <input
      id={id}
      type="checkbox"
      name="inputNames"
      checked={checked}
      onChange={onChange}
      value={value}
    />
  )
}

const CheckBoxList = () => {

//checkedItemsは初期値を空のオブジェクトにする
  const [checkedItems, setCheckedItems] = useState({})
//ひとつでもcheckedになっている場合にのみ送信ボタンを表示させたいので、全体のStateを監視する
  const [isBtnHide, setIsBtnHide] = useState(true)

  useEffect(() => {
//checkedItemsが空では無い場合、送信ボタンを表示させる
    Object.keys(checkedItems).length && setIsBtnHide(false)
//すべてのcheckedItemの値がfalseの場合に送信ボタンを表示させる
    setTimeout(() => {
      if (
        Object.values(checkedItems).every(checkedItem => {
          return checkedItem === false
        })
      ) {
        setIsBtnHide(true)
      }
    },100);
  }, [checkedItems])

  const handleChange = e => {
//checkedItemsのstateをセット
    setCheckedItems({
      ...checkedItems,
      [e.target.id]: e.target.checked
    })
    console.log('checkedItems:', checkedItems)
  }

  const dataSendBtn = e => {
//既定のイベントをキャンセルさせる
    e.preventDefault()
//送信ボタンを押したタイミングで、checkedItemsオブジェクトのvalueがtrueのkeyのみを配列にしてconsoleに表示させる
    const dataPushArray = []
    for (let [key, value] of Object.entries(checkedItems)) {
      if (value) {
        dataPushArray.push(key)
      }
    }
    console.log("dataPushArray:", dataPushArray)
  }

  return (
    <>
      <h2>好きな食べ物</h2>
      <form>
        {checkLists.map((item, index) => {
          index = index + 1
          return (
            <label htmlFor={`id_${index}`} key={`key_${index}`}>
              <CheckBox
                id={`id_${index}`}
                value={item}
                onChange={handleChange}
                checked={checkedItems[item.id]}
              />
              {item}
            </label>
          )
        })}
{/* checkedがない場合には送信ボタンを表示させない */}
        {!isBtnHide && <button onClick={dataSendBtn}>アンケート送信ボタン</button>}
      </form>
    </>
  )
}

export default CheckBoxList


とりあえず意図した通りの動きになった。
でもなんか遠回りしている気がする。。。。

new Map()での実装

 const [ischecked, toggleChecked] = useState(new Map())

Mapはstateを更新するため(再レンダーをトリガーする)に、Mapをnew Mapに置き換える必要がある。

const handleChange = e => {
  checkedItems.set(e.target.id, e.target.checked)
  setCheckedItems(new Map(checkedItems) );
  console.log("checkedItems: ", checkedItems);
}

もっと良い方法はないか、いろいろ考えてみる、追記していく :relieved:

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

Gatsby + Contentful カテゴリーから記事を表示する

やりたいこと

サイドバーにカテゴリー一覧を表示している。
表示されているカテゴリを選択した際に、カテゴリに紐づく記事を表示したい

サイドバーは下記
カテゴリーを全て取得して表示しているだけです

components/Sidebar.js
import React from "react"
import { Container, Row, Nav } from "react-bootstrap"
import { useStaticQuery, Link, graphql } from "gatsby"

import Styles from "./sidebar.module.css"

const Sidebar = () => {
  const data = useStaticQuery(graphql`
    query {
      allContentfulCategory {
        edges {
          node {
            title
            slug
            id
            createdJP: createdAt(formatString: "Y年MM月DD日")
          }
        }
      }
    }
  `)

  const categories = data.allContentfulCategory.edges
  return (
    <div className={Styles.sidebar}>
      <Row>
        <div className="col-lg-12">
          <div className={Styles.sidebar_item}>
            <div className={Styles.sidebar_heading}>
              <h2>Categories</h2>
            </div>
            <div className="content">
              <Nav className={Styles.categories}>
                {categories.map(({ node }) => (
                  <Nav.Link
                    key={node.id}
                    as={Link}
                    to={`/category/${node.slug}`}
                  >
                    {node.title}
                  </Nav.Link>
                ))}
              </Nav>
            </div>
          </div>
        </div>
      </Row>
    </div>
  )
}

export default Sidebar

やりかた

gatsby-node.jsで各投稿ページのように、カテゴリ別を作成してやる

1.カテゴリごとのページを作成

const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions

  // 使うテンプレのパス
  const categoryTemplate = path.resolve(`./src/templates/category.js`)
  const result = await graphql(
    `
      {
        allContentfulCategory {
          edges {
            node {
              slug
              id
            }
          }
        }
      }
    `
  )

  if (result.errors) {
    throw result.errors
  }

  const categories = result.data.allContentfulCategory.edges

  categories.forEach(category => {
    createPage({
      path: `category/${category.node.slug}`,
      component: categoryTemplate,
      context: {
        id: category.node.id,
        slug: category.node.slug,
      },
    })
  })
}

カテゴリごとのページのテンプレート作成

const categoryTemplate = path.resolve(./src/templates/category.js)で記述したように
カテゴリの個別ページのテンプレートを作成する

今回は/src/templates/category.jsで作成
あとは、個別投稿と同じようになる

GraphQLでidと一致するカテゴリを取得し、それに紐づくblogpostをループして表示

import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout"

const Category = ({ data }) => {
  const category = data.contentfulCategory
  const posts = data.contentfulCategory.blogpost

  return (
    <Layout>
      <h1 className="p-3">{category.title}</h1>
      {posts.map(post => {
        return (
          <div> {post.title}</div>
        )
      })}
    </Layout>
  )
}

export default Category

export const pageQuery = graphql`
  query($id: String!) {
    contentfulCategory(id: { eq: $id }) {
      id
      slug
      title
      blogpost {
        id
        slug
        title
      }
    }
  }
`
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gatsbyでサイドバーに最近の投稿を表示する

やりたいこと

componentsディレクトリ内は下記のようになっている

  • components
    • Layout
    • Sidebar
    • BlogCard

Layoutにはサイドバーが組み込まれています

components/Layout
const Layout = ({ children }) => {
  return (
    <div>
      <Header />
      <section style={{ marginTop: "9rem" }}>
        <Container>
          <div className="row">
            <div className="col-lg-8">{children}</div>
            <div className="col-lg-4">
              <Sidebar />
            </div>
          </div>
        </Container>
      </section>
      <Footer />
    </div>
  )
}
index.js
<Layout>
      {posts.map(({ node }) => {
        return (
          <BlogCard
            key={node.id}
            title={title}
            readMore={node.slug}
          />
        )
      })}
</Layout>

indexから記事を指定数切り出して渡す事もできますが
引数やら責務範囲やらややこしいのでやりたくなかった

やりかた

useStaticQueryを使う

https://www.gatsbyjs.org/docs/use-static-query/

公式の通りインポート

import { useStaticQuery, graphql } from "gatsby"

あとは、const data = useStaticQuery(graphql)として、普通にGraphQLを書いていく
最近の投稿なので、日付でソートして、指定数取得するようにします

サイドバーは下記の様になった

components/Sidebar.js
import React from "react"
import { Container, Row1 Nav } from "react-bootstrap"
import { useStaticQuery, Link, graphql } from "gatsby"

import Styles from "./sidebar.module.css"

const Sidebar = () => {
  const data = useStaticQuery(graphql`
    query {
      allContentfulBlogPost(
        sort: { fields: [publishDate], order: DESC }
        limit: 5
      ) {
        edges {
          node {
            id
            slug
            title
            publishedDateJP: publishDate(formatString: "Y年MM月DD日")
          }
        }
      }
    }
  `)

  const posts = data.allContentfulBlogPost.edges
  return (
    <div className={Styles.sidebar}>
      <Row>
        <div className="col-lg-12">
          <div className={Styles.sidebar_item + " " + Styles.recent_posts}>
            <div className={Styles.sidebar_heading}>
              <h2>Recent Posts</h2>
            </div>
            <div className="content">
              <Nav>
                {posts.map(({ node }) => (
                  <Nav.Link as={Link} to={`post/${node.slug}`}>
                    <h5 className={Styles.head}>{node.title}</h5>
                    <span className={Styles.date}>{node.publishedDateJP}</span>
                  </Nav.Link>
                ))}
              </Nav>
            </div>
          </div>
        </div>
      </Row>
    </div>
  )
}

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

古いReactベースのWebアプリも完全にリファクタリング

この記事では、数ヶ月前のReactベースのWebアプリをリファクタリングして完全に書き換える方法と理由を共有します。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

image.png

私たちはミスをしがちです。そのため、作業の見直し、再編成、見直しが必要になることがよくあります。ソフトウェアエンジニアリングでは、このフェーズをリファクタリングと呼びます。

リファクタリングには価値があります。ソフトウェアを健全な状態に保つことができるからです。これはAoneに現れるような特別なタスクではありません。上手くやれば、プログラミング活動の定期的な一部になります。

リファクタが完全なリライトになる場合

新しいプロジェクトや新しい開発スプリントを開始するときはいつも、最新かつ最高の技術やソフトウェアのデザインスキームを使用します。しかし、しばらくすると、新しい技術や新しい設計手法が出てきます。コアとなるコードベースの設計は、変更のしやすさに大きな違いをもたらします。拡張機能は多くの場合、作成時には意味のある方法で重ねて適用されますが、後になって、さらなる変更や機能、改善を開発するのがますます難しくなります。

私たちのチームの最初のReactプロジェクトは、2018年後半にアルファ版として開発されましたが、現在(2019年初頭)は、高い要求に応えるために、新しい機能、より多くのメンテナンス、より良いパフォーマンスを必要としています。

まず私たちのコアコードベースを改善する必要がありました。

"Embrace change" === "Re-write a five months old app"
  • 依存関係の自由 - 依存関係をよりコントロールできるようにするために、Next.js から独自の configure 環境に移行しました。
  • 懸念事項の分離 - 単一の責任という観点から、重要な機能(ルーティングなど)をReactから分離しました。
  • 誇大広告の背後を見る - みんなが使っているものを自動的に使うのをやめて、自分たちに合ったものを検討し始めました。
  • npmインストール時間 - いくつかの簡単な質問に基づいて、プロジェクトに注入する依存関係を選択します。最初に自問したのは、「自分たちで実装するにはどれくらいの時間がかかるのか」ということでした。
  • 変化を受け入れる - コードと依存関係を定期的に更新し、リファクタリングします。
  • パフォーマンスのコツ - このリファクタリングの段階では、アプリのパフォーマンスとユーザーエクスペリエンスも大幅に改善されました。

プロローグ

今回関係するReactプロジェクトはHyperMLと呼ばれるものです。

HyperMLは、研究者や開発者を念頭に置いて設計された継続的な研究プラットフォームです。これは、研究者や開発者が(ディープラーニングのトレーニングのような)計算量の多いタスクをクラウドGPU上で最小限のオーバーヘッドで合理化された方法でWebインターフェースを介して実行できるようにするためのものです。

依存性の自由

image.png

HyperMLは、チームの最初のReactアプリとして2018年に構築された、それを持っています。最良の方法は、最も早く、最適な設定のジャンプスタートを見つけること、そして、展開のためのマインドセットを持つことが重要であることに変わりはありませんでした。

"開発者の経験とエンドユーザーのパフォーマンスの両方に恍惚としているので、コミュニティで共有することにしました。" - Next.js

それは完璧に聞こえましたが、その後、私たちはそのSSRを使用していませんでした。私たちはより多くのコントロール、より多くの柔軟性を必要としていました、そして正直に言うと、私たちはこの "ブラックボックス "に快適さを感じませんでした。Creat-React-App は良い代替手段ですが、それでも私たちの問題は解決されませんでした。

偶然にも、JetpackはGithubのトレンドにちょうどヒットしました(JetpackはWebpackの周りの薄いラッパーであり、Webpackの設定のいずれかで拡張することができます) - それは私たちに完全にフィットします。基本的な最良の構成と、それを好きなように拡張する方法を提供してくれました。

懸念事項の分離

image.png

Next.js関連のコードとその依存関係をすべて削除したので、ルーティングを処理する別の方法を見つけなければなりませんでした - 今回はRouter5 JSを選択しました。react-routerはReactアプリのためのコミュニティで好まれているルーティングパッケージですが、Router5はより成熟しており、安定しており、私たちの「懸念の分離」という設計原則に適合しているように思えました。

Router5 (React プラグイン付き) は、React からルーティングを分離し、遅延ロードのようなものを処理するためにコアの React 関数を使用することを可能にしてくれました。その方法は以下の通りです。

[Root page]
import React, { Suspense } from 'react';

import Loading from 'components/loading';
import TopBar from 'components/top_bar';

// Common
const NotFound = React.lazy(() => import('pages/404'));
//...

// HyperML
const HomePage = React.lazy(() => import('pages/hyperml_pages/home_page'));
const JobView = React.lazy(() => import('pages/hyperml_pages/job_view'));
//...

// AutoML
//...

class Root extends React.Component {

    //...

  getContent = () => {
    switch (route) {
      case 'home_page':
        return <HomePage />;
      case 'job':
        return <JobView />;
      //...
      default:
        return <NotFound />;

    }
  };

  render() {
    return (
      <Layout className="layout">
        <Layout.Header>
          <TopBar />
        </Layout.Header>
        <Layout.Content>
          <Suspense fallback={<Loading />}>
            <div>{this.getContent()}</div>
          </Suspense>
        </Layout.Content>
        <Layout.Footer>
          Alibaba ©2019 Created by IMVL
        </Layout.Footer>
      </Layout>
    );
  }

}

//...

誇大広告の先を見る

image.png

自分に合ったものを選ぶ

HyperMLはチーム初のReactアプリでしたが、それだけではありませんでした。

アプリの状態を管理するために他の可能性のある方法を探っていくうちに、正しい方法は一つではないことがわかりました。

しかし、1つだけはっきりしていたことは、サードパーティのパッケージを使用する必要がない限り、サードパーティのパッケージを使用しないことです。Reactのデフォルトの状態管理は、正しく使えば素晴らしいものですが、私たちはReduxを状態管理に使っている "古い "プロジェクトを書き換えているので、できるだけデフォルトに近い状態を維持しつつ、"Reduxのやり方 "を維持する方法を探し始めました。

このMediumの記事(新しいコンテキストAPIの上に構築された状態管理を実装する新しいライブラリ)を見つけ、そのスマートでわかりやすいソースコードを調べた後、"npm install react-waterfall -save "を選択しました。

最終的には、より管理しやすく、より明確なコードになり、おまけとして、Redux で使用しなければならなかったすべてのパッケージを手放すことができました。

[Jobs Store]
import { setData, mergeData } from './utils';

const initialState = {
  jobs: {},
  lastActivity: {},
};

function updateJob(state, callback, newJob) {
  const { lastActivity } = state;
  if (lastActivity[newJob.ID]) lastActivity[newJob.ID] = newJob;
  return {
    jobs: {
      ...state.jobs,
      [newJob.ID]: newJob,
    },
    lastActivity,
  };
}

function deleteJob(state, callback, jobID) {
  const jobs = Object.assign({}, state.jobs);
  const lastActivity = Object.assign({}, state.lastActivity);
  delete jobs[jobID];
  delete lastActivity[jobID];
  return { jobs, lastActivity };
}

const actionsCreators = {
  setLastActivity: setData('lastActivity'),
  setJobs: setData('jobs'),
  mergeJobs: mergeData('jobs'),
  updateJob,
  deleteJob,
};

export default { initialState, actionsCreators };
[Projects Store]
import { setData, mergeData, addData } from './utils';

const initialState = {
  projects: {},
};

const actionsCreators = {
  setProjects: setData('projects'),
  mergeProjects: mergeData('projects'),
  updateProject: addData('projects'),
};

export default { initialState, actionsCreators };
[Index Store]
import createStore from 'react-waterfall';

import mergeStores from './utils';
import jobs from './jobs';
import projects from './projects';

export const { Provider, connect, actions } = createStore(mergeStores([
  jobs,
  projects,
]));
[Connect to react]
//...

import { Provider as StoreProvider } from 'store';
import Root from 'pages';


const App = () => (
  <StoreProvider>
    <Root />
  </StoreProvider>
);

[Use "action" anywhere]
//...

import { actions } from 'store';
actions.deleteJob(jobID);

[Connect to component]
//...
import { connect } from 'store';

const Activity = ({ lastActivity }) => (
  <Card>
      <JobsList jobs={lastActivity} />
  </Card>
);

Activity.propTypes = {
  lastActivity: PropTypes.arrayOf(PropTypes.shape()),
};

export default connect(({ lastActivity }) => ({ lastActivity }))(Activity);

npm インストール時間

プロジェクトの依存関係をコントロールできるようになってからは、何を追加するかをより賢く選択できるようになりました。私たちは特定の目標を達成するためにこのリファクタリングを計画しました。

プロジェクトの依存関係を大幅に減らしたことで、開発の進捗の中で最も時間のかかる部分であるデザインに役立つ重要なライブラリを追加することができました。

CSSコードの記述とメンテナンスには驚くほどの時間がかかっていましたが、Ant-Designを使用することでHyperMLのUIが改善され、ユーザーの体験が向上しただけでなく、新機能の開発にかかる時間が大幅に短縮され、より良いコードを書くための時間を確保することができました。

変化を受け入れる

React v16.8:Hooksを導入したもの

2019年2月にReact v16.8が "Hooks "を導入して登場しました。

"一晩でHooksを使うために既存のアプリケーションを書き換えることはお勧めしません。"と彼らはその日のうちに書いていました。

しかし、変化を受け入れることは私たちの文化の中にあります。現在のコードを改善していく中で、クラスのコンポーネントを関数に置き換えたり、新しいコンポーネントをHooksで書いたり、独自のHooksを構築したりするようになりました。

振り返ってみると、それは私たちがHooksをよく理解するのに役立ち、それをよく理解することで、私たちはコーディング時間を大幅に改善することができました。50個以上のコンポーネントを書き換えなければ、それは達成できませんでした。

フロントエンドパフォーマンスソリューション

アプリのパフォーマンスを向上させるには、サーバー側のコードを修正する必要があるかもしれませんが、サーバーのバックログにタスクが多すぎる場合は、フロントエンドで解決策を考える必要があります。ここでは、サーバー側で変更を加えることなくアプリのパフォーマンスを向上させた2つの方法を紹介します。

image.png

フロントエンドページング

アプリのページの一部にはジョブのリストが含まれており、これらのリストは大きくなることがあります。これらのリストは大きくなる可能性があります。広範なリストをレンダリングすることは、ほとんどのブラウザにとって複雑な作業であり、アプリのパフォーマンスだけでなく、ユーザーエクスペリエンスにも影響を与えます(ブラウザがリストのレンダリングを終えるまで真っ黒な白いページに直面する)。

この問題に対処するために、ページング機構を開発する必要があります。通常、これはサーバー側で行うものですが、主な問題はDOMにデータをレンダリングすることであり、サーバーからデータを取得することではないので、フロントエンドで開発することができます。

そのために、このパッケージでは react-infinite-scroller を使うことにしました。

[Jobs list]
//...
import InfiniteScroll from 'react-infinite-scroller';

import { connect } from 'store';
import JobItem from './item';


const JobsList = ({ jobs }) => {
  const [numOfJobsToShow, setNumOfJobsToShow] = useState(10);

  const jobsInView = useMemo(() => jobs.slice(0, numOfJobsToShow), [jobs, numOfJobsToShow]);

  return (
    <InfiniteScroll
      pageStart={0}
      loadMore={() => setNumOfJobsToShow(showingJobs => showingJobs + 10)}
      hasMore={numOfJobsToShow < jobs.length}
      loader={<Spin />}
    >
      {jobsInView.map(job => <JobItem job={job} />)}
    </InfiniteScroll>
  );
};

JobsList.propTypes = {
  jobs: PropTypes.arrayOf(PropTypes.shape()),
};

ローカルストレージに状態を保存

パフォーマンスとユーザーエクスペリエンスを向上させるもう一つの方法は、特に遅いインターネット接続がある場合に、ブラウザがデータをフェッチするのを「助ける」ことです。

私たちは、アプリのデータストアをブラウザのローカルストレージに保存することでこれを実現しました。この方法では、ユーザーは次回アプリにアクセスしたときに(サーバーからの)データを待つ必要がありません。

この方法には1つの欠点があります。それは、変更があるたびにローカルストレージにデータを書き込むことによるパフォーマンスへの影響です。これを克服するために、このタスクにはWeb Workerを使用して、バックグラウンドスレッドで実行するようにしています。

[Index Store]
import createStore from 'react-waterfall';

import mergeStores from './utils';
import jobs from './jobs';
import projects from './projects';
import { importLocalStore } from './localStore';
const localStorage = require('workerize-loader!./localStore')(); // ** Web Worker **

export const { Provider, connect, actions, subscribe } = createStore(mergeStores([
  jobs,
  projects,
]));

importLocalStore(actions);

subscribe((action, state) => localStorage.update(state));
[localStore.js]
// Runs on Web Worker
export function update(state) {
  Object.keys(state).forEach(key => localStorage.setItem(key, state[key]));
}

// Runs on main thread
export function importLocalStore(actions) {
  localStorage.getItem('jobs').then(jobs => actions.mergeJobs(jobs || {}));
  localStorage.getItem('projects').then(projects => actions.mergeProjects(projects || {}));
}

ボーナスのヒント

HyperMLに画像を追加することで、アプリがより使いやすくなり、作業ツールを楽しくするちょっとしたおまけを与えてくれることがわかりました。Undrawは定期的に更新される美しいSVG画像のオープンソースのコレクションで、完全に無料で帰属表示なしで使用することができます。

ボーナスヒントII

ESlintは、より良いコードを書くことを強制することで、チームのdevスキルを向上させます。プロジェクトでの使用を検討してみてください。

概要

数ヶ月前のアプリを書き換えるのは無駄に思えるかもしれませんが、コードのメンテナンス、新機能の追加、新しいプロジェクトの開発にかかる時間を考えれば、このリアクターが時間の適切な使い方であるだけでなく、必要な作業であることは明らかです。

私たちは、最初にいくつかの部分を書き換え、他の部分はマイナーチェンジを加えたままにして、少しずつ始めました。約2週間後には、完全に刷新された作業版のウェブアプリが完成しました。今では、このリファクタリングのおかげで、それ以降に開発した新機能ごとに何時間もの作業時間を節約できたと推定しています。

私たちの経験を共有し、時々リファクタリングをしてコードを更新することを奨励することは、私たちにとって不可欠でした。

例えば、コードベースが膨大で、長い間改訂が行われていない場合など、私たちの推奨を行うことが難しい場合があることを想定しています。しかし、その場合はもっと重要なことがあるかもしれません。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

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

[React] 本番環境でのみ画面が真っ白になる場合

概要

開発環境だと問題なく動作するのに、本番環境だと画面が真っ白になる現象が発生。

開発環境で発生していたWarningを全て解決してもダメ。

解決に1時間以上かかったのに、結果として大したことない理由だったので、共有したいと思いました...。

現象

作成したページにアクセスすると画面が真っ白....。

たまたま、ブラウザの開発者コンソールを確認したら、javascriptのエラーが出ていた!

内容は Minified React error #152;

原因

react の return メソッドの中で、javascript のコメント記法である // を使用していると、難読化の過程でソースが壊れてしまうことが判明。

Hoge.js
// 例

render() {
  // renderの中でこのコメントの書き方をしているとエラーになる
}

対策

ここに書いてある通りで、

Github issue Minified React error #152 - comments before JSX #8687

return メソッドの引数内の、 // によって生成しているコメントを削除すると解決する。

わかりやすいのはここ

感想

React初心者向けの本に書いてあると良さそうと感じました。

特に、元々 return 内に書いていなかったけれども、ソースの移動とかをしているうちに return メソッド内に紛れ込んでしまう、ということは普通にありそう。

この書き方 /* コメント */ だとエラー発生しないという記載もあるので、全部こっちの書き方に移行すればいいかもしれない。

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