๐พ๋ค์ด๊ฐ๋ฉฐ
๋ฐ์ํ ํ ์คํธ๋ฐ์ค๋?
- ์ฌ์ฉ์์ ์ ๋ ฅ์ ๋ฐ๋ผ์ ํฌ๊ธฐ๊ฐ ์๋ ์กฐ์ ๋๋ ํ ์คํธ ๋ฐ์ค. ์์ ์ ์ ํ๋๋ฅผ ์๊ฐํด๋ณด๋ฉด ๋๋ค.
- ํ๋ฉด์ ํฌ๊ธฐ์ ๋ฐ๋ผ์ ๋น์จ์ด ์๋ ์กฐ์ ๋๋ ํ ์คํธ ๋ฐ์ค.
๋ณดํต ์์ ๋ ๊ฐ์ง๋ฅผ ๋ชจ๋ ํด๊ฒฐํ ์ ์๋ ๋ฐฉ๋ฒ์ด ๋ฐ๋ก ์คํ์ผ๋ก ์กฐ์ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
๊ทธ๋ฌ๋ ์ฌ๊ธฐ์์ ๊ถ๊ธ์ฆ์ด ์๊ฒผ์ต๋๋ค.
textarea์ ๊ธฐ๋ณธ ์์ฑ ์ค rows์ cols๊ฐ ์๋๋ฐ, ๋ณดํต ์ด๊ฒ์ผ๋ก ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ ์๋ ์์ต๋๋ค.
์คํ์ผ๋ก ์กฐ์ ํ ๊ฒฝ์ฐ ์ต์ด ์ ์ธํ rows์ cols๊ฐ ๋ฐ๋์ง ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด cols์ rows๋ก ๋ฐ์ํ์ ํ์ง ์๋ ๊ฒ์ผ๊น?
๊ถ๊ธํด์ ์ง์ ๊ตฌํํด๋ณด์์ต๋๋ค!!
โจ๋ณธ๊ฒฉ์ ์ผ๋ก
โ cols = 1 ์ด ์๋ฏธํ๋ ๊ฒ
- cols๋ ๊ฐ๋ก์ ํฌ๊ธฐ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
- cols๋ ์ซ์๋ฅผ ๊ฐ์ผ๋ก ๋ฐ์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด cols=1์ด ์๋ฏธํ๋ ๊ฒ์ ๋ฌด์์ผ๊น์?
๋ฐ๋ก, 1byte์
๋๋ค. ๋ต... ์ฌ์ค ์ฌ๊ธฐ์์ ๋ฉ์ท์ด์ผ ํ๋ค.
์ฌ๊ธฐ์์ ๋ฑ์ฅํ๋ ๊ธ์์ byte ๊ฐ๋ ..! ์ด๋ฏธ ์ด๋ ์ ๋ ๋ค์ด์ ์๊ณ ์์ง๋ง, ํ๊ธ์ ๊ฒฝ์ฐ ํ๋์ ๋ชจ์, ์์ ๋น 2byte, ์ซ์, ํน์๋ฌธ์, ์์ด๋ 1byte๋ฅผ ์ฐจ์งํฉ๋๋ค. ์ฆ, ํ๊ธ๊ณผ ์์ด๋ฅผ ์ ๋ ฅํ ๋์ cols๊ฐ ๋์ด๋๋ ์ ๋๊ฐ ๋ค๋ฅด๋ค๋ ๊ฒ์ ๋๋ค. ํ๊ธ๋ก ์ ๋ ฅํด๋, ์ซ์์ ํน์๋ฌธ์์ ๊ฒฝ์ฐ๊ฐ ์์ผ๋ ์ ๋ ฅ๋ฐ๋ ์ธ์ด๋ฅผ ํ๊ธ๋ก ํต์ผํ๋ ๊ฒ๋ ํ๋ญ๋๋ค. (์ฐธ๊ณ ๋ก ์ํฐ๋ฅผ ์น ๋๋ 1byte๊ฐ ํ์)
์, ๋คํํ rows๋ ์ค ์๋ผ๊ณ ์๊ฐํ์๋ฉด ๋ฉ๋๋ค...
-> cols๋ฅผ ์กฐ์ ํ๊ธฐ ์ํด์ ์ ๋ ฅ๋ฐ์ ๊ฐ์ byte๋ฅผ ์์์ผ ํ๋ค.
const getByteOfValue = (str: string) => {
let byte = 0;
for (let i = 0; i < str.length; i++) {
// ๊ธฐ๋ณธ ํ๊ธ 2๋ฐ์ดํธ ์ฒ๋ฆฌ
str.charCodeAt(i) > 128 ? (byte += 2) : byte++;
}
return byte;
};
โ textarea์์ ๋ง์ง๋ง์ผ๋ก ์ ๋ ฅํ ๊ธ์
textarea๋ฅผ ๋ฆฌ์กํธ์์ ๋ง๋ค ๋ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์ํด ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํฉ๋๋ค.
import { FormEventHandler, useState } from 'react';
import styles from './Textarea.module.scss';
const Textarea = ({ ...props }: React.HTMLProps<HTMLTextAreaElement>) => {
const [value, setValue] = useState('');
const onChangeTextarea: FormEventHandler<HTMLTextAreaElement> = event => {
const elem = event.target as HTMLTextAreaElement;
setValue(elem.value);
};
return (
<textarea
value={value}
onChange={onChangeTextarea}
className={styles.textarea}
{...props}
/>
);
};
export default Textarea;
๊ทธ๋ ๋ค๋ฉด value์ ๊ฐ์๋ ์ด๋ค ๊ฒ ๋ค์ด์ฌ๊น์?
์ฌ์ฉ์์ ์
๋ ฅ: "hello" / value: "hello"
์ฌ์ฉ์์ ์
๋ ฅ: "hello ใ
" / value: "hello ใ
"
์ฌ์ฉ์์ ์
๋ ฅ: "hello ์ธ" / value: "hello ์ธ"
๊ทธ๋ ์ต๋๋ค. value๋ ์ฌํ๊น์ง ์ ๋ ฅํ๋ ๋ชจ๋ ๊ธ์๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ง์ง๋ง์ผ๋ก ์
๋ ฅํ ๊ธ์๋ value[vlaue.length - 1]
์
๋๋ค. ์์ ์์์์๋ "o", "ใ
", "์ธ"๊ฐ ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ธ์์๋... ์ฒซ๋ฒ์งธ์ ๋๋ฒ์งธ๋ ์ด ๊ธ์์๊ฐ ๋ฐ๋์์ต๋๋ค. ๊ทธ๋ฌ๋, ๋๋ฒ์งธ์ ์ธ๋ฒ์งธ๋ ๊ธ์์๊ฐ ๋๊ฐ๊ตฐ์.
'ใ
'๊ณผ 'ใ
' ๋ชจ๋ ํ๊ธ์ด๋ผ์ cols์ ๊ทธ๋๋ก 2byte์ฉ ๋ํด์ฃผ๋ ๊ฒ์ด ์๋ 'ใ
'์ ์
๋ ฅํ์ ๋ 2๋ฅผ ๋ํด์ฃผ๊ณ , 'ใ
'๋ฅผ ์
๋ ฅํ์ ๋ ์ด ๊ธ์ ์๊ฐ ๋ฐ๋์ง ์์์ผ๋ ๋ํด์ผ ํ๋ค๋ฉด 0์ ํด์ผ ๋ฉ๋๋ค.
-> ๊ธ์ ์์ ๋ณ๋์ ๋ฐ๋ผ cols์ ์ผ๋ง์ byte๋ฅผ ๋ํด์ผ ํ๋์ง ๊ฒฐ์ ํด์ผ ํ๋ค.
๊ธ์ ์๊ฐ ๋ฐ๋์๋ ์ง ํ์ธํ๋ ํจ์
//์ด์ ๊ธธ์ด ์ ์ฅ const [prevInputLength, setPrevInputLength] = useState(0); //์ ๋ ฅ๋ฐ์ value์ ๊ธธ์ด(ํ์ฌ ๊ธธ์ด)์ ์ด์ ๊ธธ์ด ๋น๊ต const checkIncreasingValueByte = (value: string) => { const inputTextLength = value.length; const hasIncreasedValue = prevInputLength <= inputTextLength - 1; setPrevInputLength(inputTextLength); //๊ธธ์ด๊ฐ ๋์๋ค๋ฉด true ์๋๋ผ๋ฉด false return hasIncreasedValue; };
์ ๋ ฅํ ๊ธ์์ byte๋ฅผ ๊ณ์ฐํ๋ ํจ์
//์ด์ ์ ๊ณ์ฐํ byte ์ ์ฅ const [prevByte, setPrevByte] = useState(0); //์ด์ ์ ๊ณ์ฐํ byte์ ์ ๋ ฅ๋ฐ์ str์ byte๋ฅผ ๋น๊ต const getGapOfBytes = (str: string) => { //์ ์ฒด byte ๊ณ์ฐ const byte = getByteOfValue(str); let returnValue = 1; //1byte์ ์ฐจ์ด๋ผ๋ฉด 1์ ๋ฐํ if (byte - prevByte === 1) returnValue = 1; //์๋๋ผ๋ฉด 2๋ฅผ ๋ฐํ else returnValue = 2; //๊ณ์ฐํ byte ์ ์ฅ setPrevByte(byte); return returnValue; };
์ฆ, ๋ง์ฝ ๊ธ์ ์๊ฐ ์ฆ๊ฐํ๋ค๋ฉด, ์ด์ ๊ธ์์ ์ด byte์ ํ์ฌ ๊ธ์์ ์ด byte๋ฅผ ๊ณ์ฐํ์ฌ ๊ทธ ์ฐจ์ด๋งํผ๋ง cols์ ๋ํด์ค์ผ ํฉ๋๋ค.
if(checkIncreasingValueByte()) cols += getGapOfBytes(value);
์ฌ๊ธฐ์์ ์ checkIncreasingValueByte์ธ๋ฐ getGapOfBytes๋ฅผ ์ฌ์ฉํ์ง ์์์๊น์?
getGapOfBytes ํจ์๋ getByteOfValue์ ํจ์์ ์์กดํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ getByteOfValue์ ๋ด๋ถ์๋ ์ ์ฒด ๊ธ์๋ฅผ ๋๋ฉด์ byte๋ฅผ ๊ณ์ฐํฉ๋๋ค. ์ฐจ๋ผ๋ฆฌ length๋ฅผ ์ด์ฉํด์ ๋จ์ํ๊ฒ ๊ณ์ฐํ๋ ํธ์ด ๋ ๋น ๋ฅด๊ธฐ ๋๋ฌธ์
๋๋ค. (์ฌ์ค ๊ธ ์ ๋ค๊ฐ ๋ฐ๊ฒฌํจ) ์ด ๊ธ์ฒ๋ผ ๊ธด ๊ธ์ ์ ๋๋ค๊ณ ํ์ ๋ ๋ชจ๋ ๊ธ์์๋ฅผ ๋ค์ ๊ณ์ฐํ๋ ๊ฒ๋ณด๋ค ์ฑ๋ฅ์ด ๋ ์ข์ต๋๋ค!
โ ๊ฐ๋ก(horizontal) ๋ฐ์ํ ํ ์คํธ๋ฐ์ค
- rows: ์ธ๋ก ๋์ด๋ ๊ณ ์ ์ ๋๋ค. ์ธ๋ก ๊ธธ์ด๋ฅผ ๊ฐ์ผ๋ก ๋ฐ์์ผ ํฉ๋๋ค.
- maxCols: ์ต๋ ๊ฐ๋ก ๊ธธ์ด๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค.
- cols: ์ต์ ๊ฐ๋ก ๊ธธ์ด๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค.
๋ฐ์ํ์ ํ ๋ ๊ณ ๋ คํ ์ ์ ์ต๋๊ฐ๊ณผ ์ต์๊ฐ ์ฌ์ด์์ ์์ ๋กญ๊ฒ ๋ ์?๋ค๋ ์ผ ํ๋ค๋ ์ ์ ๋๋ค. ๊ทธ๋์ ๋ค์๊ณผ ๊ฐ์ด ์ต์๊ฐ๊ณผ ์ต๋๊ฐ์ ๋ฒ์ ๋ด์ ์๋์ง, ๋์ง๋ ์์๋์ง ํ์ธํ ์ ์๋ ๋ณ์๋ค์ ๋ง๋ค์์ต๋๋ค.
cols์ maxCols์ ๊ฒฝ์ฐ ๊ฐ์ด ์์ ์๋ ์์ต๋๋ค. ๋ฌดํ๋๋ก ๊ฐ๋ก ๊ธธ์ด๊ฐ ๋์ด๋ ์ ์์ ์๋ ์์ง ์์๊น์?
const isOverMinCols = !!cols && cols <= currentCols;
const isUnderMaxCols = !!maxCols && currentCols <= maxCols;
const isOverMaxCols = !maxCols || !isUnderMaxCols;
const isValidHorizontal = horizontal && (isUnderMaxCols || isOverMinCols) && !isOverMaxCols;
์ด์ ์ด ์น๊ตฌ๋ค์ ๋ ๋๋ง๋ ๋๋ง๋ค ํ์ธ์ ํด์ค ๊ฒ๋๋ค. ๋ฌผ๋ก ์ ๋ ฅ๋ฐ๋ value๊ฐ ๋ฐ๋ ๋๋ง๋ค ๋ ๋๋ง ๋์ง๋ง, ์ด ์น๊ตฌ๋ค์ ํ์ฌ cols์ ๊ฐ์ ์์กดํด์ผ ํฉ๋๋ค. ๊ทธ๋์ ํ์ฌ cols(currentCols)๋ฅผ ์ํ๋ก ๋ง๋ค์ด์ฃผ๊ณ , textarea์ cols์ ๊ฐ์ผ๋ก ๋๊ฒจ์ค๋๋ค.
const [currentCols, setCurrentCols] = useState(cols ?? 1);
/** ์๋ต */
<textarea
value={value}
ref={textarea}
className={styles.textarea}
onChange={handleChangeTextarea}
onKeyUp={handleKeyEnter}
cols={currentCols}
rows={currentRows}
{...props}
/>
cols๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก 1์ด ๋ค์ด๊ฐ๋๋ค. cols ๊ฐ์ด ์์ ์๋ ์๊ณ , ์ปค์๋ฅผ ๋ณผ ์ ์๋ ์ต์ ํฌ๊ธฐ๋ ๋์ด์ผ ํ๋๊น์.
์ด์ ๊ฐ๋ ๋ฐ์๊ณ , ๋ฒ์๋ ์ค์ ํ์ผ๋ ์ ๋ ฅ์ด ๋ฐ๋ ๋๋ง๋ค cols๋ฅผ ์ ๋ฐ์ดํธ ํด์ค ์ผ๋ง ๋จ์์ต๋๋ค. value๋ฅผ ๋ฐ์ธ๋ฉ ํด์ฃผ๋ handleChangeTextarea์ ํจ์์์ ๊ฐ์ด ์ฒ๋ฆฌํด์ฃผ์ด๋ ๋์ง๋ง, value๊ฐ ๋ฐ๋์ ๋ฐ๋ผ cols๋ฅผ ์ ๋ฐ์ดํธํ๋ ๋ถ์ ํจ๊ณผ๋ผ๊ณ ์๊ฐํด์ useEffect๋ก ๊ด๋ฆฌํด์ค๋๋ค.
useEffect(() => {
if (!textarea.current) return;
const elem = textarea.current as HTMLTextAreaElement;
updateCountOfTextAfterEnter(value); //์ด ์น๊ตฌ๋ ๋ฌด์์ผ๊น?
const isOverCurrentCols = checkOverCurrentCols();
if (isValidHorizontal) {
elem.cols = isOverCurrentCols ? countOfTextAfterEnter : currentCols;
}
setCurrentCols(elem.cols);
}, [value]);
์ฌ๊ธฐ์์ ์ updateCountOfTextAfterEnter๋ผ๋ ํจ์์ ์ด๋ฆ์ด ๋น์ทํ countOfTextAfterEnter๋ผ๋ ์น๊ตฌ๊ฐ ์๋กญ์ต๋๋ค.
์ฌ๊ธฐ์์ ์์ ๋ด์ฉ์ด ๋ค์ ๋ฑ์ฅํฉ๋๋ค. cols์ ๊ฐ์ ๊ธ์์ byte๊ฐ์ด๋ค...
//ํ์ฌ ์
๋ ฅํ ํ
์คํธ์ ๊ธธ์ด. ์ํฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋๋. ์นธ์ด ๋ชจ์๋ผ์ ์ค๋ฐ๊ฟ ๋๋ ๊ฒฝ์ฐ๊ฐ ์๋!
const [countOfTextAfterEnter, setCountOfTextAfterEnter] = useState(0);
const updateCountOfTextAfterEnter = (value: string) => {
const inputLanguageByte = getGapOfBytes(value);
//์ ์ฒด ๊ธ์ ์์ ๋ณ๋์ด ์๋ค๋ฉด, ๋ณ๋๋ byte ์๋งํผ ๋ํ๊ธฐ. ์๋ค๋ฉด 0์ ๋ํ๊ธฐ.
const countOfText = checkIncreasingValueByte(value) ? inputLanguageByte : 0;
setCountOfTextAfterEnter(prev => prev + countOfText);
};
ํ์ฌ ์ ๋ ฅํ ๊ธ์์ ์๊ฐ ๋ฐ๋๋ ๊ฒ์ ์์์ผ cols๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ํ์ฌ ์ ๋ ฅํ ๊ธ์๋ฅผ ํ์ธํ๊ณ ๊ธ์ ์๊ฐ ์ฆ๊ฐํ๋ค๋ฉด ์ฆ๊ฐํ byte ๋งํผ ๋ํด์ฃผ๊ณ , ์๋๋ผ๋ฉด 0๋งํผ ๋ํด์ฃผ์์ต๋๋ค. ๊ธ์๋ฅผ ์ง์ ๋ค๋ฉด ์์๋ฅผ ์ฃผ๊ธฐ ๋๋ฌธ์ ๋๋ค.
์, ์ด๋ ๊ฒ ๋์ธ ์ค ์์์ฃ ..? ๐
๋ง์ฝ cols๊ฐ ๊ธฐ๋ณธ 20์ผ๋ก ์ค์ ๋์๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ํ์ฌ๋ ๊ธ์๋ฅผ ์ ๋ ฅํ ๋๋ง๋ค cols๊ฐ ์ฆ๊ฐํฉ๋๋ค. ์ฆ, ๊ธฐ๋ณธ์ผ๋ก ์ค์ ํ 20์ ๋ ์ถ๊ฐ๋ฅผ ํ๊ณ ์๋ ๊ฒ์ด์ฃ . ๊ทธ๋ฌ๋, 20์ ๋ค ์ฑ์ธ ๋๊น์ง ์์ง์ด๋ฉด ์๋ฉ๋๋ค.
useEffect(() => {
if (!textarea.current) return;
const elem = textarea.current as HTMLTextAreaElement;
updateCountOfTextAfterEnter(value);
const isOverCurrentCols = checkOverCurrentCols();
//ํ์ฌ cols๊ฐ ๊ธ์๋ก ๋ค ์ฐผ๋์ง ์๋ ค์ค!
const isPullCurrentCols = elem.cols === currentCols;
if (isValidHorizontal && isPullCurrentCols) {
elem.cols = isOverCurrentCols ? countOfTextAfterEnter : currentCols;
}
setCurrentCols(elem.cols);
}, [value]);
์ด๋ ๊ฒ ์กฐ๊ฑด์ ํ๋ ์ถ๊ฐํด์ ๋๋์ด!! ๊ฐ๋ก ๋ฐ์ํ ํ ์คํธ๋ฐ์ค๋ฅผ ๋ง๋ค์์ต๋๋ค...ใ ใ
์ถ๊ฐ์ ์ผ๋ก enter ํค๋ฅผ ๋๋ฅผ ๋๋ง๋ค ํ์ฌ cols๊ฐ ๋ฐ๋ ์ ์์ต๋๋ค. ํ
์คํธ์ ์ค๊ฐ์์ ์ํฐ๋ฅผ ์น ๊ฒฝ์ฐ๊ฐ ์์ฃ .
๊ทธ๋์ enter ํค๋ฅผ ๋๋ฅธ๋ค๋ฉด ๋จผ์ , ๋ค์ ํ์ฌ ๊ฐ์ง ์ต๋ cols๊ฐ ์ผ๋ง์ง ์์๋ด์ผ ํฉ๋๋ค.
const handleKeyEnter: React.KeyboardEventHandler<HTMLTextAreaElement> = event => {
if (event.key === 'Enter') {
if (isValidHorizontal) {
//์ฌ๊ธฐ์์ ์ผ๋จ ์ํฐ๋ฅผ ํ์ผ๋ ํ์ฌ ์
๋ ฅํ ๊ฐ์ ์ด๊ธฐํ.. ์ฌ๊ธฐ์์ ๋ง์ todo๊ฐ ์๋ต๋จ..
setCountOfTextAfterEnter(0);
//enter๋ฅผ ํ
์คํธ ์ค๊ฐ์์ ํ์ ๊ฒฝ์ฐ currentMacCols๊ฐ ๋ฌ๋ผ์ง ์ ์๋ค.
const currentMaxCols = calcMaxColsByte(value);
setCurrentCols(currentMaxCols);
}
};
const calcMaxColsByte = useMemo(
() => (value: string) => {
//์ํฐ์ ์ํฐ ์ฌ์ด์ ์๋ ๊ธ์๋ค์ ์ํฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ์๋ผ์ ๋ฐฐ์ด์ ์ ์ฅ
const ArrayOfBetweenEnterValues = splitByEnter(value); //value.split(์ํฐ ๊ณจ๋ผ๋ด๋ ์ ๊ทํํ์)
//ํด๋น ๊ธ์๋ค์ ๊ธธ์ด๋ฅผ ๋ฐฐ์ด์ ์ ์ฅ
const ArrayOfLength = ArrayOfBetweenEnterValues.map(
values => +values.length
);
//๊ฐ์ฅ ๊ธด ๊ธ์์ ๊ธธ์ด๋ฅผ ์ ์ฅ
const maxLengthOfValues = Math.max(...ArrayOfLength);
//์์ ๊ธธ์ด์ ์ธ๋ฑ์ค === ๊ฐ์ฅ ๊ธด ๊ธ์์ ์ธ๋ฑ์ค
const indexOfMaxLength = ArrayOfLength.indexOf(maxLengthOfValues);
//๊ฐ์ฅ ๊ธด ๊ธ์์ byte๋ฅผ ๊ณ์ฐํ์ฌ return
return getByteOfValue(ArrayOfBetweenEnterValues[indexOfMaxLength]);
}, [value] );
๋ง์ todo ๋ค์ด ์๊ฒ ์ง๋ง ์ผ๋จ ๊ตฌ์ค์ ํ๋ค! ์ ๋๋ก ๋ง๋ค์ด ๋ณธ ๊ฐ๋ก ๋ฐ์ํ ํ
์คํธ ๋ฐ์ค ์ฝ๋ ์ค๋ช
์ ์ฌ๊ธฐ๊น์ง์
๋๋ค! ์ธ๋ก ๋ฐ์ํ๊ณผ ์๋ฐ์ํ ํ
์คํธ ๋ฐ์ค์ ๊ฒฝ์ฐ ์๋ ์ฝ๋๋ฅผ ๋งํฌ๋ก ๋จ๊น๋๋ค.
https://gist.github.com/Sleepingoff/879d368e87bb7e5f29585ab39561edd9
ํน์... ์ฌ๊ธฐ์์ ๋ ํ๊ณ ์ถ์ ๋ถ๋ค์ ์ํด ์๋ ค๋๋ฆฌ๋ ๋จ์ todo๋ค...์ ๋น์ํ ๋จ์ ๋๋ฐฉ์ถ
[ ] ์ต๋๊ฐ๊น์ง ๋ชจ๋ ์ฐฌ ํ
์คํธ ๋ฐ์ค์ ์คํฌ๋กค ๋ณด์ด๊ฒ ํ๊ธฐ
[ ] ๊ธ์๋ฅผ ์ง์ ์ ๋ colsํน์ rows์ ๋ํ ์ฒ๋ฆฌ
[ ] ์ต๋๊ฐ๊น์ง ๋ชจ๋ ์ฑ์ ์ง๋ง ๊ธ์๋ฅผ ์ง์ ๋ค์ ๋ฒ์ ๋ด๋ก ๋ค์ด์์ ๊ฒฝ์ฐ์ ๋ํ ์ฒ๋ฆฌ
[ ] width 100% ๋ฑ ์๋ ๋จ์์ ๋ํ ๋์(์ ์ํ)... cols๋ byte๊ฐ์ธ๋ฐ.. ๋ณํ ์ด๋ป๊ฒ ํด...
[ ] vertical, horizontal์ ๋ชจ๋ ์
๋ ฅํ์ง ์์์ ๋ ์๋ฌ์ฒ๋ฆฌ
[ ] ์ํฐ ์ ๊ทํํ์์ ๊ฑธ๋ฆฌ๋ ์ฌ์ฉ์์ ์
๋ ฅ ์ฒ๋ฆฌ
[ ] ๋งค์ฐ ๋ง์ useState ์ ๋ฆฌ
โ๏ธ๊ฒฐ๋ก
ํ์ง ์๋ ๊ฑฐ์๋ ์ด์ ๊ฐ ์๋ค.
๊ทผ๋ฐ ํ๋ฉด ๋ ์ฌ๋ฏธ์์ต๋๋ค. ์ํ ๊ธฐ๊ฐ์ ๋ด์งํ๋ ๋๋์ด๋ผ์ ์ง์ค์ด ์ ๋์๋ค์ใ
ใ
'Create' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์๊ณ ๋ฆฌ์ฆ] ์ด๊ฒ ๋๋ค...? (1) | 2024.06.03 |
---|---|
[์๊ณ ๋ฆฌ์ฆ] ๋ ๊ทธ๋๋ ํ๊ธด ํ์์ด...? (1) | 2024.05.30 |
[React] ๋ฆฌํฉํ ๋ง - ๋ฐ์ดํฐ/์ก์ /๊ณ์ฐ์ผ๋ก ๋ถ๋ฆฌํ๊ณ ์ฟผ๋ฆฌ ์คํธ๋ง์ ์ฌ์ฉํ์ (0) | 2024.05.08 |
[React] ์ปดํฌ๋ํธ๋ ํ ๋ฒ์ ํ๋์ ์ฑ ์๋ง ์ง๋ค. (0) | 2024.05.05 |
[package] ๋ ๋ญ ์๊ณ ์์๊น? (0) | 2024.04.28 |