React.jsはFacebook社が開発したJavaScriptのフレームワークでモダンなアプリケーションの一部分に使うとレンダリング周りでスムーズで拡張性の高いプロダクトが開発できると2015年頃から注目されている。ブラウザで表示するView周りでその効力を発揮するのだが、そのReact.jsでよくあるエラーとその解決方法についてまとめていきます。
このページの目次
React.createElement: type should not be null, undefined, boolean, or number.
React.jsでは下記のようにReactコンポーネントを記述することができる。しかし、これを書いてもエラーが起きてしまった場合は、どうすればいいのか。
import React, { Component, PropTypes } from 'react'; import { Link } from 'react-router' import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { increment } from '../actions/app'; import styles from '../main.css'; import App from '../components/app'; /// この辺りにCSS等の記述がある export default class TopContainer extends Component{ render(){ console.log("render top") return( <div> <Link to="/">トップページ</Link> <App /> </div> ); } };
<code><div></code>
で囲んでいるのは、JSXでコンパイルする時に2つ以上のコンポーネントを返せないため。仮に囲まないと、Adjacent JSX elements must be wrapped in an enclosing tagという例外が出る。
直接コンポーネントに渡してもいいが、それだと融通が利かないことも多い。なのでContainersを経由して、各ContainersのjsからさらにComponentの各部品を呼び出すという仕組みにしている。
<Route path="/" component="App"> <IndexRoute component="Home"> <Route path="home" component="Home"/> <Route path="profile" component="Profile"/> </Route>
https://github.com/reactjs/react-router/issues/2220
React.js+reduxでmetaをどのように入れればいいのか
react.jsを使った場合、初期に何も設定をしなければ、index.htmlが最初に読み込まれることになります。
そこで静的にデフォルトファイルに書いてしまうと、動的にCSSやJavaScript、TitleタグやDescriptionの変更を行うことができません。現代のウェブアプリケーションでSEO対策をしていないアプリケーションをスケールさせることは難しいでしょう。この辺りは基本的な事項として取り組んでおかなければなりませんので、ぜひreact-helmetを使ってみてください。
react-helmetの記述例
その場合に、react-helmetモジュールを使って下記のように記述します。
<Helmet htmlAttributes={{"lang": "ja", "amp": undefined}} // amp takes no value title="Bitcoin ウォレット" titleTemplate= "%s" defaultTitle={baseTitle} base={{"target": "_blank", "href": url}} meta={[ {"name": "description", "content": description}, {"property": "og:type", "content": "article"} ]} link={[ {"rel": "canonical", "href": url}, {"rel": "apple-touch-icon", "href": "http://mysite.com/img/apple-touch-icon-57x57.png"}, {"rel": "apple-touch-icon", "sizes": "72x72", "href": "http://mysite.com/img/apple-touch-icon-72x72.png"} ]} script={[ // {"src": "http://include.com/pathtojs.js", "type": "text/javascript"}, {"type": "application/ld+json", innerHTML: `{ "@context": "http://schema.org" }`} ]} />
https://github.com/nfl/react-helmet#server-usage
React.jsでrouterが効かず任意のURLに遷移できない場合
下記のようにセキュリティのエラーが出ている場合か、普通に記述方法がまちがっている場合があります。
https://twinery.org/forum/discussion/4747/uncaught-securityerror-failed-to-execute-replacestate-on-history
Helmetを使っている場合に限りますが、urlを開発しているurlと同じ設定にしていないと動かない事があります。Helmetにそういう副作用があるとは…。Helmetはmetaの内容を記述しているモジュールだったので、Helmetのurlを開発環境用のURLに変更して解決しました。
import Helmet from "react-helmet";
// urlの環境が現在動いている開発環境のURLとことなると今回のエラーが発生する const url = "http://localhost:8080"; const description = "このサービスの説明です。"; const baseTitle = "タイトルタグに入る想定";
そのほかでRouter周りで動かない場合はこの辺りもチェックしてみてはいかがでしょうか。
https://github.com/reactjs/react-router/issues/224
reduxを試してみた(4日目) – redux-react-routerを試す by @kompiro on @Qiita http://qiita.com/kompiro/items/de10197368f864c2e846
React.jsでthisがnullにケース
何かbuttonなどを押した時の処理を追加するというケースで、thisがnullになってしまいpropsがエラーになってしまうケースがあります。これはES6を使用している場合です。
<button className="btn" onClick={this.onClose}> Close </button>
Uncaught TypeError: Cannot read property 'props' of null
こういう場合に幾つかの解決策がありますが、bindしてthisを送る必要があります。
// 解決策1 <button className="btn" onClick={this.onClose.bind(this)}> Close </button> // 解決策2 constructor() { super(); this.onClose = this.onClose.bind(this); } return { <button className="btn" onClick={this.onClose}> Close </button> }
モダンな書き方だと下記のようになりますが、ES7の書き方なので、まだ仕様が変更される可能性があるために上記の書き方で解決しています。また、こちらの書き方だとwebstormでエラーが起きてしまうようです。基本的なところですが、なぜnullになるのか注意が必要です。
<button className="btn" onClick={::this.onClose}> Close </button>
RplayではReact.jsでのリプレイス・一部サービスを開発しています。
引き続きReact.jsについての情報を掲載していきます。
プログラミング学習で詰まった場合
プログラミングでエラー文言をみて自分で修正してみたもののわからないということもあるかと思います。会社であれば近くの先輩などに聞くこともできますが、独学している場合などは困ってしまいますよね。そういう時にプログラミングやデザインなどの質問に答えてくれるサービスをまとめておきましたので、困っている方はこちらを確認してみてください。
Reactの構文チェックにはairbnbのJavaScriptのスタイルガイドがオススメです。最近開発者の中で人気になってきてるので、Rplayでも導入してみました。その時に1から導入したときのまとめです。