: 프로그램은 순수 함수로 이루어져야한다는 선언형 프로그래밍 패러다임
: 동일한 입력(input)에 대해 항상 동일한 출력(output)을 반환하며, 부작용(side effect)이 없는 함수
const arr = [1, 2, 3];
function addElement(arr ele) {
arr.push(ele);
}
addElement(arr, 4);
console.log('original data', arr); // [1, 2, 3, 4]
// 전역 변수인 arr를 변경함
const arr = [1, 2, 3];
function addElement(arr ele) {
return [...arr, ele];
}
console.log('modified data', addElement(arr, 4)); // [1, 2, 3, 4]
console.log('original data', arr); // [1, 2, 3]
// 전역 변수인 arr을 변경하지 않고, 입력된 인자만으로 출력을 반환
- state의 변화와 mutation을 최소화한다.
- 외부 데이터로부터 함수를 독립적으로 유지한다.
- 함수를 일급 객체로 다룬다.
: React에서 상태(state)를 사용하여 입력 폼을 제어하는 방법
함수형 프로그래밍은 상태(state)를 변경하는 대신 불변성을 유지하고 상태를 업데이트하는 함수를 사용할 것을 강조한다.
그리고 제어 컴포넌트에서도 입력 폼의 상태를 변경할 때 순수 함수와 유사한 방식으로 처리한다.
제어 컴포넌트에서는 입력 폼의 상태를 변경할 때, 순수 함수인 useState
훅을 사용하여 불변성을 유지한다.
useState
는 새로운 상태를 반환하면서 기존 상태를 수정하지 않는다. 이를 통해 컴포넌트의 상태 변경을 추적하고 예측 가능하게 만들며, 순수 함수형 프로그래밍 원칙을 따르게 된다.
const ControlledComponent = () => {
const [value, setValue] = useState('');
const handleChange = (e) => {
setValue(e.target.value);
}
return (
<input
type='text'
value={value}
onChange={handleChange}
/>
);
}
: React에서 함수를 사용하여 UI를 작성하는 방법
함수 컴포넌트는 순수 함수로 작성되며, 동일한 입력에 대해 항상 동일한 결과를 반환한다.
const FunctionComponent = ({ name }) => {
return <h1>Hello, {name}!</h1>
}
: 컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수
HOC를 사용하여 컴포넌트의 재사용 가능한 로직을 추상화하고, 컴포넌트 간의 코드를 공유할 수 있다.
function App() {
return (
<>
<MyComponent message="hi" />
<EnhancedComponent message='hello'/>
</>
);
}
const withLogger = (WrappedComponent) => { // 인자로 컴포넌트를 받아서
return (props) => {
console.log('Component rendered:', WrappedComponent.name); // Component rendered: MyComponent
return <WrappedComponent {...props}/> // 새로운 컴포넌트를 반환한다.
}
}
const MyComponent = (props) => {
return <div>{props.message}</div>
}
const EnhancedMyComponent = withLogger(MyComponent);
: 자기 자신을 재귀적으로 호출하여 구성할 수 있는 컴포넌트
함수형 프로그래밍의 재귀적인 호출 개념을 사용한다.
function App() {
const nestedObject = {
A: 1,
B: {
b1: 2,
b2: {
b21: "Hello"
},
b3: {
b31: {
message: "Hi"
},
b32: {
message: "Hi"
}
}
},
C: {
c1: 3,
c2: 4
}
};
return <RecursiveComponent data={nestedObject} />;
}
인자로 받은 data가 객체인지 아닌지 판별하여
객체가 아닌 경우 <li>
태그로 감싸 리턴하고,
객체인 경우 [key, value] 쌍을 key는 <li>
, value는 <ul>
로 감싸 다시 RecursiveComponent로 전달한다.
const isObject = (x) => typeof x === "object" && x !== null;
// x는 객체이고, null이 아닌지 판별해주는 함수
export const RecursiveComponent = ({ data }) => {
if (!isObject(data)) {
return <li>{data}</li>;
} else {
const pairs = Object.entries(data); // [key, value] 페어 배열을 반환
return (
<>
{pairs.map(([key, value]) => (
<li>
{key}:
<ul>
<RecursiveComponent data={value} />
</ul>
</li>
))}
</>
);
}
};
: 여러 개의 컴포넌트를 조합하여 새로운 컴포넌트를 생성하는 방법
컴포넌트를 작은 단위로 분리하고 조합하여 재사용 가능한 코드를 작성하는 데 유용하다.
function App() {
return (
<>
<DangerButton text="Danger button" />
<BigSucessButton text="Big success button" />
</>
);
}
Button 컴포넌트는 size
, color
, text
등의 속성을 받아와서 버튼을 렌더링한다.
DangerButton과 BigSuccessButton은 Button 컴포넌트를 사용하여 새로운 컴포넌트를 생성하며 해당 컴포넌트에 props를 전달한다. 이렇게 Button 컴포넌트를 재사용하며 각각의 컴포넌트에서 필요한 속성을 설정할 수 있다.
const StyledButton = styled.button`
size: ${(props) => (props.size === "large" ? "32px" : "8px")};
font-size: ${(props) => (props.size === "large" ? "32px" : "16px")};
background-color: ${(props) => props.color};
`;
const Button = ({ size, color, text, ...props }) => {
return (
<StyledButton size={size} color={color}>
{text}
</StyledButton>
);
};
const DangerButton = (props) => {
return <Button {...props} color="red" />; // Button 컴포넌트 재사용
};
const BigSucessButton = (props) => {
return <Button {...props} size="large" color="green" />; // Button 컴포넌트 재사용
};
: 부분 적용된 컴포넌트는 인자를 일부 고정하고 새로운 컴포넌트를 생성하는 방법
function App() {
return (
<>
<DangerButton text="Partially applied danger button" />
<BigSuccessButton text="Partially applied big success button" />
</>
);
}
partiallyApplied
함수는 부분 적용된 컴포넌트를 생성하는 함수이다.
이 함수는 인자로 받은 컴포넌트에 일부 속성을 미리 적용한 새로운 컴포넌트를 반환한다.
이러한 방식을 사용하면 컴포넌트를 재사용하면서 일부 속성을 미리 지정할 수 있다.
const StyledButton = styled.button`
size: ${(props) => (props.size === "large" ? "32px" : "8px")};
font-size: ${(props) => (props.size === "large" ? "32px" : "16px")};
background-color: ${(props) => props.color};
`;
const partiallyApplied = (Component, partialProps) => {
return (props) => <Component {...partialProps} {...props} />;
};
const Button = ({ size, color, text, ...props }) => {
return (
<StyledButton size={size} color={color}>
{text}
</StyledButton>
);
};
const DangerButton = partiallyApplied(Button, { color: "red" }); // partiallyApplied 함수에 컴포넌트와 지정할 속성을 props로 전달한다.
const BigSuccessButton = partiallyApplied(Button, {
color: "green",
size: "large"
});
이때, BigSuccessButton의
partialProps
에는 {color: 'green', size: 'large'}
가 전달되고,
props
에는 {text: 'Partially applied big success button'}
이 담겨있다.
고생하셨네요! 저도 최근에 HOC 공부했었는데,, 쉽지 않더라구여 고생하셨네요!