1. はじめに
以下の記事に記載されているReact勉強ロードマップの課題2に取り組むための背景知識を軽くまとめた。
1-1. インプット
以下の教材の44.まで行った。
1-2. 再レンダリング
どんな時に再レンダリングされる?
- Stateが更新されたコンポ―ネント
- propsが変更されたコンポーネント
- 再レンダリングされたコンポーネント配下の子要素
レンダリングの最適化
Stateが更新されたコンポーネントやpropsが変更されたコンポーネントは表示内容が変わるので、再レンダリングを行うのは分かるのだが、再レンダリングされたコンポーネント配下の子要素については、上記の2つに当てはまらなくても再レンダリングされてしまう。これの解消について、以下で述べる。
memoの使用(コンポーネントの最適化)
import { useState, useCallback, useMemo } from 'react';
import './App.css';
import { ChildArea } from './ChildArea';
export const App = () => {
console.log('App');
const [text, setText] = useState('');
const [open, setOpen] = useState(false);
const onChangeText = (e) => setText(e.target.value);
const onClickOpen = () => setOpen(!open);
const onClickClose = useCallback(() => setOpen(false), [setOpen]);
const temp = useMemo(() => 1 + 3, []);
console.log(temp);
return (
<>
<div>
<input value={text} onChange={onChangeText} />
<br />
<br />
<button onClick={onClickOpen}>表示</button>
<ChildArea open={open} onClickClose={onClickClose} />
</div>
</>
);
};
import { memo } from 'react';
const style = {
width: '100%',
height: '200px',
backgroundColor: 'khaki',
};
export const ChildArea = memo((props) => {
const { open, onClickCLose } = props;
console.log('ChildAreaがレンダリングされた!!');
const data = [...Array(100).keys()];
data.forEach(() => {
console.log('...');
});
return (
<>
{open ? (
<div style={style}>
<p>子コンポ―ネント</p>
<button onClick={onClickCLose}>閉じる</button>
</div>
) : null}
</>
);
});
memoを使用しようしたコンポーネントはpropsに変更がない限り再レンダリングされない。よって、親コンポーネントであるApp.jsxのinputタグの中身が変更されて、onChangeText関数が実行され、setTextによりステートが更新されても、App.jsxは再レンダリングされるが、ChildArea.jsxが再レンダリングされない。
useCallback の使用(関数の最適化)
import { useState, useCallback, useMemo } from 'react';
import './App.css';
import { ChildArea } from './ChildArea';
export const App = () => {
console.log('App');
const [text, setText] = useState('');
const [open, setOpen] = useState(false);
const onChangeText = (e) => setText(e.target.value);
const onClickOpen = () => setOpen(!open);
const onClickClose = useCallback(() => setOpen(false), [setOpen]);
const temp = useMemo(() => 1 + 3, []);
console.log(temp);
return (
<>
<div>
<input value={text} onChange={onChangeText} />
<br />
<br />
<button onClick={onClickOpen}>表示</button>
<ChildArea open={open} onClickClose={onClickClose} />
</div>
</>
);
};
import { memo } from 'react';
const style = {
width: '100%',
height: '200px',
backgroundColor: 'khaki',
};
export const ChildArea = memo((props) => {
const { open, onClickCLose } = props;
console.log('ChildAreaがレンダリングされた!!');
const data = [...Array(100).keys()];
data.forEach(() => {
console.log('...');
});
return (
<>
{open ? (
<div style={style}>
<p>子コンポ―ネント</p>
<button onClick={onClickCLose}>閉じる</button>
</div>
) : null}
</>
);
});
ChildAreaコンポーネントに渡しているonClickClose関数は、アロー関数で宣言しているので、毎回新しい関数を生成しているという仕様により、毎回違う関数を渡している(propsが更新されている)と判断してしまう。よって、処理が変わらない場合は同じものを使いまわすという指示にする必要がある。そこで、useCallbackを使用する。useCallbackはアロー関数全体をuseCallback()で囲ってやる。また、useEffectと一緒で第2引数に値を配列[]で指定してやる必要がある。この第2引数は監視する値なので、setOpenになっている。
useMemo の使用(変数の最適化)
const temp = useMemo(() => 1 + 3, []);
そこまで使う頻度は高くないが、変数に設定する中の処理が大きくなると使用される。今回の場合は[]を第2引数に指定しているので、最初だけ 1 + 3 が実行されて、tempに代入される。
1-3. 様々なCSSの当て方
Inline Styles
export const InlineStyle = () => {
const containerStyle = {
border: 'solid 2px #392eff',
borderRadius: '20px',
padding: '8px',
margin: '8px',
display: 'flex',
justifyContent: 'space-around',
alignItems: 'center',
};
const titleStyle = {
margin: 0,
color: '#3d84a8',
};
const buttonStyle = {
backgroundColor: '#abedd8',
border: 'none',
padding: '8px',
borderRadius: '8px',
};
return (
<>
<div style={containerStyle}>
<p style={titleStyle}>- Inline Styles -</p>
<button style={buttonStyle}>FIGHT</button>
</div>
</>
);
};
変数としてCSSを宣言でき、それをタグのstyle={}に代入することで適応できる。値を文字列で宣言したり、キャメルケースの変更する点が普段と異なる。
CSS Modules
sassというライブラリを使用する
import classes from './CssModules.module.scss';
export const CssModules = () => {
return (
<>
<div className={classes.container}>
<p className={classes.title}>- CSS Modules -</p>
<button className={classes.button}>FIGHT!!</button>
</div>
</>
);
};
.container {
border: solid 2px #392eff;
border-radius: 20px;
padding: 8px;
margin: 8px;
display: flex;
justify-content: space-around;
align-items: center;
}
.title {
margin: 0;
color: #3d8418;
}
.button {
background-color: #abedd8;
border: none;
padding: 8px;
border-radius: 8px;
&:hover {
background-color: #46cdcf;
color: #fff;
cursor: pointer;
}
}
別の.module.scssファイルにCSSを記述し、それをインポートして使用する。
Styled JSX
styled-jsxというライブラリを使用する
export const StyledJsx = () => {
return (
<>
<div className="container">
<p className="title">- Styled JSX -</p>
<button className="button">FIGHT!!</button>
</div>
<style jsx="true">{`
.container {
border: solid 2px #392eff;
border-radius: 20px;
padding: 8px;
margin: 8px;
display: flex;
justify-content: space-around;
align-items: center;
}
.title {
margin: 0;
color: #3d8418;
}
.button {
background-color: #abedd8;
border: none;
padding: 8px;
border-radius: 8px;
&:hover {
background-color: #46cdcf;
color: #fff;
cursor: pointer;
}
}
`}</style>
</>
);
};
styleタグを使用し、jsx="true"でjsxであることを明記する。そして、そのタグの中で{``}を書き込み、その中でCSSを書き込む。
styled-components
styled-componentsというライブラリを使用する
import styled from 'styled-components';
export const StyledComponents = () => {
return (
<>
<SContainer>
<STitle>- Styled Components -</STitle>
<SButton>FIGHT!!</SButton>
</SContainer>
</>
);
};
const SContainer = styled.div`
border: solid 2px #392eff;
border-radius: 20px;
padding: 8px;
margin: 8px;
display: flex;
justify-content: space-around;
align-items: center;
`;
const STitle = styled.p`
margin: 0;
color: #3d8418;
`;
const SButton = styled.button`
background-color: #abedd8;
border: none;
padding: 8px;
border-radius: 8px;
&:hover {
background-color: #46cdcf;
color: #fff;
cursor: pointer;
}
`;
styled-componentsはstyledが当たった変数を宣言し、それをタグとして扱うことで、styleを適応できる。
Emotion
@emotion/reactと@emotion/styledというライブラリを使用する
/** @jsxRuntime classic */
/** @jsx jsx */
import React from 'react';
import { jsx, css } from '@emotion/react';
import styled from '@emotion/styled';
export const Emotion = () => {
const containerStyle = css`
border: solid 2px #392eff;
border-radius: 20px;
padding: 8px;
margin: 8px;
display: flex;
justify-content: space-around;
align-items: center;
`;
const titleStyle = css({
margin: 0,
color: '#3d8418',
});
return (
<>
<div css={containerStyle}>
<p css={titleStyle}>- Emotion -</p>
<SButton>FIGHT!!</SButton>
</div>
</>
);
};
const SButton = styled.button`
background-color: #abedd8;
border: none;
padding: 8px;
border-radius: 8px;
&:hover {
background-color: #46cdcf;
color: #fff;
cursor: pointer;
}
`;
containerStyle, titleStyle, SButtonの3つの記述の仕方ができる。
1-4. その他重要な内容
- React Router
- Atomic Design
- グローバルなステート管理
- APIを叩いてJSONデータの取得