1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Reactを学ぶ

Posted at

Reactを動かす

<!DOCTYPE html>
<html>
<head>
 <script src="/libs/react.development.js"></script>
 <script src="/libs/react-dom.development.js"></script>
 <script src="/libs/babel-standalone.js"></script>
</head>
<body>
    <div id="app"></div>
    <script type="text/babel">
     // jsでタグは読み込まれないので、javascriptのオブジェクトに変換する際にバベルを使ってjavascriptのコードを変換して使用
     const appEl = document.querySelector('#app');
     const root =ReactDOM.createRoot(appEl);
     
     root.render(<h1>こんにちは</h1>);//jsx構文
     //予期せぬ文字列となっている:jsで読み込まれない。
     // v18以降はroot.renderが推奨
     // 下記は非推奨
     // ReactDOM.render(<h1>こんにちは</h1>,appEl);
    </script>
</body>
</html>

コンポーネント:
画面の各構成要素をReactで定義したもの

・再利用の向上
・可読性の向上
・疎結合になる(バグの減少)

コンポーネントはJSの関数定義

function Welcome(){
return <h1>Hello</h1>;
}

<Welcome />

<!DOCTYPE html>
<html>
<head>
   <script src="/libs/react.development.js"></script>
   <script src="/libs/react-dom.development.js"></script>
   <script src="/libs/babel-standalone.js"></script>
</head>
<body>
    <div id="app"></div>
    <script type="text/babel">
        const appEl = document.querySelector('#app');
        const root = ReactDOM.createRoot(appEl);
        function Example(){//必ず関数の頭は大文字、小文字だとhtmlのタグと認識される。
         return <h1>Hello Components</h1>; //関数コンポーネント
        }


        // const Example2 =() =>{
        //  return <h1>Hello Components2</h1>
        // }

         // 1行の時
         const Example2 =() => <h1>Hello Components2</h1>
         //複数行の時
        const Example3 =() =>{
        return (
         <div>
          <h1>Hello Components2</h1>
         </div>
        )
        }
        //下記でもOK,{}なしでもreturn のみなので不要
         const Example4 =() => (
         <div>
          <h1>Hello Components2</h1>
         </div>
         )
               
        const a =() =>{
         return   //何も続けなかった場合にjavascriptエンジンが "return undefined;"のセミコロンが代入されているのと同じことになり、undefineとなり、実行文章が終えることと同じ意味になるため、改行と同じ意味になります。
         // 複数行である場合には()をつけるようにする。
          "戻り値";
        }
        console.log(a())
        root.render(<Example2 />);
    </script>
</body>
</html>

React 立ち上げ

# プロジェクトの作成方法
npx create-react-app {プロジェクト名}

# create-react-appドキュメント
npm docs create-react-app

Windowsの方でエラーが発生する方は以下のコマンドを実行してみてください。

