【React】これで基礎はばっちり基礎 総まとめ

Reactとは何なのか?Reactの超基礎をまとめています。

※現在、Reactは関数コンポーネントで書くのが一般的ですが、本記事は以前の記法であるclassコンポーネントとなっております。

.jsファイルの構成

Reactのファイル.jsの構成について見てみます。

import React from 'react';         Reactをimport

class App extends React.Component {    React.Componentを継承するクラスの定義
  render() {                 JSXを戻り値とするrenderメソッドを定義
    const text = 'Hello';
    return (
      <div> { text } </div>
    );
  }
}
export default App;                    クラスをexport

  • return内をJSXで記述します。この部分がブラウザに表示されます。
  • returnの外にはJavaScriptを記述することができます。

JSX

JSXとは何か?

Reactで、見た目を作るコードを書くファイルのことです。

つまり、HTMLの役割をするものです。

JSXの特徴

render() {
  return (
    <div>
      <h1>heading</h1>
      <p>paragraph</p>
    </div>
  );
}

  • return内に複数の要素があるとエラーとなるため<div>で囲って1つの要素とする必要があります。

コメントの書き方

{/*コメント*/}

JavaScriptの場合(returnの外)
// コメント

imgタグの書き方

<img src='https://〜.jpg'/>

タグの終わりに/が必要です。

イベント

イベントの使い方を見ていきます。

<button イベント名 = { () => { 処理 } }></button>

例
<button onClick = { () => { 処理 } }></button>

処理をconsole.logとする場合
<button onClick = { () => { console.log('ボタン') } }></button>

state

Reactの最もポピュラーなhook、stateについて見ていきましょう!

stateとは、ユーザーの動きに合わせて変わる値です。

例えば、ボタンを押すとstateが変わり、表示が変更される。といった使い方をします。

constructor(props)
  super(props);
  this.state = { name: 'コーヒー' }
}
render() {
  console.log(this.state);
  return (

> { name: 'コーヒー' }

ここで定義したオブジェクト{ name: ‘コーヒー’ }が、stateの初期値です。

constructorやsuperは定型文なのでこのまま覚えましょう!

定義したstateはthis.stateで取得できます。

上記はオブジェクトを出力する方法でしたが、値を取得する場合は以下のように.nameとします。

constructor(props)
  super(props);
  this.state = { name: 'コーヒー' }
}
render() {
  return (
    <h1>朝は{this.state.name}から始まる</h1>
  );
}

指定されたプロパティに対応するstateの値を変更する

stateの値を変更するには、setStateを使います。

this.setState({プロパティ名: 変更する値})

ボタンクリックで名前の表示を変える例を見ます。

  constructor(props) {
    super(props);
    this.state = {name: 'にんじゃわんこ'};
  }
  
  render() {
    return (
    	<div>
    	  <h1>こんにちは、{this.state.name}さん!</h1>
        <button onClick={() => {this.setState({name:'ひつじ仙人'})}}>ひつじ仙人</button>
        <button onClick={() => {this.setState({name:'にんじゃわんこ'})}}>にんじゃわんこ</button>
      </div>
    );
  }

{name:’ひつじ仙人’}は切り替え表示する文字、「ひつじ仙人」はビューに表示している文字です。

メソッド化

メソッドは以下のように定義することができる。

class クラス名 {
  constructor(){

  }
  メソッド名() {
    行いたい処理
  }
}

  constructor(props) {
    super(props);
    this.state = {name: 'にんじゃわんこ'};
  }
  
  handleClick(name) {
    this.setState({name: name});
  }
  render() {
    return (
        <button onClick={() => {this.setState({name:'ひつじ仙人'})}}>ひつじ仙人</button>
        <button onClick={() => {this.setState({name:'にんじゃわんこ'})}}>にんじゃわんこ</button>
    );
  }

handleClickというメソッドを作り、その中でsetStateのnameプロパティの値を変更する処理を行います。

handleClickメソッドを呼び出すときに、引数nameに「ひつじ仙人」「にんじゃわんこ」が渡され、メソッドhandleClick(name)で、引数が以下のように変更となります。

{this.setState({name: 'ひつじ仙人'})}

↓

{this.handleClick('ひつじ仙人')}

カウントアップ機能を作る

カウントアップ機能を作ります。

stateの定義、stateの表示

constructor(props) {
  super(props);
  this.state = {count: 0};
}

render() {
  return (
    <div>
      <h1>
        {this.state.count}
      </h1>
      <button>+</button>
    </div>
  );
}

stateの変更

stateを変更し、ボタンをクリックしたときに呼び出されるメソッドを定義します。

handleClick() {
  this.setState({count: this.state.count + 1});
}

render() {
  return (
    <div>
      <h1>
        {this.state.count}
      </h1>
      <button onClick={()=>{this.handleClick()}}>+</button>
    </div>
  );
}

Reactの表示の仕組み

Reactのコードを実際にブラウザに表示するには、App.js以外にもindex.jsとindex.htmlというファイルが必要になります。

App.jsのJSXのHTMLへの変換の仕方

index.js内でindex.htmlのid=”root”を取得し、Appを渡して、App.jsが表示されている。

<!DOCTYPE html>
<html>
  <head>
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
    
    <script src="bundle.js"></script>
  </body>
</html>

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
ReactDOM.render(<App />, document.getElementById('root'));

import React from 'react';

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello World</h1>
        <p>一緒にReactを学びましょう!</p>
      </div>
    );
  }
}

