여러 곳에서 사용하는 공통된 컴포넌트의 모든 자식 요소에 props를 전달하고 싶었다.
export const CommonComponent = () => {
const [state, dispatch] = useReducer(reducer, {
status: status || 'enable',
});
return (
<div>
{children} // status를 children에게 모두 전달하고 싶다!
</div>
)
}
function reducer(state: any, action: any) {
switch (action) {
case 'mouse_enter':
return {
...state,
status: 'hover',
};
case 'mouse_leave':
return {
...state,
status: 'enable',
};
}
return state;
}
굳이 Provider를 만들고 싶지 않았는데, 찾다가 새로운 걸 발견했다.
https://react.dev/reference/react/cloneElement#cloneelement
cloneElement를 이용해서 아래와 같이 전달하고 싶은 props를 지정할 수 있었다.
export const CommonComponent = () => {
const [state, dispatch] = useReducer(reducer, {
status: status || 'enable',
});
return (
<div>
{cloneElement(children, { status: state.status })}
</div>
)
}
function reducer(state: any, action: any) {
switch (action) {
case 'mouse_enter':
return {
...state,
status: 'hover',
};
case 'mouse_leave':
return {
...state,
status: 'enable',
};
}
return state;
}
하지만 기본적으로 cloneElement는 추천되지는 않는다.
왜냐하면, props가 전달되고 있는지 상위 컴포넌트에서는 코드만 보고 알 수 없기 때문이다.
따라서, 좋은 코드가 아니다.
이러한 대안을 이용해서 아래처럼 다시 수정해보았다.
interface Props {
status: 'enable' | 'active' | 'hover';
children: (status: 'enable' | 'active' | 'hover') => JSX.Element;
}
export const CommonComponent = ({ status, icon }: Props) => {
const [state, dispatch] = useReducer(reducer, {
status: status || 'enable',
});
return (
<div>
{children(state.status)}
</div>
)
}
function reducer(state: any, action: any) {
switch (action) {
case 'mouse_enter':
return {
...state,
status: 'hover',
};
case 'mouse_leave':
return {
...state,
status: 'enable',
};
}
return state;
}