```powershell
Set-ExecutionPolicy RemoteSigned

その他

Vite というモジュールバンドラーを使ったプロジェクトの作成
最近は一般的

npm create vite@latest
  "scripts": {
    "start": "react-scripts start",
//開発時に使うコマンドでサーバーを立ち上げアプリを使う
    "build": "react-scripts build",
//本番環境用にビルドするコマンド
    "test": "react-scripts test",
//テストスクリプトを実行するようのコマンド
    "eject": "react-scripts eject"
//隠しファイルを表示する用のコマンド
  },


  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
//コードチェック
    "preview": "vite preview"
  },

React スタイル

import "./Example.css";

class MyClass{}//<<JSでは左のように使うため混同しないように



const Example = () => {
  return (
   <div className="component">
    {/* classではなくclassNmae */}
      <h3>Hello Component</h3>
    </div>
  );
};

export default Example;
.App-start .component{
 padding:1rem;
 color:red;

 border:5px solid green
}

/* cssはグローバルになるため、CSSを当てる際には注意が必要 */

パーツを分割


import Child from "./component/Child";
// .jsはどちらでも良いwebpackが勝手に解釈してくれる

import Child from "./components/Child"
const Example = () => <Child />;

export default Example;

const Child = () => { 
 return (
  <div className="component">
   <h3>Child Component</h3>
  </div>
 );
}
 
//コンポーネントは一つのファイルに一つのコンポーネントが普通
//export default でOK
export default Child 

フラグメント

import "./Child.css";
// import React from "react"  //どちらでも良い
//この場合には<React.Fragment>で囲む



import { Fragment } from "react";  //どちらでも良い
const Child = () => {
 return (
  // ルート要素として一つのルートで囲む必要がある。
  // divなど不要なタグで囲まないようにするためにFragmentを使う
  //fragmentは属性をつけることができない
  <Fragment key="">
   {/* キー属性はつけることが可能、ただし、Fragmentのキーワードは省略不可 */}
   {/* <>でOK */}
   <div className="component">
    <h3>Hello Component</h3>
   </div>
   <h3>Hello Fragment</h3>
   <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati repellat dolor doloribus iure consequatur soluta? Optio corrupti ratione suscipit recusandae eius perspiciatis illo corporis? Aliquam nam repellendus quos expedita est?</p>
  </Fragment>
 );
};

export default Child;

ReactのJS実行

JSのコード内では波括弧を使ってJAVASCRIPTの指揮を評価してその結果を画面上に表示する。

import "./Expression.css"

const Expression = () => {
 const title = "Expression";
 const arry = ['item1', 'item2', 'item3'];
 const hello = (arg) => `${arg} function`; //`${arg}`:テンプレートリテラル
 const jsx = <h3>Helloe JSX</h3>;//Javascriptのオブジェクトとして使われる。
 const bool = true;
 return (
  <div className={title.toLowerCase()}>
   {/* タイトルを使って小文字表示 メソッドも実行可能*/}
   <h3>Hello {title}</h3>
   <h3>Hello {arry}</h3>
   {/* 配列の場合自動的に展開されて表示する */}
   <h3>{hello('Hello')}</h3>
   <h3>{/* 画面上に表示されません。 */}</h3>
   {<h3>Helloe JSX</h3>} 
   {/*これも JS コード 最終的にJSのオブジェクトに変換される。 */}
   {bool} 
   {/* boolearnは表示されない。 */}
  </div>
 );
 //jsのコードを埋め込むことができる。式を埋め込み可能
}
 


export default Expression;

式と文

JSX内では式しか使うことができない。
式:何らかの値を返すもの(変数に代入できるもの)
文:変数宣言、for文、if文、switch文やセミコロンで区切るもの。

import "./Child.css";

const Child = () => {
 const fn = () => 'hello';
 const a =if (true) { 'hello' };//NG
 // if文自体は変数に代入できないものなので文となる。
 const f = fn();
 //関数を実行した結果はhelloという値を返す式となりますので、この関数の実行結果は式
 const c = 1 === 1;
 //式 左オペランドと右オペラんどが等しい場合にはtrue/falseを返す式となります。
 //ただし、表示はされない
 const b = 1;
 // const b = 1;は文になる。
 // 1というのは1という値を返す式、変数に代入できる。
 1;//式にも文にもなりえる 式ぶん

 if (true) { 'hello' };
 // ここでif文はOK
  return (
    <div className="component">
    <h3>式と文</h3>
    {1 === 1} 
    {/* 非表示い */}
    {true ? 'hello' : 'bye'}
    {/* OK */}
    {if (true) {'hello'};}
    {/* NG  for も同様 return内で使わなければOK */}
    </div>
  );
};

export default Child;
const title = 'Expression';
const array = ['item1', 'item2', 'item3'];
const fn = (arg) => {
  return `${arg} Function`;
};
const upperCaseText = 'upperCaseText';

const Example = () => {
  return (
    <>
      <h3>Hello JSX</h3>
      {/* toUpperCaseメソッドで文字列をすべて大文字にします。 */}
      <h3>{upperCaseText.toUpperCase()}</h3>
      {/* +演算子で文字列を結合します。 */}
      <h3>{'Hello ' + title}</h3>
      {/* 配列がJSX内で渡されると自動的に要素が展開されて表示されます。 */}
      <h3>{array}</h3>
      {/* 関数の実行はreturnに続く値が返ってきます。 */}
      <h3>{fn('Hello')}</h3>
    </>
  );
};

export default Example;

props

import Child from "./components/Child";

const Example = () => {
 return (
  <>
  <Child  />
  <Child color="red" />
  </>

)};
// 属性を指定して値を渡すことが可能
export default Example;
import "./Child.css";
// 外部から値を渡して再利用性を
// const Child = (props) => {
 // propsである必要なし pでも慣習的に暗黙ルール
 
 // 分割代入する場合
const Child = ({ color:c = 'green' }) => {
 // green:初期値設定
 // color:c colorの値をcとして置き換えて使う
 console.log()
 return (
   <>
   <div className={`component  ${c}`}>
      <h3>Hello Component</h3>
    </div>
   </>
  );
};

export default Child;

Props2

import Child from "./components/Child";

const Example = () => {
 const hello = (arg) => `ello ${arg}`;
 const o = {
  color: "red",
  num:123,
 }
 return (
  <>
   {/* <Child /> */}
   {/* <Child color="red" /> →エラー*/}
   {/* 下記でfnを渡すように定義されていることから、呼び出す際にpropsとして関数を渡していないのでfnはundefinedとなり、fn is not a functionとなる */}
   <Child
    {...o}
    // スプレッド演算子でオブジェクトの値が展開される。
    // num={123}
    fn={hello}
    bool
    obj={{ name:'Tom',age:18 }}
    // trueの値が渡ってくる
   />
   {/* 属性が定義されていない分についてはundefinedとなる。 */}
  </>

 )
};
// 属性を指定して値を渡すことが可能
export default Example;


/* POINT 式と文
式:何らかの値を返すもの(変数に代入できるもの)
文:変数宣言、for文、if文、switch文やセミコロンで区切るもの。
*/

import "./Child.css";
// 外部から値を渡して再利用性を
// const Child = (props) => {
 // propsである必要なし pでも慣習的に暗黙ルール
 
 // 分割代入する場合
// const Child = (props) => {
 // console.log(props)
const Child = ({ color:c = 'green',num, fn,bool,obj }) => {
 // green:初期値設定
 // color:c colorの値をcとして置き換えて使う
 console.log();
 return (
   <>
   <div className={`component  ${c}`}>
      <h3>Hello Component</h3>
      <h3>{num}</h3>
      <h3>{fn('Props')}</h3>
      <h3>{bool ? 'true' :'false'}</h3>
      <h3>{obj.name + obj.age}</h3>
    </div>
   </>
  );
};

export default Child;

チルドレン

import Profile from "./components/Profile";
import Container from "./components/Container";

const profile = [
  { name: "Takashi", age: 19, country: "Japan", color: "green" },
  { name: "Jane", age: 28, country: "UK", color: "red" },
];

const Example = () => {
  return (
    <div>
    <Container title="Childrenとは?" >
     <Profile {...profile[0]} />
    </Container>
    </div>
  );
};

const Example2 = () => {
 return (
  <div>
   <Container title="Childrenとは?" children={
    [<Profile key={profile[0].name} {...profile[0]} />,
     <Profile key={profile[1].name} {...profile[1]} />]
   } first={<Profile key={profile[0].name} {...profile[0]} />}
    second={<Profile key={profile[1].name} {...profile[1]} />}
   />
    {/* 上記の表現でも問題なし、このコンポーネント自体もjavascriptのオブジェクトになりますので、この列に格納することができます。 */}

  </div>
 );
};

export default Example2;


propsのルール

// POINT propsの流れは一方通行 親から子へ
// POINT propsは読み取り専用

import Bye from "./components/Bye"
import Hello from "./components/Hello"

const Example = () => {
 const name = "Tom";
  return (
    <>
    <Hello name={ name } />
    <Bye name={name } />
    </>
  );
};

export default Example;

const Hello = (props) => {
 // props.name = 'BOb';// エラー読み取り専用props

 const desc = Reflect.getOwnPropertyDescriptor(props, 'name');
 console.log(desc);
 // configurable:false;変更できるか?できない
 // writable:false;書き換え可能か?不可
  return (
    <div>
      <h3>Hello {props.name}</h3>
    </div>
  );
};

export default Hello;
const Bye = (props) => {
 const name = 'Tom';
 // Helloへは渡せない
 // 親コンポーネント
  return (
    <div>
      <h3>Bye {props.name}</h3>
    </div>
  );
};

export default Bye;

jsxの正体

babelにて関数に置き換えられ、オブジェクトになる。

JSXはJSのオブジェクトに変換される。
JSオブジェクト(React要素)

  const sample2 = (
    <div>
      <h1>Hello!</h1>
      <h2>Good to see you.</h2>
    </div>
  );

Babel変換

  const sample2 =React.createElement(
    "div",//タグ名
   null,// プロップスの値
   React.createElement("h1", null, "Hello!"),
    
    React.createElement("h2", null, "Good to see you.")
  );

実行結果

const element ={
 type:'h1',
 props:{
  className:'greeting',
  children:'Hello World'
}
};

開発で利用するイベントについて

const Example = () => {
 const clickHandler = () => {
  alert('ボタンがクリックされrました。');
  // 戻り値returnがないのでundefinedの戻り値が返ってくる。
 }
 // 極力名前付き関数を定義してから下記に入力
 
 const hello = () => 'hello react';
 console.log(hello)
 // () => 'hello react'がそのまま表示される。
 console.log(hello());
 // hello reactが表示される。

 return (
   <>
   <button onClick={clickHandler}>クリックしてね</button>
    {/* onClickのCは大文字 */}
   {/* clickHander()(関数を実行したもの)と()をつけるわけではなくclickHandler(ボタンを押されて実行するもの)として記載する。 */}
   <button onClick={() => clickHandler()}>クリックしてね</button>
   {/* 上記の場合には関数の実効記載が必要。クリックされてから関数が実行するため、実行されたreturnには()を付けないと関数が戻り値となってしまう。 */}
   <button>クリックしてね</button>
   {hello()}
   </>
  );
};

export default Example;
import "./Example.css";

const Example = () => {
  return (
    <div>
      <h3>コンソールを確認してください。</h3>
      <label>
        入力値のイベント:
        <input
          type="text"
      onInput={() => console.log("onChange検知")}
      //JSにおけるonInputがReactのonChangeイベントと同じ(変更された時に発火する)ようになる
      // 通常JSではonchangeイベントは入力を終えてフォーカスが外れた時に動作する。
      onBlur={() => console.log("onBlur検知")}
      // 入力欄からフォーカスが消えた時を検知
      onFocus={() => console.log("onFocus検知")}
      // 入力欄からフォーカスを得た時を検知
        />
      </label>
      <div>
        <label>
          入力値を取得:
          <input type="text" onChange={(e) => console.log(e.target.value)} />
        </label>
    </div>
    {/* マウスホバー時を検知 */}
      <div
     className="hover-event"
     
     onInput={() => console.log("カーソルが入ってきました。")}
     onChange={() => console.log("カーソルが入ってきました。")}
        onMouseEnter={() => console.log("カーソルが入ってきました。")}
        onMouseLeave={() => console.log("カーソルが出ていきました。")}
    >

        ホバーしてね!
      </div>
    </div>
  );
};

export default Example;

useState

import { useState } from "react";
const Example = () => {
 let valArry = useState("hello");
 let [val, setVal] = useState('hello');
 // [0,f]
 //配列の0番目に参照用の値が渡ってきます。
 // 配列の0番目:参照用の値
 // 配列の1番目:更新用の関数
 // 初期値0
 // 読み込み用と
 console.log(valArry)

 return (
  <>
   <input
    type="text"
    onChange={(e) => {
     // const setFn = valArry[1];
     setVal(e.target.value)
     // 更新されない
    }} /> = {val}
  </>
 );
};

export default Example;

変数の値を変えても画面の表示は変わらない理由
・Reactにコンポーネントの再実行(再レンダリング)を依頼し、新しいReact要素を作成してもらう必要がある。
・変更した値をどこかに保持しておく必要がある。(stateに保存)
これらを可能にする仕組みが useState

import { useState } from "react";

const Example = () => {
 let displayVal;
 //2. Exampleが実行されるたびに値が空になってしまう。
  let [ val, setVal ] = useState();
  console.log('再レンダリングされました');
  return (
    <>
      <input
        type="text"
        onChange={(e) => {
          console.log(e.target.value);
          setVal(e.target.value);
          //1. displayVal = e.target.value; onChangeにおってコードが実行される
         }}
      />
    = {val}{/* このコードはExample()が実行されないと変わらない/3.さらにExampleが実行されると2の挙動で空が反映される。 */}
    </>
  );
};

export default Example;

1.接続hook Into
React内部と接続。状態が管理されるようになる。
2現在の値と更新関数を返却
3.更新関数で新しい値をReactに渡す。また、Reactに自身のコンポーネントを再実行するように依頼する。

useStateはコンポーネントごとに保持

import { useState } from "react";

const Example = () => {
 let displayVal;
 //2. Exampleが実行されるたびに値が空になってしまう。
  let [ val, setVal ] = useState();
  console.log('再レンダリングされました');
  return (
    <>
      <input
        type="text"
        onChange={(e) => {
          console.log(e.target.value);
          setVal(e.target.value);
          //1. displayVal = e.target.value; onChangeにおってコードが実行される
         }}
      />
    = {val}{/* このコードはExample()が実行されないと変わらない/3.さらにExampleが実行されると2の挙動で空が反映される。 */}
    </>
  );
};

export default Example;
import { useState } from "react";

const Example = () => {
 // let displayVal;
 //2. Exampleが実行されるたびに値が空になってしまう。
  let [ val, setVal ] = useState();
  console.log('再レンダリングされました');
  return (
    <>
      <input
        type="text"
        onChange={(e) => {
          console.log(e.target.value);
          // displayVal =e.target.value
          setVal(e.target.value);
          //1. displayVal = e.target.value; onChangeにおってコードが実行される
         }}
      />
    {/* = {displayVal} */}
    {/* Stateを利用しないと再レンダリングされない */}
    = {val}
    {/* このコードはExample()が実行されないと変わらない/3.さらにExampleが実行されると2の挙動で空が反映される。 */}
    </>
  );
};

export default Example;```