export default App;

これによりHTMLに変換されています。

CSSの読み込み

index.html内でstylesheet.cssを読み込みます。

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="stylesheet.css">
    <title>React App</title>
  </head>

タグ(要素)のCSSの書き方
class App extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello World</h1>
        <p>一緒にReactを学びましょう!</p>
      </div>
    );
  }
}

h1 {
  color: red;
}
p {
  color: blue;
}

こんなふうに、普通の記法でOKです。

classのCSSの書き方
class App extends React.Component {
  render() {
    return (
      <div>
        <h1 className='title'>Hello World</h1>
        <p className='text'>Hello React</p>
      </div>
    );
  }
}

classじゃなくて、className!

.title {
  color: red;
}
.text {
  color: blue;
}

コンポーネントについて

Reactでは見た目を機能毎にコンポーネント化しています。

むしろそれこそがReact!

import React from 'react';
class Language extends React.Component {
  render() {
    return (
      JSX
    );
  }
}

コードの説明

①Reactをインポート

②React.Componentを継承するクラスを定義

③renderメソッドを定義 JSXを戻り値とする

これがコンポーネント作成の雛形!

Languageコンポーネントのブラウザでの表示の流れ

Language.js → App.js → index.js → index.html

App.jsでLanguageコンポーネントを呼び出す必要があり、

以下のようにLanguage.js内でLanguageコンポーネントをexportします。

import React from 'react';
class Language extends React.Component {
  render() {
    return (
      JSX
    );
  }
}
export default Language;

App.jsの方では、以下変更を加えます。

  • Languageコンポーネントのimport
  • JSX内に<コンポーネント/>を記述
import React from 'react';
import Language from './Language';

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello World</h1>
        <Language/>
      </div>
    );
  }
}

上記の<Language/>の数だけコンポーネントを呼び出す(表示する)ことができます。

このコンポーネントのHTML、CSSを変更していきます。

App.jsからLanguage.js(コンポーネント)にデータを渡します。

class App extends React.Component {
  render() {
    return (
      <div>
        <Language
          name = '名前'
          image = '画像'
        />
      </div>
    );
  }
}

ここで、name, imageをpropsと言いいます。

「props名=値」で、propsを渡せすことができる。

propsの受け取り

Languageコンポーネント側でpropsを受け取ります。

this.propsで受け取りができます。

class Language extends React.Component {
  render() {
    console.log( this.props );
    return (
      JSX
    );
  }
}

> 
{
  name: "名前"
  image: "画像"
}

propsの値の取得

{this.props.name}

画像の場合
<img src={this.props.image} />

上記のように、propsを使うことで、1つのコンポーネントに複数の値を入れることができます。

しかし、それらを一つずつ取得するのは大変です。

そこで、mapメソッドを使用します。

mapメソッド使用例

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>言語一覧</h1>
        <div className='language'>
          <Language 
            name='HTML & CSS'
            image='https://~'
          />
          <Language 
            name='JavaScript'
            image='https://~'
          />
          <Language 
            name='React'
            image='https://~'
          />
        </div>
      </div>
    );
  }
}

mapメソッドを使用すると、以下のように書き換えられる。

class App extends React.Component {
  render() {
    const languageList = [
      {
        name: 'HTML & CSS',
        image: 'https://~'
      },
      {
        name: 'JavaScript',
        image: 'https://~'
      },
      {
        name: 'React',
        image: 'https://~'
      }
    ];

    return (
      <div>
        <h1>言語一覧</h1>
        <div className='language'>
          {languageList.map((languageItem) => {
            return (
              <Language
                name={languageItem.name}
                image={languageItem.image}
              />
            )
          })}  
        </div>
      </div>
    );
  }
}

languageListという配列を作成し、mapメソッドを用いて1つずつオブジェクトを取り出し、Languageコンポーネントを呼び出し、その中でpropsを渡します。

propsを渡すとは、LanguageItem→languageItem.nameやlanguageItem.imageに渡すことを言います。

モーダル

モーダルの作成手順

  1. コンポーネントの中にモーダルのJSXを追加する
  2. 初期状態でモーダルを隠す
  3. モーダルの表示・非表示を設定

