【React 17.0.2】属性(props)と状態(state)

Reactコンポーネントでも親子関係を持つと考えられる

<Parent>
	<ChildOne />
	<ChildTwo>
		<Baby />
	</ChildTwo>
</Parent>

props: 親から子へ渡される属性値 ※子コンポーネントで変更できない
state: 子の内部状態 ※親コンポーネントから参照・変更できない
L stateが更新されるとstateを持つコンポーネントが再レンダリングされる

### props
外部から渡される属性値は、propsと呼ぶ

<Component
	string="this is string"
	number={123}
	bool={true}
	array={[9,8,7]}
	object={{ hello: 'world'}}
	func = {a=> a*2}
	variable={something}
/>

<button
	id="the-button"
	className="button is-primary"
	onClick={handleClick}
>Button</button>
<label htmlFor="the-id">Label</label>

<input
	type="text"
	id="email"
	arial-labelledby="the-label"
	aria-required="true"
/>

### イベント処理
イベントの処理は別に書く

const handleClick = () => {
	
}

const button = <button onClick={handleClick}>Click me</button>;

### カスタム属性
独自要素には自由にpropsを定義できる

<Component customProp={something} />
<Layout
	header={<Header />}
	content={<Content />}
	footer={<Footer />}
/>

<Panel narrow>...</Panel>

### state
コンポーネント内部でデータを管理したい場合は、useState関数(state)を使う
  L useStateは更新されたデータを覚えていて、2回目以降はそちらを使う

		function CountButton(){
			const countState = React.useState(0);
 
			const count = countState[0]; // 状態
			const setCount = countState[1]; // 状態を更新するための関数

			const handleClick = () => setCount(count + 1);

			return <button onClick={handleClick}>{count}</button>;
		}

		const root = document.getElementById('root');


		ReactDOM.render(<CountButton />, root);

stateによる更新の影響範囲を確認

		function Parent(){
			const [num, setNum] = React.useState(0);

			const handleClick = () => setNum(num + 1);

			return(
				<>
					<p><button onClick={handleClick}>{num}</button></p>
					<p><Child num={num} /></p>
					<p><Child num={num} /></p>
				</>
			);
		}

		function Child({ num }){
			const [myNum, setMyNum] = React.useState(0);

			const handleClick = () => setMyNum(myNum + 1);

			return (
				<button className="child" onClick={handleClick}>
					{num + myNum}
				</button>
			);
		}

### フック
フックはReactの便利な機能を導入できるヘルパー関数
useStateはフックの一つ

なるほど、propsだけでなくuseStateを使って開発していくのね。
なんとなくイメージが沸きました。

Reactとは?何のメリットがあるのか?

– ReactとはDOM操作ライブラリでコンポーネント指向の開発スタイル
– ReactのDOM操作の特徴
  L 仮想DOM(Virtual DOM)
  L データとUIの同期
– Reactは具体的なDOM操作はコーディングせず、before afterのデータを更新する
– 仮想DOMの仕組みはReactのほか、Vue.jsでも採用されている
– props(属性)やstate(状態)といったReactが管理するデータを更新する

e.g. : JSでdom操作を書く場合

<div id="root"></div>
	<script>
		const element = document.createElement('p');
		element.id = 'the-text';
		element.className = 'text';
		element.innerText = 'Hello world';
		const root = document.getElementById('root');
		root.insertAdjacentElement('beforeend', element);
	</script>

入れ子(ul,li)の場合はこう書く
L React.createElementはReact要素を返却する
  L ReactDOM.renderは、第一引数がReact要素、第二引数がReact要素を内部に描画する親要素

		const element = React.createElement('ul', {className: 'list'}, [
				React.createElement('li', {className: 'list-item'}, ['one']),
				React.createElement('li', {className: 'list-item'}, ['two']),
				React.createElement('li', {className: 'list-item'}, ['three'])
			]);

### JSXはcreateElement
CDNからBabelを読み込んだ状態でscriptのtypeにbabelを指定すると実行される
JSXの構文は機能的にはcreateElementと同一

<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
	<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
	<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

	<script type="text/babel">
		const element = <p id="the-text" className="text">Hello React</p>;
		const root = document.getElementById('root');

		ReactDOM.render(element, root);
	</script>

