宣言的なview
今まで扱っていたJavaScriptやjQueryは、直接DOm操作する命令的なviewでした。
一方Reactは宣言的なviewといい、データさえ与えれば勝手にviewが変わります。
メンテナンス性はこっちの方がいい!
コンポーネントについて
Reactに限りませんが、一つのファイルに全ての処理を記述すると何千行という膨大な行になります。
よって可読性が悪くなってしまいます。
そこでコンポーネントごとにファイル分けをすることによ李、可読性・再利用性・保守性を向上させることができます。
※細かくまとめすぎると「保守性」が低くなり、粗すぎると「再利用性」が低くなる。
チームでの方針はあると思うが、繰り返し使えるかどうかを基準にしてもいいかもしれません。
//ReactDOMという名前でreact-domをインポート
import ReactDOM from "react-dom";
//App.jsxからApp関数コンポーネントを読み込んでいる
import { App } from "./App";
//App関数コンポーネントをid="root"の中で使うという意味
ReactDOM.render(<App />, document.getElementById("root"));
export const App = () => {
return (
<>
<h1>こんにちは!</h1>
<p>清水です</p>
</>
);
}
※コンポーネントファイルのAppファイル等はApp.js
でも問題なく動きますが、以下の理由からApp.jsx
で命名することをお勧めします。
・一目でコンポーネントファイルとわかる
・補完機能が使える(具体的には、まだわかりません、、、)
イベントの使い方
export const App = () => {
const onClickButton = () => {
alert('成功しました');
}
return (
<>
{console.log('コンソールに表示させます')}
<button onClick={onClickButton}>ボタン</button>
</>
);
}
HTMLの中でJavaScriptを記述するときは{}
で囲むことで記述できます。
Propsとは
簡単にいうと引数のような働きをしている。
「色が違うだけなのに、毎回3行書くのめんどくさい!」
↓
「3行はコンポーネントにして、色だけ個別に指定すればいいんじゃね?」
↓
これがPropsです。
※この下の説明重要
さらに技術的に書くなら、
・親コンポーネント(インポートするファイル)から「色」を渡します。
・子コンポーネント(エクスポートするファイル)はその色を「props」という引数で受け取ります。(propsでなくてもいい)
・propsの中身はオブジェクトになっており、[キー:値]で受け取ります。
・引数.キー
を指定することで、値を受け取ることができる。
Props(properties)の実践
やりたいことがわかったところで、実際に記述していこうと思います。
まず下準備です。
① jsファイルと同じ階層に「componentsフォルダ」を作成
② ①の中にColoredMessageファイルを作成
③ 下記のように文字の色と大きさを指定する関数を作成
export const ColoredMessage = () => {
const contentStyle = {
color: "blue",
fontSize: "20px"
};
return <p style={contentStyle}>しみともです</p>;
};
//いらないものは削除してます
import { ColoredMessage } from "./components/coloredMessage";
export const App = () => {
return <ColoredMessage />;
}
これで準備が完了したので、Propsを使っていきたいと思います。
以下のようにコードを変更していきます。
import { ColoredMessage } from "./components/coloredMessage";
export const App = () => {
//任意で命名した「color」と「message」にPropsを渡していきます
return <ColoredMessage color="blue" message="うまくできるかな?"/>;
}
export const ColoredMessage = (props) => {
// { color: 'blue', message: 'うまくできるかな?' }と表示されるか確認
console.log(props);
const contentStyle = {
//任意で命名したclorを指定
color: props.color,
fontSize: "20px"
};
//任意で命名したmessageを指定
return <p style={contentStyle}>{props.message}</p>;
};
これでうまく引数のように使用できていることがわかるかと思います。
ちなみに、以下のように様々なものを指定することができます。
<HeadLine
title="about.js"//文字列
number={1111}//数値
array={[1, 2, 3]}//配列
obj={{ name: "清水", old: 24 }}//オブジェクト
boolean//true
false={false}//false
component={<span>しみとも</span>}//jsx(コンポーネント)
onClick={() => alert("クリック")}//関数
/>
children
Propsにはchildrenというものが存在します。
上記のPropsでは属性にメッセージを指定しましたが、childrenではタグのようにメッセージを指定することができます。
さらに詳しく説明すると
//通常のpropsでは下記の記述で終了です
<ColoredMessage color="red" />
//開始タグと終了タグの中に存在しているものが「children:foo」として渡される
//fooも「children:foo」となり、propsとして渡すことができる
<ColoredMessage color="red">foo</ColoredMessage>
さらにdiv
、p
などのタグを入力することもできます。
こちらの方が使い勝手が良さそうですね!
import { ColoredMessage } from "./components/coloredMessage";
export const App = () => {
return (
<>
<ColoredMessage color="red">うまくできるかな?</ColoredMessage>
<ColoredMessage color="blue">
<div>
<p>こんなこともできるよ</p>
<p>試してみてね</p>
</div>
</ColoredMessage>
</>
);
}
export const ColoredMessage = (props) => {
const contentStyle = {
color: props.color,
fontSize: "20px"
};
//props.childrenで取得できる
return <p style={contentStyle}>{props.children}</p>;
};
もっと効率よく記述するには
ここで分割代入をうまく使えば、props.children
みたいな記述を短く書くことができます!
export const ColoredMessage = (props) => {
const { color, children } = props;
const contentStyle = {
color,
fontSize: "20px"
};
return <p style={contentStyle}>{children}</p>;
};
あとは引数の段階で分割代入する方法もあります。
(知らなかった、、、。こっちの方がいいじゃんね。)
export const ColoredMessage = ({ color, children }) => {
const contentStyle = {
color,
fontSize: "20px"
};
return <p style={contentStyle}>{children}</p>;
};
画像を表示するしないをpropsで管理する方法
export function Hero({imageOn = false}) {
return (
<div>
{imageOn && <figure>[画像]</figure>}
</div>
)
}
export default function Home() {
return (
<Hero
imageOn
/>
)
}
Heroコンポーネント
を記述していても「imageOnがtrueにならないと表示されない」ようになっている。
※この場合のtrueとは属性があるかないか。記述があればOK!
↓
imageOn = false
はデフォルト引数であり、「引数を指定しなかった場合は、こうしてね!」って感じ。
今回はfalseにしてね!という設定をしている。
そして{imageOn && <figure>[画像]</figure>}
は
「imageOnがtrueなら<figure>[画像]</figure>
を返してね」という意味。
↓
もし「&&」ではなく「||」なら、
「imageOnがtrueならimageOnを返し、それ以外なら<figure>[画像]</figure>
を返してね」
という意味になる。
cssをprppsで操作する方法
①
適応させたい箇所に具体的な数値を記述。
<Social iconSize="30px"/>
②
①をコンポーネントファイルで受け取る。
Social({iconSize = 'initial'})
<ul style={{'--icon-size':iconSize}}>
③
moduleファイルで'--icon-size'の値を設定。
font-size: var(--icon-size, 24px);
コンポーネントを渡す方法
ちなみに下記の例は、Tabler-iconを使用。
import Link from "next/link";
import { IconSearch, IconHeart, IconShoppingCart } from "@tabler/icons-react";
const Navigations = [
{
id: "1",
icon: IconSearch,
},
{
id: "2",
icon: IconHeart,
},
{
id: "3",
icon: IconShoppingCart,
},
];
export default function Layout({ children }) {
return (
<ul>
{Navigations.map((Navigation) => {
const IconComponent = Navigation.icon;
return (
<li key={Navigation.id}>
<IconComponent />
</li>
);
})}
</ul>
);
}