モーダルが表示されているかそうでないかは、stateを使って判定します。

constructorを定義し、stateを定義します。

そして、stateのプロパティ名にisModalOpenを定義し、初期値をfalseとします。

class Lesson extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isModalOpen:false}
  };

この時点ではモーダルは表示され続けています。

そのため、isModalOpenがtrueのときだけモーダルが表示されるというようにします。

① 変数modalを定義

② stateのModalがtrueのとき、変数modalに、モーダルのJSXを代入する

③ return内で、モーダルJSXを変数modalに書き換える

  render() {
    let modal;
   
    if (this.state.isModalOpen){
      modal = (
        <div className='modal'>
          <div className='modal-inner'>
            <div className='modal-header'></div>
            <div className='modal-introduction'>
              <h2>{this.props.name}</h2>
              <p>{this.props.introduction}</p>
            </div>
            <button className='modal-close-btn'>
              とじる
            </button>
          </div>
        </div>
      );
    }
    return (
      <div className='lesson-card'>
        <div className='lesson-item'>
          <p>{this.props.name}</p>
          <img src={this.props.image} />
        </div>
        {modal}
      </div>
    );
  }

ifを使って条件を付けたことで、初期状態でモーダルが隠れるようになりました。

次は、クリック時にモーダルが表示されるようにします。

① stateを変更するhandleClickLessonメソッドを定義する。

② そして、isModalOpenの値をtrueにする処理をする

③rerurn内にonClickイベントを追加し、 クリック時にhandleClickLessonを呼び出されるようにする。

class Lesson extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isModalOpen: false};
  }
  
  handleClickLesson () {
    this.setState({isModalOpen:true});
  }
  
  render() {
    let modal;
    if (this.state.isModalOpen) {
      modal = (
        <div className='modal'>
          <div className='modal-inner'>
            <div className='modal-header'></div>
            <div className='modal-introduction'>
              <h2>{this.props.name}</h2>
              <p>{this.props.introduction}</p>
            </div>
            <button className='modal-close-btn'>
              とじる
            </button>
          </div>
        </div>
      );
    }
    return (
      <div className='lesson-card'>
        <div
          className='lesson-item'
          onClick={() => {this.handleClickLesson()}}
        >
          <p>{this.props.name}</p>
          <img src={this.props.image} />
        </div>
        {modal}
      </div>
    );
  }
}

あとは、モーダルを「とじる」ボタンで閉じれるようにするだけ!

上記のモーダル表示のクリックイベントと同様に、「とじる」のクリックイベントを作成する。

class Lesson extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isModalOpen: false};
  }

  handleClickLesson() {
    this.setState({isModalOpen: true});
  }
  
  handleClickClose () {
    this.setState({isModalOpen:false});
  }

  render() {
    let modal;
    if (this.state.isModalOpen) {
      modal = (
        <div className='modal'>
          <div className='modal-inner'>
            <div className='modal-header'></div>
            <div className='modal-introduction'>
              <h2>{this.props.name}</h2>
              <p>{this.props.introduction}</p>
            </div>
            <button
              className='modal-close-btn'
              onClick={() => {this.handleClickClose()}}
            >
              とじる
            </button>
          </div>
        </div>
      );
    }

    return (
      <div className='lesson-card'>
        <div
          className='lesson-item'
          onClick={() => {this.handleClickLesson()}}
        >
          <p>{this.props.name}</p>
          <img src={this.props.image} />
        </div>
        {modal}
      </div>
    );
  }
}

お問い合わせフォームの作成

モーダルの作成ができたところで、次は、お問い合わせフォームの作成をします。

見た目(JSX)を作成

class ContactForm extends React.Component {
  render() {
    return (
      <div className='contact-form'>
        <form>
          <p>メールアドレス(必須)</p>
          <input />
          
          <p>お問い合わせ内容(必須)</p>
          <textarea />
          
          <input 
            type = 'submit'
            value = '送信'
          />
        </form>
      </div>
    );
  }
}

送信完了時に表示するメッセージを準備する

フォームが送信されたかどうかはstateで管理します。

送信されていなければstateはfalseとしたいので、初期値はfalseに設定する。

空の変数contactFormを定義し、isSubmittedで条件分岐します。

class ContactForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isSubmitted:false
    };
  }

  render() {
    let contactForm
    
    if (this.state.isSubmitted) {
      contactForm = (
        <div className='contact-submit-message'>
          送信完了
        </div>
      );
    } else {
      contactForm = (
        <form>
          <p>メールアドレス(必須)</p>
          <input />
          <p>お問い合わせ内容(必須)</p>
          <textarea />
          <input
            type='submit'
            value='送信'
          />
        </form>
      );
    }
    
    return (
      <div className='contact-form'>
        { contactForm }
      </div>
    );
  }
}

