React コンポーネント

ステート

ステートの保持

※App.js
import React, {Component} from ‘react’;

class App extends Component {
 style = {
  fontSize: “20px”,
  coloer: “red”,
 }

 constructor(props){
  super(props);
  this.state = {
   msg: ‘Message from state.’,
  }
 }
 render(){
  return <div>
    <p style={this.style}>{this.state.msg}</p>
    <p style={this.style}>{this.props.msg}</p>
   </div>;
 }
}

export default App;

※index.js
import React from ‘react’;
import ReactDOM from ‘react-dom’;
import App from ‘./App’;

ReactDOM.render(
 <React.StrictMode>
  <App msg=”Message from prop” />
 </React.StrictMode>,
 document.getElementById(‘root’)
);

ステートの更新

import React, {Component} from ‘react’;
import ‘./App.css’;

class App extends Component {

 style = {
  fontSize: “20px”,
  coloer: “red”,
 }

 constructor(props){
  super();
  this.state = {
   counter: 0,
   msg: ‘count start!’,
  }
  this.doAction = this.doAction.bind(this);
 }

 doAction(e){
  this.setState((state)=>({
   counter: state.counter + 1,
   msg: `count:${state.counter}`,
  }));
 }

 render(){
  return <div>
    <p style={this.style}>{this.state.msg}</p>
    <button style={this.style} onClick={this.doAction}>Click</button>
   </div>;
 }
}

export default App;

コンテキスト

コンテキストの取得

import React, {Component} from ‘react’;

let data = {
 title: ‘Title’,
 message: ‘this is sample message’,
};

const SampleContext = React.createContext(data);

class App extends Component {
 render(){
  return <div>
   <Title />
   <Message />
  </div>
 }
}

class Title extends Component {
 static contextType = SampleContext;
 render(){
  return <div>
   {this.context.title}
  </div>
 }
}

class Message extends Component {
 static contextType = SampleContext;
 render(){
  return <div>
   {this.context.message}
  </div>
 }
}

export default App;

コンテキストの変更

import React, {Component} from ‘react’;

let data = {
 title: ‘Title’,
 message: ‘this is sample message’,
};

const SampleContext = React.createContext(data);

class App extends Component {

 newData = {
  title: ‘Title_changed’,
  message: ‘Message_changed’,
 };

 render(){
  return <div>
   <Title />
   <Message />
   ↓ の部分のみ、contextにdataではなくnewDataを使用
   <SampleContext.Provider value={this.newData}>
    <Title />
    <Message />
   </SampleContext.Provider>
   <Title />
   <Message />
  </div>
 }
}

class Title extends Component {
 static contextType = SampleContext;
 ~
}

class Message extends Component {
 static contextType = SampleContext;
 ~
}

export default App;

Hooks

useState

import React, { useState } from ‘react’

const [変数, set関数名] = useState(初期値);


const [count, setCount] = useState(0);
const [value, setValue] = useState(‘AAA’); 等

return (
 clickの度に+1された値がcountにセットされる
 <div onClick={()=>setCount(count+1)}>
  {count}
 </div>
);

useMemo

import React, { useMemo } from ‘react’

const App = () => {

 const 変数 = useMemo(() => 関数名, []);

 heavyFuncはAppを何度呼び出しても最初の1回しか実行されず、常に1回目の実行結果がキャッシュされて使用される
 const result = useMemo(() => heavyFunc(), []);

 return (
  <div>
   {result}
  </div>
 );
}

useEffect

import React, { useEffect } from ‘react’