React.createElementの属性値をpropsと言う。第三引数は第二引数のchildrenプロパティとして渡すこともできるので、以下のようにしても同じ。ただし、視認性の問題からタグで囲むことの方が多い

const element = <p id="the-text" className="text" children="JSX & babel" />;

JSXには、単一のルート要素を持つべきというルールがあるため、複数の要素を入れる場合は、親要素としてDivタグで囲むようにする
下記の場合はdiv要素がないとエラーで実行できない

const element = (
	<div>
		<article>...</article>
		<aside>...</aside>
	</div>
);

ただし、Fragment要素を利用した方がbetter

const element = (
	<React.Fragment>
		<article>...</article>
		<aside>...</aside>
	</React.Fragment>
);
const element = (
	<>
		<article>...</article>
		<aside>...</aside>
	</>
);

### 値の埋め込み

		const name = 'john';
		const element = <p id="the-text" className="text">{name}</p>;
		const members = [
			{name: 'John', instrument: 'guitar'},
			{name: 'Paul', instrument: 'bass'},
			{name: 'George', instrument: 'guitar'},
			{name: 'Ringo', instrument: 'drums'}
		];

		const element = (
			<ul>
				{members.map(member => (
					<li key={member.name}>
						{member.name} plays {member.instrument}
					</li>
					))}
			</ul>
		);

### コンポーネントを定義
Reactでは独自要素を作ることができ、独自要素はコンポーネントと呼ばれ、関数として定義します。
関数名はネイティブと区別するため必ず大文字で始め、React要素を返却する

function Sample(props){
			return <p id={props.id} className="text">{props.children}</p>
		}

		const root = document.getElementById('root');


		ReactDOM.render(<Sample id="the-text">Props Test</Sample>, root);

DOM操作のロジック部分と、表示部分を明示的に分けて記述してるのか
なるほど、良く考えられてて面白いですね。
最初ちょっと抵抗感ありましたけど、仕組みを理解すると分かりやすいです。

Ubuntu20.04でReactの環境構築

### ubuntuにnodejs, npm, yarnをインストール
$ cat /etc/os-release
NAME=”Ubuntu”
VERSION=”20.04.3 LTS (Focal Fossa)”
$ sudo apt update
$ sudo apt install nodejs
$ nodejs -v
v10.19.0
$ sudo apt install npm
$ npm -v
6.14.4
$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add
$ echo “deb https://dl.yarnpkg.com/debian/ stable main” | sudo tee /etc/apt/sources.list.d/yarn.list
$ sudo apt install yarn
$ yarn -v
1.22.5
※yarnはrepositoryを入れないとinstallできないので注意が必要

### project作成
$ yarn create react-app hello
$ cd hello
$ yarn start

src/index.js
L 変更なし

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

src/App.js

function App() {
  return (
    <div className="App">
      <h1>Hello React!</h1>
    </div>
  );
}

export default App;

きゃー☺️

動画背景のHTML・CSSを作る

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Hpscript</title>
	<meta name="description" content="Hpscript provides comprehensive software services of full commitment to help you achieve your goals at any stage.">
	<link rel="stylesheet" type="text/css" href="css/video-styles.css">
	<link rel="shortcut icon" href="favicon.ico">
</head>
<body>
	<header id="header">
		<h1>Hpscript</h1>
		<div id="video-area">
			<video id="video" src="audio/video.mp4" webkit-playsinline playsinline muted autoplay loop></video>
		</div>
	</header>
</body>
</html>
@charset "utf-8";

#header {
	position: relative;
	height: 100vh;
}

#video-area {
	position: fixed;
	z-index: -1;
	top: 0;
	right: 0;
	left: 0;
	bottom: 0;
	overflow: hidden;
}

#video {
	position: absolute;
	z-index: -1;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 177.77777778vh;
	height: 56.25vw;
	min-height: 100%;
	min-width: 100%;
}
h1 {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translateY(-50%) translateX(-50%);
	color: #fff;
	text-shadow: 0 0 15px #666;
}
a {
	color: #fff;
}

よっしゃあ、次はreactやな

[AWS] cloudfrontとS3で静的サイトを構築する

1. ドメイン取得
2. Certified Managerでrequest(リージョンをus-east-1で取得する)
      ※regionがTokyoだとCloudfrontでCertified Managerの設定ができない