```jsx
import { useState } from "react";
const Example = () => {
 console.log(<Example />)
 // _owner FiberNode
 // memorizedStateにて値が保持される。
 // 次の値はnextに入っている。
 const [btnValA, setValA] = useState(0);
 // コンポーネントのトップレベルしか呼ぶことができないuseState
 // if,for,whileなど{}文内においても使用できない。
 // setValAの関数と紐付けされたbtnValAが更新される
 const [btnValB, setValB] = useState(10);
 // 順番で定義されたもの保持されるuseState
 const [ btnValC, setValC ] = useState(100);
 
 const btnCountUp = () => { 
   setValA(btnValA + 1);
 }
 const btnCountUpB = () => { 
   setValB(btnValA + 1);//更新されない
 }
 const btnCountUpC = () => { 
   setValC(btnValC + 1);
 }

 return (
  <>
   <p>ボタンAを{btnValA}回押しました!</p>
   <button onClick={btnCountUp}>ボタンA</button>
   <p>ボタンBを{btnValB}回押しました!</p>
   <button onClick={btnCountUpB}>ボタンB</button>
   <p>ボタンAを{btnValC}回押しました!</p>
   <button onClick={btnCountUpC}>ボタンA</button>
  </>
 );
};

export default Example;


import { useState } from "react";

const Example = () => {
 const [count, setCount] = useState(0);
 const countUp = () => {
  setCount(count + 1);//:値は1//非同期処理となる。
  setCount(count + 1);//:値は1
  setCount(p => p + 100);//:値は101 関数の引数は前の関数の結果
  setCount(p => p + 1);//:値は1
  console.log(count);
 }
 const countDown = () => {
  setCount(count - 1);
  
 }
 return (<>
  <p>現在のカウント数:{count}</p>
  <button onClick={(countUp)}>+</button>
  <button onClick={(countDown)}>-</button>
 </>);
  
};

export default Example;

useStateの注意点

useStateの関数については予約という考え方のため、
即時処理が行われない。
そのため、関数の実行する際に現在の状況を反映させたい場合には、
set関数内に関数を設置することで値を引用して更新される。

import { useState } from 'react';

const Example = () => {
  const [count, setCount] = useState(0);
  
  const countUp = () => {
   setCount(state => state + 1);
   // 現在の値を見て行う場合が多いので常時上記の使い方で実施
  };

  const countDown = () => {
    setCount(state => state - 1);
  };
  return (
    <>
      <h3>練習問題</h3>
      <p>現在のカウント数: {count}</p>
      <button onClick={countUp}>+</button>
      <button onClick={countDown}>-</button>
    </>
  );
};

export default Example;

オブジェクト型のuseStateの注意点

// POINT プリミティブ型:1, "str", bool, 10n, Symbol(), null, undefined
// POINT オブジェクト型:{}, []などのプリミティブ型以外
// POINT オブジェクト型のstateを変更する場合には必ず新しいオブジェクトを作成する!

import { useState } from "react";

const Example = () => {
 const personObj = { name: "Tom", age: 18 };
 const [person, setPerson] = useState(personObj);
 const changeName = (e) => { 
  setPerson({ name: e.target.value, age: person.age });
  // setPerson({ name: e.target.value, age: person.age });
  // ageプロパティを消してしまうと更新されてしまうので、setPersonを実行する際には必ず同じ構造で記載すること。
  }
 const changeAge = (e) => { 
  setPerson({ name: person.name, age:e.target.value });

 }
 const reset = () => { 
  setPerson({ name: "", age: "" });
  }
 return (
  <>
   <h3>Name:{person.name}</h3>
   <h3>Age:{person.age}</h3>
   <input type="text" name="" onChange={changeName} id="" value={person.name} />
   <input type="number" name="" onChange={changeAge} id="" value={person.age} />
   <div>
    <button onClick={reset}>リセット</button>
   </div>
  </>

 );
};

export default Example;

オブジェクトのuseStateについて

import { useState } from 'react';

const Example = () => {
  const orderObj = { item: 'apple', count: 10 };
  const [order, setOrder] = useState(orderObj);
 const changeItem = (e) => { setOrder({ ...order, item: e.target.value }) };
 // スプレッド演算子で展開
 const countUp = () => {
  setOrder((order) => ({ ...order, count: order.count + 1 }));
  // 配列に()をつけるのは配列がオブジェクトリテラルなのか、あろー関数の関数式か不明であるため、オブジェクトを返す場合には()入れる。
  };
 const countDown = () => {
  setOrder((order) => ({ ...order, count: order.count - 1 }));
  };
  return (
    <div>
      <h3>練習問題</h3>
      <p>
        記述を変更し、完成コードのように「+と-ボタンをクリックするとCountの表示が1ずつ増減する機能」と「input要素に連動してItemの表示が変更される機能」を実装してください。コンポーネントの外側(上部)に変数や関数を準備しているためうまく使ってください。
      </p>
    <h3>Item:{order.item}</h3>
      <h3>Count:{order.count}</h3>
      <input type="text" value={order.item} onChange={changeItem} />
      <button onClick={countUp}>+</button>
      <button onClick={countDown}>-</button>
    </div>
  );
};

export default Example;

配列のuseState

import {useState} from "react"
const Example = () => {
  const numArray = [1, 2, 3, 4, 5];
 const [nums, setNums] = useState(numArray);
 console.log(nums);
 const shuffle = () => {
  const newNums = [...nums];
  // スプレッド演算子として定義する。新しい配列として定義する。
  // newNums =numsは配列がコピーではなく、配列の参照をコピーしている。
  const value = newNums.pop();
  newNums.unshift(value);
  setNums(newNums);
  // 配列の末尾が削除
  console.log(newNums)
 }
  return (
    <>
    <h1>{nums}</h1>
    {/* {}で展開されると並んで表示される。 */}
    <button onClick={shuffle}>shuffle</button>
    </>
  );
};

export default Example;

State

State はコンポーネント毎に保持

コンポーネントに紐づく値はそれぞれ独立して管理される。

React要素のツリー内の位置によってどのコンポーネントのstateか識別している。

コンポーネントのReact要素ツリーにおける位置が変わらない場合はstateは保持される。
しかし、keyをつけることによって同じ位置の同じコンポーネントでも別物と認識させられる。

import { useState } from "react";
const Example = () => {

 const [toggle, setToggle] = useState(true);
 const toggleComponent = () => { 
  setToggle(prev => !prev)
  }
 return (
  <>
   <button onClick={toggleComponent}>toggle</button>
   {toggle ? <Count title="A" /> : <Count title="B" />} 
   {/* 上記の内容では表示位置が変わらない */}
   {/* stateの値を引き継ぐ、同じ位置で切り替わる場合について */}
   {toggle ? <Count title="A" /> : <div><Count title="B" /></div>}
   {/* 上記の場合にはdivがBに追加されているためツリー構造が変わることから値が引き継がれない */}
   <Count title="A" />
   {toggle && <Count title="B" />}
   {/* 上記の場合にはコンポーネントが消滅するため、値が初期化される。 */}
   {toggle ? <Count key="A" title="A" /> : <Count key="B" title="B" />} 
   {/* 上記のコンポーネントが値を別々にしたい場合にはkeyという属性を設定することで、一意のコンポーネントの値を管理できる。 */}
  </>
 )
}
const Count = ({ title }) => {
  const [count, setCount] = useState(0);
  const countUp = () => {
    setCount((prevstate) => prevstate + 1);
  };
 const countDown = () => {
    setCount(count - 1);
  };
  return (
    <>
      <h3>{title}: {count}</h3>
      <button onClick={countUp}>+</button>
      <button onClick={countDown}>-</button>
    </>
  );
};

export default Example;

stateをpropsで渡すケース

・コンポーネントが消滅する可能性がある時
・特定のstateを複数の子コンポーネントで共有したいとき

import { useState } from "react";

const Example = () => {
 const [toggle, setToggle] = useState(true);
 const [countA, setCountA] = useState(0);
 const [countB, setCountB] = useState(0);
  const toggleComponent = () => {
    setToggle(prev => !prev);
  }
  return (
    <>
    <button onClick={toggleComponent}>toggle</button>
    {/* {toggle ? <Count key="A" title="A" count={count} setCount={setCount} /> : <Count key="B" title="B" count={count} setCount={setCount} />} */}
    {/* 定義したSTATEをpropsで渡す(値を共有する) */}
     <Count key="A" title="A" count={countA} setCount={setCountA} /> 
     <Count key="B" title="B" count={countB} setCount={setCountB} />
    </>
  )
}
const Count = ({ title,count,setCount }) => {
  
  const countUp = () => {
    setCount((prevstate) => prevstate + 1);
  };
  const countDown = () => {
    setCount(count - 1);
  };
  return (
    <>
      <h3>{title}: {count}</h3>
      <button onClick={countUp}>+</button>
      <button onClick={countDown}>-</button>
    </>
  );
};

export default Example;

useState:値と際レンダリングを依頼

・コンポーネントの中で呼び出す。

・if文やfor文の中で呼び出さない

・値の更新と再レンダリングは予約(非同期される)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?