Reactを利用する上で押さえておくと良い基本要素について取り上げます。Vue.jsなどの経験者がReactの公式ドキュメントを一通り読んだあと、Reactの基礎内容を振り返るための内容です。
Hello World
まずは、少ない実装でReactの動作確認をします。id属性がrootの要素内に Hello World
と表示されるように実装します。
public/index.html
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="root"></div>
</body>
</html>
src/App.js
import React from 'react'
function App() {
return (
<div>
<p>
Hello World
</p>
</div>
)
}
export default App
src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App/>, document.getElementById('root'))
ReactDOM.renderでDOMにReact要素を反映してます。
実行結果です。
JSX
BabelでJavaScript構文にコンパイル
JSXはJavaScriptの拡張言語です。以下のようにBabelでJavaScript構文にコンパイルできます。
npm install --save-dev babel-cli babel-preset-react
$ cat app.jsx
<div><p>Hello World</p></div>
$
$
$ ./node_modules/.bin/babel --presets=react app.jsx
React.createElement(
"div",
null,
React.createElement(
"p",
null,
"Hello World"
)
);
JSXはHTMLのように記述でき、直接JavaScriptで記述するより理解しやすいため利用されます。
{}で式の埋め込み
{}
内にJavaScriptの式を記述できます。
const App = () => {
const sum = (a, b) => a + b
return (
<div>
<p>{sum(3, 4)}</p>
</div>
)
}
XSS対策として、デフォルトでHTMLタグをエスケープしてくれます。
className, on[Event]
JavaScriptの予約語とかぶる属性はそのまま利用できません。
例えば、class
は className
と指定します。
React.Fragment
returnする際、1つのタグにまとめる必要がありますが、divでまとめると余計なdivタグが追加されてしまいます。
const App = () => {
return (
<div>
<p>aaa</p>
<p>bbb</p>
</div>
)
}
React.Fragmentを利用すると余計なタグが追加されません。
<React.Fragment></React.Fragment>
または、 <></>
で囲みます。
const App = () => {
return (
<>
<p>aaa</p>
<p>bbb</p>
</>
)
}
参考
- https://reactjs.org/docs/glossary.html#jsx
- https://reactjs.org/docs/introducing-jsx.html
- https://reactjs.org/docs/react-api.html#createelement
- https://reactjs.org/docs/dom-elements.html#differences-in-attributes
- https://reactjs.org/docs/react-api.html#reactfragment
コンポーネント
クラス or 関数
関数コンポーネント
import React from 'react'
const App = props => {
return (
<div>
<p>
{props.message}
</p>
</div>
)
}
export default App
クラスコンポーネント
import React from 'react'
class App extends React.Component {
render() {
return (
<div>
<p>
{this.props.message}
</p>
</div>
)
}
}
export default App
関数コンポーネントでは、クラスコンポーネントが持つ ライフサイクルメソッド
state
などの機能を実装できませんでした。React16.8で追加された Hooks を利用すれば、関数コンポーネントでもクラスコンポーネントと同様に実装することができます。
コンポーネントの設計の考え方としては、状態を持たない純粋関数で作られたコンポーネントをなるべく多く作り、それらをimportして利用する方式が良いです。テストしやすく、再利用性が高まります。
ライフサイクル
コンポーネントのライフサイクルの特定タイミングで処理を差し込むことができます。
import React from 'react'
class App extends React.Component {
constructor(props) {
super(props)
}
componentDidMount() {
// コンポーネント生成時
}
componentDidUpdate() {
// コンポーネント更新時
}
componentWillUnmount() {
// コンポーネント削除時
}
render() {
return (
<div>
<p>Hello world</p>
</div>
)
}
}
export default App
参考
- https://reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class
- https://reactjs.org/docs/react-component.html#the-component-lifecycle
- http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
state|コンポーネントの状態
import React from 'react'
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
items: Array(9).fill(0),
}
}
handleClickItem(index) {
const items = this.state.items.slice()
items[index]++
this.setState({ items: items })
}
handleResetItems() {
this.setState({ items: Array(9).fill(0) })
}
render() {
const items = this.state.items.map((item, index) => {
return (
<li
key={index}
onClick={() => this.handleClickItem(index)}
>
{`Button${index}: ${item}`}
</li>
)
})
return (
<div>
<ul>{items}</ul>
<div onClick={this.handleResetItems.bind(this)}>Reset items</div>
</div>
)
}
}
export default App
実行イメージです。
状態を変更させるにはsetState
を利用します。renderメソッド
が再度呼び出されます。
関数が this.props
this.state
などのコンポーネント属性にアクセスできるようにするには、以下のような対応が必要です。
onClick={() => this.handleClickItem(index)}
のようにアロー関数を利用する- アロー関数を利用すると1つ上のthisと同じスコープになってくれる
onClick={this.handleResetItems.bind(this)}
のようにbind関数を利用する
https://reactjs.org/docs/faq-functions.html にて解説されています。
参考
props|読み取り専用
import React from 'react'
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
message: 'Hello',
flg: true
}
}
handleClick = () => {
this.setState({ flg: !this.state.flg })
}
render() {
return (
<div>
{this.state.flg && <p>aaaaa</p>}
<Child
message={this.state.message}
handleClick={this.handleClick}
/>
</div>
)
}
}
const Child = (props) => (
<div>
<p>{props.message}</p>
<div onClick={props.handleClick}>Click</div>
</div>
)
export default App
親コンポーネントから props
を経由してデータを渡せます。子コンポーネントで発生したイベントに応じて、親コンポーネントの状態を変更したい場合、状態を変更するコールバックを props
経由で渡します。
参考
- https://reactjs.org/docs/components-and-props.html
- https://reactjs.org/docs/thinking-in-react.html#step-5-add-inverse-data-flow
Developer Tools
開発時に役立つツールです。