3. ドメイン管理画面のDNS設定でAWS Certified Managerで取得したCNAMEを設定する
4. S3にbucketを作成し、HTML, JS, img, cssファイルなどを保存
5. CloudFrontでcreate distribution
 L origin domainにS3を設定
 L Alternate domain name (CNAME) にドメインを指定

cloudfrontでルーティングも実装できるのね。

marguee.jsを使わずCSSで文字を動かす

HTML

<div class="video">
      <div class="narrate">
        <p class="ticker" data-duplicated='false'>The Boston Celtics have signed center Robert Williams III to a contract extension, the team announced today. </p>
      </div>
    </div>

CSS

html {
	height: 100%;
}
body {
	height: 100%;	
}
.video {
	height: 100%;
	background: url(../img/nba.jpg) no-repeat;
	background-size: 80% auto;
	background-position: center;

}
.narrate {
	position: absolute;
	bottom: 10px;	
	overflow:hidden;
}
p {
	display: inline-block;
  	color: #ffffff;
  	font-size: 36pt;
  	letter-spacing: 4px;
  	text-shadow: 
       2px  2px 0px #003366,
      -2px  2px 0px #003366,
       2px -2px 0px #003366,
      -2px -2px 0px #003366,
       2px  0px 0px #003366,
       0px  2px 0px #003366,
      -2px  0px 0px #003366,
       0px -2px 0px #003366; 
	font-size: 15px;
	animation: flowing 15s linear 1;  
	transform:translateX(100%);  
}

