🙆

React学習記録 #2

2023/12/31に公開

初めに

今回はReactのコードとその結果について書いていきます!

この記事はjavascript(以下js)についての基礎知識を有する方に向けたものとなります。

参考にしたサイトは以下の通りです
https://ja.react.dev/learn/describing-the-ui
https://ja.react.dev/learn/adding-interactivity

実行環境:

windows11 , typescript使用、Next.js, VSCode
(ブラウザや、htmlファイルに記述する方は環境は影響しないと思います)

UIの記述

React公式ドキュメントにあるProfileコンポーネントと、レンダーするコンポーネント内に
<h1>Amazing scientists</h1>
<Profile />
と記述します。
以下はexport ~ { ~ } と書いてある部分以外に記述します

function Profile() {
return (
<img
src="https://i.imgur.com/MK3eW3As.jpg"
alt="Katherine Johnson"
/>
);
}

結果としては以下のようになります。保存するだけでwebページが変更されるので便利ですね!

以上のように、一つのファイル内に多くのコンポーネントを宣言すると、ファイルが煩雑になり、コードの可読性が落ちるので、別ファイルにコンポーネントを記述し、それをモジュールとして外部から参照できるようにし、exportするファイル内で呼び出すことにします。

例えば、私の場合には、以下のように記述します。

page.tsx
import Profile from './component'
export default function Home() {
  return (
  <h1>Amazing scientists</h1>
      <Profile />
    </div>
    </main>
  )
}
component.tsx
export default function Profile() {
    return (
      <img
        src = "https://i.imgur.com/MK3eW3As.jpg"
        alt = "Kaherine Johnson"
      />
    );
  }

先ほどと見た目は変わらないですね!このようにして、コンポーネントをファイルごとに書くことができました。

JSXでマークアップを記述する

以下のコードをpage.tsx に追加してみます。

// This doesn't quite work!
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
<li>Invent new traffic lights
<li>Rehearse a movie scene
<li>Improve spectrum technology
</ul>

そうすると、うまく動作しなくなりました。

これは、JSXが含まれていないことが原因として挙げられます。

これを解決するには、コンバータを使用してreturn内に以下のように記述します。

<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>
<ul>
<li>Invent new traffic lights</li>
<li>Rehearse a movie scene</li>
<li>Improve spectrum technology</li>
</ul>
</>

また、JSXを使って記述してみます。

index.tsx
const person = {
  name: 'Gregorio Y. Zara',
  theme: {
    backgroundColor: 'black',
    color: 'pink'
  }
};
export default function TodoList() {
  return (
    <div style={person.theme}>
      <h1>{person.name}'s Todos</h1>
      <img
        className="avatar"
        src="https://i.imgur.com/7vQD0fPs.jpg"
        alt="Gregorio Y. Zara"
      />
      <ul>
        <li>Improve the videophone</li>
        <li>Prepare aeronautics lectures</li>
        <li>Work on the alcohol-fuelled engine</li>
      </ul>
    </div>
  );
}

コンポーネントにpropsを渡す

Reactコンポーネントは、互いにやり取りをする際にpropsというものを使用します。
親コンポーネントは小コンポーネントにpropsを渡すことで情報を伝えることができます。

propsとは

propsとはJSXタグに渡す情報のことです。例えば以下のようなコードを書きます。

function Avatar() {
return (
<img
className="avatar"
src="https://i.imgur.com/1bX5QH6.jpg"
alt="Lin Lanying"
width={100}
height={100}
/>
);
}

export default function Profile() {
return (
<Avatar />
);
}

img に渡すことができるpropsの種類は事前に決められています。しかし、Avatar のような自分で定義した独自のコンポーネントの場合は、任意のpropsを渡してそれをカスタマイズできます。

上記のコードの例では、Profile コンポーネントは<Avatar /> に何のpropsも渡していません。
以下の手順でpropsを渡します。今回はpersonとsizeを渡してみましょう。

<Avatar
size={100}
person={{
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2'
}}
/>

function Avatar({ person, size}) {
return (
<img
className="avatar"
src={getImageUrl(person)}
alt={person.name}
width={size}
height={size}
/>
);
}

propsのおかげで親と子のコンポーネントを独立して考えることができるようになります。

例えば、Profile で person や size を変更するときに Avatar 内でどう使われるかを気にしないでよくなります。同様に、Avatar がこれらの props をどのように使うのかは、Profile を見ずに変更できるようになります。

propsが唯一の引数となります。

propsに値が渡されなかった場合には、パラメータ名の直後に = とデフォルト値を書くことができます。
例えば、上記のコードの中の size={100} を消し、function Avatar({ person, size = 100}) とすると、先ほどと変わらずに表示されます

これらを使用して書いていくと、props が長くなった時にはコードが見づらくなってしまいます。

function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}

これを解消するために、以下のように記述します。

function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}

これにより、Profileに渡されたpropsを、個々の名前を列挙することなくすべてAvater に転送できます。

例えば以下のようなコードを書いてみます。

App.js
import Avatar from './Avatar.js';

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{ 
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}
Avatar.js
import { getImageUrl } from './utils.js';

export default function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}
utils.js
export function getImageUrl(person, size = 's') {
  return (
    'https://i.imgur.com/' +
    person.imageId +
    size +
    '.jpg'
  );
}

では実行してみようと思いましたが、なぜかローカルの方では実行してもカードのような表示にはならず、単なる画像として表示されてしまいました。(code sand boxの方ではうまくできました。)

試行錯誤した結果、sandboxではカードについてcssで記述されていたので、そちらを採用させていただきました!

以下のように追加しました!

global.css
.card {
  width: fit-content;
  margin: 10px;
  padding: 10px;
  font-size: 20px;
  text-align: center;
  border: 1px solid #aaa;
  border-radius: 20px;
  background: #fff;
}

clock コンポーネント

現実の時間を表示させるコンポーネントを作成します!
以下のようにしてコードを記述します

App.tsx
import { useState, useEffect } from 'react';
import Clock from './Clock.js';

function useTime() {
  const [time, setTime] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => {
      setTime(new Date());
    }, 1000);
    return () => clearInterval(id);
  }, []);
  return time;
}

export default function App() {
  const time = useTime();
  const [color, setColor] = useState('lightcoral');
  return (
    <div>
      <p>
        Pick a color:{' '}
        <select value={color} onChange={e => setColor(e.target.value)}>
          <option value="lightcoral">lightcoral</option>
          <option value="midnightblue">midnightblue</option>
          <option value="rebeccapurple">rebeccapurple</option>
        </select>
      </p>
      <Clock color={color} time={time.toLocaleTimeString()} />
    </div>
  );
}
Clocks.tsx
export default function Clock({ color, time }) {
  return (
    <h1 style={{ color: color }}>
      {time}
    </h1>
  );
}

まとめ

今回はここまでとしたいと思います。
ここからはNext.js を学習し、アプリ開発の方法を学習したのちに自己紹介ページを作成してみようと思います。Reactを再び学習することがあれば、さらに記事を追加していきたいと思います!

それでは!

Discussion