React学習記録 #2
初めに
今回はReactのコードとその結果について書いていきます!
この記事はjavascript(以下js)についての基礎知識を有する方に向けたものとなります。
参考にしたサイトは以下の通りです
実行環境:
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するファイル内で呼び出すことにします。
例えば、私の場合には、以下のように記述します。
import Profile from './component'
export default function Home() {
return (
<h1>Amazing scientists</h1>
<Profile />
</div>
</main>
)
}
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を使って記述してみます。
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 に転送できます。
例えば以下のようなコードを書いてみます。
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>
);
}
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}
/>
);
}
export function getImageUrl(person, size = 's') {
return (
'https://i.imgur.com/' +
person.imageId +
size +
'.jpg'
);
}
では実行してみようと思いましたが、なぜかローカルの方では実行してもカードのような表示にはならず、単なる画像として表示されてしまいました。(code sand boxの方ではうまくできました。)
試行錯誤した結果、sandboxではカードについて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 コンポーネント
現実の時間を表示させるコンポーネントを作成します!
以下のようにしてコードを記述します
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>
);
}
export default function Clock({ color, time }) {
return (
<h1 style={{ color: color }}>
{time}
</h1>
);
}
まとめ
今回はここまでとしたいと思います。
ここからはNext.js を学習し、アプリ開発の方法を学習したのちに自己紹介ページを作成してみようと思います。Reactを再び学習することがあれば、さらに記事を追加していきたいと思います!
それでは!
Discussion