@keyframes flowing {
100% {
transform:translateX(-100%); 
}

jQueryのmarquee.jsを使う場合

<script
  src="https://code.jquery.com/jquery-3.6.0.min.js"
  integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
  crossorigin="anonymous"></script>
    <script src="js/marquee.js"></script>
    <script>
       $(function(){
         var $mq = $('p.ticker').marquee();

       });
    </script>

これでもmarqueeの動きはするが、margueeの文字がループ処理されるので、結局CSSを採用することに。
.bind(‘finished’, function(){} と $*.marquee(‘destroy’);で色々書いてみたんだが、どうやってもループになってしまう。

うーん 難しいね

jQueryとmarquee.jsで流れる文字を実装

githubからmarquee.jsを取得します。
jquery.marquee.js

html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- <link rel="stylesheet" type="text/css" href="styles.css"> -->
</head>
<body>
    <div>
      <p class="ticker">This demonstration shows 3 jQuerified marquees and 3 standard marquees.</p>
    </div>
    <script
  src="https://code.jquery.com/jquery-3.6.0.min.js"
  integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
  crossorigin="anonymous"></script>
    <script src="js/marquee.js"></script>
    <script>
      $(function(){
        $('p.ticker').marquee();
      });
    </script>
</body>
</html>

非常に簡単です。ajaxでjsonからテキストを取得したタイミングで実行すれば良さそうです。

Pythonでjson出力

import json

print('********** JSON **********')
data = dict()
data['message'] = 'Python json test'
data['members'] = [
	{'name': 'momo', 'color': '#FA3E05' },
	{'name': 'dubai', 'color': '#FFFFAA'}
]

print(json.dumps(data, ensure_ascii=False, indent=2))

$ python3 app.py
********** JSON **********
{
“message”: “Python json test”,
“members”: [
{
“name”: “momo”,
“color”: “#FA3E05”
},
{
“name”: “dubai”,
“color”: “#FFFFAA”
}
]
}

json.dumpsで出力できる
問題ありませんね

fetchAPI

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- <link rel="stylesheet" type="text/css" href="styles.css"> -->
</head>
<body>
  <select id="sel">
      <option> --場所を選ぶ-- </option>
      <option value="kyoto">京都</option>
      <option value="osaka">大阪</option>
      <option value="kobe">神戸</option>
  </select>

  <div id="mes">
    集合場所は<span id="pos"></span>
    集合時刻は<span id="time"></span>
  </div>
    <script>
      const url = "ajax_getData.php";
      let selid = document.getElementById('sel');

      selid.addEventListener('change', function(){
        let optval = selid.options[selid.selectedIndex].value;
        let param = new URLSearchParams();
        param.append("opt",optval);

        fetch(url, {
          method: "post",
          body: param,
        }).then(response => {
            if(response.ok){
              let promise = response.json();
              promise.then(data =>{
                document.getElementById('pos').innerHTML = data.position;
                document.getElementById('time').innerHTML = data.ap_time;
              })
            } else {
              alert("request failed");
            }
        })
      })
    </script>
</body>
</html>

なるほど。。。
ajaxの取得をtime intervalで数秒ごとに取るようにして表示すれば良いのか。
ほぼほぼロジックも出来たので背景処理のところだな

ubuntu20.04にmysql8.0をインストール

$ sudo apt update
$ sudo apt install mysql-server
$ sudo mysql –defaults-file=/etc/mysql/debian.cnf
mysql> SET GLOBAL validate_password.length=6;
mysql> SET GLOBAL validate_password.policy=LOW;
mysql> ALTER USER ‘root’@’localhost’ IDENTIFIED WITH mysql_native_password BY ‘${new password}’;
$ mysql -u root -p

create database test;
use test;
create table master_zip (
zip_code char(7) primary key,
pref_name char(5),
city_name char(10),
town_name char(20),
area_name char(20)
);
insert into master_zip values
(“1690075″,”東京都”,”新宿区”,””,”高田馬場”),
(“2130001″,”神奈川県”,”川崎市”,”高津区”,”溝の口”),
(“2470056″,”神奈川県”,”鎌倉市”,””,”大船”),
(“2500408″,”神奈川県”,”足柄下郡”,”箱根町”,”強羅”)
;
mysql> select * from master_zip;
+———-+————–+————–+———–+————–+
| zip_code | pref_name | city_name | town_name | area_name |
+———-+————–+————–+———–+————–+
| 1690075 | 東京都 | 新宿区 | | 高田馬場 |
| 2130001 | 神奈川県 | 川崎市 | 高津区 | 溝の口 |
| 2470056 | 神奈川県 | 鎌倉市 | | 大船 |
| 2500408 | 神奈川県 | 足柄下郡 | 箱根町 | 強羅 |
+———-+————–+————–+———–+————–+
4 rows in set (0.00 sec)

$ php -v
PHP 7.4.3 (cli) (built: Jul 5 2021 15:13:35) ( NTS )
$ sudo apt install php7.4-mysql
$ php -m
$ sudo vi /etc/php/7.4/cli/php.ini
$ php -S 192.168.34.10:8000

<body>
  <label>郵便番号</label>
  <input type="text" id="code">
  <div id="mes">住所:<span id="place"></span></div>

  <script
  src="https://code.jquery.com/jquery-3.6.0.min.js"
  integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
  crossorigin="anonymous"></script>
    <script>
      $(function(){
        let area;
        $('#code').on("mouseleave input",function(){
            code = $(this).val();
            $.post({
               url: 'ajax_getDBData.php',
               data: {
                  'code': code
               },
               dataType: 'json',
            }).done(function(data){
              console.log(data);
              $.each(data, function(key, item){
                area = isValue(item.pref_name) + isValue(item.city_name) + isValue(item.town_name) + isValue(item.area_name);
              })
              $("#place").text(area);
            }).fail(function(XMLHttpRequest, textStatus, errorThrown){
              alert(errorThrown);
            })
        })
        isValue = function(val){
          if(val == undefined){
            val = "";
          }
          return val;
        }
      })
    </script>
</body>

php

header("Content-Type: application/json; charset=UTF-8");
$row = array();
$data = array();
$code = func_escape(filter_input(INPUT_POST, "code"));

$dsn = "mysql:dbname=test;host=localhost";
$user = "root";
$password = "hogehoge";
try {
    $dbh = new PDO($dsn, $user, $password);
    // echo "接続";
} catch (PDOException $e){
    print('connection failed:'.$e->getMessage());
}
$sql = "select zip_code, pref_name, city_name, town_name, area_name from master_zip where zip_code = ?";
$sth = $dbh->prepare($sql);
$sth->bindValue(1,$code,PDO::PARAM_STR);
$sth->execute();
$data = $sth->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($data);
exit;

function func_escape($word){
	return htmlspecialchars($word, ENT_QUOTES);
}

パスワードの変更の箇所が躓きやすいかも