문제 1. (FirstTemplate 에 작성합니다.)
const FirstTemplate: Story<IButtonProps> = (args) => {
return (
<>
<Button size="small" variant="outlined" color="primary">
Primary
</Button>
<Button size="medium" variant="contained" color="secondary">
Secondary
</Button>
<Button size="large" variant="text" color="error">
Error
</Button>
</>
);
};
문제 2. (SecondTemplate 에 작성합니다.)
const SecondTemplate: Story<IButtonProps> = (args) => {
const [text, setText] = useState<string | number>;
const handleChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
setText(e.target.value);
}, []);
return (
<div>
<Input value={text} onChange={handleChange}> />
<Button disabled={!text}>Submit</Button>
</div>
);
};
문제 3. (ThirdTemplate 에 작성합니다.)
// 수정 전
const ThirdTemplate: Story<IButtonProps> = (args) => {
const buttons = useMemo(() => {
return [
{ number: 1, id: 'red'},
{ number: 2, id: 'green'},
{ number: 3, id: 'blue'},
];
}, []);
const [changeButtonStyle, setChangeButtonStyle] = useState<String>('blue');
const onButtonStyleChange = useCallback((e) => {
const { id } = e.target;
setChangeButtonStyle(id);
}, []);
return (
<div>
<Thing theme={changeButtonStyle} />
<div className="interface">
{buttons.map((button)=>{
return(
<Button key={button.id} id={button.id} onClick={onButtonStyleChange}>
{button.number}
</Button>
);
})}
</div>
</div>
);
}
// 코멘트 수정 후
const ThirdTemplate: Story<IButtonProps> = (args) => {
// 아래 콜백 함수가 Arrow Function일 경우 블록 레벨에서 실행될 로직이 없으면 바로 리턴한다.
// Arrow Function에 대해 알아보기.
const buttons = useMemo(
() => [
{ number: 1, id: 'red' },
{ number: 2, id: 'green' },
{ number: 3, id: 'blue' }
],
[],
);
// typescript string 타입은 String (x) --> string (o)
const [changeButtonStyle, setChangeButtonStyle] = useState<string>('blue')
// event에도 가능하면 타입을 바인딩 해주자
// target 이 아니라 currentTarget으로 접근해야 id를 받아올 수 있다. target과 currentTarget의 차이점 조사하기.
const onButtonStyleChange = useCallback(({ currentTarget }) => {
const { id } = currentTarget;
setChangeButtonStyle(id);
},[]);
// 실 매개변수도 구조분해가 가능하다.
// Arrow Function에서 내부 로직 없이 바로 return 할때 블록으로 감싸서 명시적으로 return하는 경우 가독성이 떨어진다.
return (
<div>
<Thing changeButtonStyle={changeButtonStyle} />
<div className="interface">
{buttons.map(({ id, number }) => (
<Button key={id} id={id} onClick={onButtonStyleChange}>
{number}
</Button>
))}
</div>
</div>
);
}
// 수정 전 styled component 코드
import styled from "@emotion/styled";
export const Thing = styled.div<{theme: String}>`
width: ${({ theme })=> theme ==="blue"? "60px": theme === "red"? "30px": "90px"};
height: ${({ theme })=> theme ==="blue"? "60px": theme === "red"? "30px": "90px"};
border-radius: 25px;
background-color: ${({ theme })=> theme ==="blue"? "blue": theme === "red"? "red": "green"};
`
// 코멘트 수정 후
import styled from '@emotion/styled';
// props로 받으려고 제네릭으로 type을 주기 --> styled.div<{ state명: type명 }>
export const Thing = styled.div<{ changeButtonStyle: string }>`
width: ${({ changeButtonStyle }) =>
changeButtonStyle === 'blue' ? '60px' : changeButtonStyle === 'red' ? '30px' : '90px'};
height: ${({ changeButtonStyle }) =>
changeButtonStyle === 'blue' ? '60px' : changeButtonStyle === 'red' ? '90px' : '90px'};
border-radius: 25px;
background-color: ${({ changeButtonStyle }) =>
changeButtonStyle === changeButtonStyle};
`;
# Arrow Function
전통적인 함수표현의 간단한 대안책이지만 모든 상황에 사용할 순 없다.
- this나 super에 대한 바인딩이 없으며 methods로 사용 안됨
- new.target 키워드가 없다
- 스코프 지정할 때 사용하는 call, apply, bind methods 이용 불가
- 생성자(Constructor)로 사용 불가
- yield를 화살표 함수 내부에서 사용 불가
구문
기본 구문
(param1, param2, ..., paramN) => { statements }
(param1, param2, ..., paramN) => expression
// 다음과 같다: => { return expression; }
// 매개변수가 하나면 괄호는 선택사항이다:
(singleParam) => { statements }
singleParam => { statements }
// 매개변수가 없는 함수는 괄호가 필요하다:
() => { statements }
고급 구문
// 객체 리터럴 표현 반환 위해 함수 본문(body)을 괄호에 넣는다:
params => ({foo: bar})
// 나머지 매개변수, 기본 매개변수 지원
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, ..., paramN = defaultValueN) => { statements }
// 매개변수 목록 내 구조분해할당도 지원됨
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); //6
짧게 함수 표현하는 방법
var elements = [
'Hydrogen',
'Helium',
'Lithium',
'Beryllium'
];
// 배열을 반환하는 map함수
elements.map(function(element) {
return element.length;
});
// 위 함수를 아래와 같이 쓸 수 있다
elements.map((element) => {
return element.length;
});
// 파라미터 하나 --> 괄호생략
elements.map(element => {
return element.length;
});
// 화살표 함수에 문장이 유일하면 return, {} 생략
elements.map(element=> element.legnth);
// 이런 경우 length 속성만 필요함 --> 구조분해 할 수 있다. (destructing 매개변수 사용)
elements.map(({ length: lengthFooBArX }) => lengthFooBArX);
// destructuring 파라미터 할당도 가능
elements.map(({ length }) => length);
# currentTarget
currentTarget는 읽기전용 속성이다. Event가 DOM을 통과할 때 이벤트의 현재 대상을 식별한다. 항상 이벤트 핸들러가 첨부된 요소 (이벤트가 걸려져있는 위치)를 참조하고 이벤트가 발생한 요소, 그 자식 요소를 식별한다. event.target은 실제 이벤트가 발생하는 위치, 내가 클릭한 요소를 반환한다. event.currentTarget과 event.target이 같을 수도 있지만 이벤트 위임을 통한 이벤트에서는 두 개가 다른 값을 가질 수 있다.
참고: 이벤트 버블링, 위임 target과 currentTarget차이, MDN: Event.currentTarget
# 회고
일단 작동하는 코드를 구현한 뒤에 코드를 고쳐나가는 방식으로 과제를 수행했다. Prettier가 설치는 되어있었지만 설정을 제대로 안해주었는데, 저장하면서 설정이 안먹히는것 같다 생각했는데 바로 여쭤 봤어야 했는데, 그냥 넘어갔던 점이 아쉽다. 다음엔 의문이 들때 바로 질문을 해야겠음. type지정을 하면서 코드를 작성 해 보는것이 처음이었는데 기존에 있는 코드들을 참고하면서 적용해 나가니 혼자 공부할 때 막막했던 때 보다 훨씬 수월했다. useMemo, useCallback을 추후 컴포넌트 최적화를 고려하여 사용하는 연습을 해 보았는데, 이 것을 어떻게 하면 최적화가 되었는지 확인할 수 있는지 알아봐야겠다. 참고 자료를 주셔서 해당 자료들을 바탕으로 좀 더 공부해야 봐야겠음
'공부 정리' 카테고리의 다른 글
23.01.11: dependency array에는 언제, 뭘 넣어주어야 할까 (useEffect, useMemo, useCallback) (0) | 2023.01.11 |
---|---|
23.01.10: React-hook-form 이용한 form 구현(React storybook, typescript) (0) | 2023.01.11 |
22.12.29: 프로그래머스_다음에 올 숫자 (0) | 2022.12.29 |
22.12.28: 프로그래머스_옹알이(1) (0) | 2022.12.29 |
22.12.21: 타입스크립트 타입들 - Union, Any, Unknown (0) | 2022.12.21 |