const App = () => {
 
 レンダリング前だと要素を取得できない
 const elm = document.querySelector(‘#message’);
 console.log(elm); // null
 

 関数の実行タイミングをReactのレンダリング後まで遅らせる
 useEffect(() => {
  const elm = document.querySelector(‘#message‘);
  console.log(elm); // HTMLDivElement
  elm.innerHTML = ‘REACT’;
 });

 return <div id=”message“></div>;
}

export default App;

コンポーネント

関数コンポーネント

let dom = document.querySelector(‘#root’);

let style = {
 fontSize: “20pt”,
 color: “red”,
};

関数コンポーネントの定義
function Func(props){
 return <p style={style}>{props.content} {props.name}</p>;
}

let element = (
 <div>
  関数コンポーネントの呼び出し
  <Func content=”Function” name=”React” />
 </div>
);

ReactDOM.render(element, dom);

コンポーネントクラス

let dom = document.querySelector(‘#root’);

let style = {
 fontSize: “20pt”,
 color: “red”,
};

class Func extends React.Component {
 content = ”;
 name = ”;
 constructor(props){
  super(props);
  this.content = props.content;
  this.name = props.name;
 }
 render(){
  return <p style={style}>{this.content} {this.name}</p>;
  ↓も可
  return <p style={style}>{this.props.content} {this.props.name}</p>;
 }
}

let element = (
 <div>
  <Func content=”Function” name=”React” />
 </div>
);

ReactDOM.render(element, dom);

連携

import React, {Component} from ‘react’;

{Component}までimportしているのでReact.は省略できる
class App extends Component {
 data = [
  ”PHP”,
  ”Python”,
  ”Ruby”,
 ];
 render(){
  return <div>
   <List title=”サンプルリスト” data={this.data} />
  </div>
 }
}

class List extends Component {
 number = 1;
 render(){
  return (
   <div>
    <p>{this.props.title}</p>
    <ul>
     {this.props.data.map(
      (item)=>
       <Item number={this.number++} value={item} key={this.number} />
     )}
    </ul>
   </div>
  );
 }
}

class Item extends Component {
 render(){
  return (
   <li>
    [{this.props.number}]{this.props.value}
   </li>
  );
 }
}

export default App;

子コンポーネントのエレメントを取得

class App extends Component {
 render(){
  return <div>
   <h1>React</h1>
   <Message title=”Children”>
    1行目.2行目.3行目
   </Message>
  </div>
 }
}

class Message extends Component{
 render(){
  let content = this.props.children;
  return <div>
   {content}
  </div>
 }
}
export default App;

フォーム利用

import React, {Component} from ‘react’;

class App extends Component {
 input = ”;

 constructor(props){
  super(props);
  this.state = {
   message: ‘type your name:’
  };
  this.doChange = this.doChange.bind(this);
  this.doSubmit = this.doSubmit.bind(this);
 }

 doChange(event){
  フォームの値を取得
  this.input = event.target.value;
 }

 doSubmit(event){
  this.setState({
   message: `Hello, ${this.input}!!`
  });
  フォームデータの送信をクライアント側で止める
  event.preventDefault();
 }

 render(){
  return <div>
   <h2>{this.state.message}</h2>
   <form onSubmit={this.doSubmit}>
    <input type=”text”     
     onChange={this.doChange}
     必須属性
     required
     正規表現による入力制限
     pattern=”A-Za-z”
     最小値
     min=”10″
     最大値
     max=”100″ />
     最小文字数
     minlength=”10″
     最大文字数
     maxlength=”100″ />
    <input type=”submit” value=”Click” />
   </form>
  </div>
 }
}

export default App;

フォームの自作チェック

import React, {Component} from ‘react’;

class App extends Component {
 constructor(props){
  super(props);
  this.state = {
   message: ‘type your name:’
  };
  this.doCheck = this.doCheck.bind(this);
 }

 doCheck(event){
  alert(`${event.target.value}は入力最大文字数を超過しています(最大10文字)`);
 }

 render(){
  return <div>
   <h2>{this.state.message}</h2>
   チェックイベントに自作クラスを指定
   <Message maxlength=”10″ onCheck={this.doCheck} />
  </div>
 }
}

class Message extends Component {
 constructor(props){
  super(props);
  this.doChange = this.doChange.bind(this);
 }

 doChange(e){
  if (e.target.value.length > this.props.maxlength) {
   チェックイベントを発生させる=doCheckが実行される
   this.props.onCheck(e);
   e.target.value = e.target.value.substr(0, this.props.maxlength);
  }
 }

 render(){
  return <div>
   <input type=”text” onChange={this.doChange} />
  </div>
 }
}

export default App;

コンテキストを利用したテーマの統一

import React, {Component} from ‘react’;

let theme = {
 light: {
  backgroundColor: “pink”,
 },
 dark: {
  backgroundColor: “gray”,
 }
};

const ThemeContext = React.createContext(theme.dark);

class App extends Component {
 static contextType = ThemeContext;
 render(){
  return <div style={this.context}>
   <Title title=”Title” />
   <Message message=”Message” />
  </div>
 }
}

class Title extends Component {
 static contextType = ThemeContext;
 render(){
  return <div style={this.context}>
   {this.props.title}
  </div>
 }
}

class Message extends Component {
 static contextType = ThemeContext;
 render(){
  return <div style={this.context}>
   {this.props.message}
  </div>
 }
}

export default App;

React

前の記事

React JSX
React

次の記事

React Redux