メッセージを表示する

送信されたら表示が切り替わるようにするには以下の形式で記述します。

<form onSubmit={() => {処理}}>

</form>

  handleSubmit() {
    this.setState({isSubmitted: true});
  }

  render() {
    let contactForm;
    if (this.state.isSubmitted) {
      contactForm = (
        <div className='contact-submit-message'>
          送信完了
        </div>
      );
    } else {
      contactForm = (
        <form onSubmit={() => {this.handleSubmit()}}>
          <p>メールアドレス(必須)</p>
          <input />
          <p>お問い合わせ内容(必須)</p>
          <textarea />
          <input
            type='submit'
            value='送信'
          />
        </form>
      );
    }

handleSubmitメソッドを定義して、

フォーム送信時に handleSubmitメソッド が実行されるようにonSubmitイベントを追加しました。

stateでフォームに入力された値を管理する

フォームに入力された値を、statewを使って取得します。

①stateにemailの項目を追加する。

②input タグにstateのemailを指定して表示する。

  constructor(props) {
    super(props);
    this.state = {
      isSubmitted: false,
      email:'mail@prog-8.com'
    };
  }

  handleSubmit() {
    this.setState({isSubmitted: true});
  }

  render() {
    let contactForm;
    if (this.state.isSubmitted) {
      contactForm = (
        <div className='contact-submit-message'>
          送信完了
        </div>
      );
    } else {
      contactForm = (
        <form onSubmit={() => {this.handleSubmit()}}>
          <p>メールアドレス(必須)</p>
          <input value={this.state.email} />
          <p>お問い合わせ内容(必須)</p>
          <textarea />
          <input
            type='submit'
            value='送信'
          />
        </form>
      );
    }

onChangeイベントを追加して、入力値を取得し、consoleに出力します。

          <input
            value={this.state.email}
            onChange={(event) => {console.log(event.target.value)}}
          />

inputタグのonChangeイベントで、handleEmailChangeメソッドの引数eventに値を渡し、

新たに定義したhandleEmailChangeというメソッドで、stateのemailを更新します。


  handleEmailChange(event) {
    const inputValue = event.target.value;
    this.setState({email:inputValue})
  }

  handleSubmit() {
    this.setState({isSubmitted: true});
  }

  render() {
    let contactForm;
    if (this.state.isSubmitted) {
      contactForm = (
        <div className='contact-submit-message'>
          送信完了
        </div>
      );
    } else {
      contactForm = (
        <form onSubmit={() => {this.handleSubmit()}}>
          <p>メールアドレス(必須)</p>
          <input
            value={this.state.email}
            onChange={(event) => {this.handleEmailChange(event)}}
          />
          <p>お問い合わせ内容(必須)</p>
          <textarea />
          <input
            type='submit'
            value='送信'
          />
        </form>
      );
    }

フォーム入力エラーメッセージを表示する

hasEmailErrorというstateを初期値falseで定義します。

emailErrorText変数を定義し、hasEmailErrorの値によってエラーメッセージの表示・非表示を切り替える条件式を設定します。

  constructor(props) {
    super(props);
    this.state = {
      isSubmitted: false,
      email: '',
      hasEmailError: false
    };
  }

  handleEmailChange(event) {
    const inputValue = event.target.value;
    this.setState({email: inputValue});
  }

  handleSubmit() {
    this.setState({isSubmitted: true});
  }

  render() {
    let emailErrorText
    
    if (this.state.hasEmailError) {
      emailErrorText = (
        <p className='contact-message-error'>
          メールアドレスを入力してください
        </p>
      );
    }

    let contactForm;
    if (this.state.isSubmitted) {
      contactForm = (
        <div className='contact-submit-message'>
          送信完了
        </div>
      );
    } else {
      contactForm = (
        <form onSubmit={() => {this.handleSubmit()}}>
          <p>メールアドレス(必須)</p>
          <input
            value={this.state.email}
            onChange={(event) => {this.handleEmailChange(event)}}
          />
          {emailErrorText}
          
          <p>お問い合わせ内容(必須)</p>
          <textarea />
          <input
            type='submit'
            value='送信'
          />
        </form>
      );
    }

class ContactForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isSubmitted: false,
      email: '',
      hasEmailError: false,
    };
  }

  handleEmailChange(event) {
    const inputValue = event.target.value;
    /* 定数isEmptyを定義し、入力チェックの結果を代入 */
    const isEmpty = inputValue === ''
    
    /* setStateを使ってemailとhasEmailErrorを一緒に更新 */
    this.setState({
      email: inputValue,
      hasEmailError: isEmpty
    });
    
  }

以上で、お問い合わせフォームを作成することができました!

お読みいただきありがとうございました。

コメント