데브코스에 중요한 활동중 하나인 딥다이브가 있다는 것을 시작하기전에 알게 되었고, 그렇다면 나는 무엇을 발표하면 좋을까 하는 생각을 했었습니다. 생각하다보니 작년 이맘때 쯤에 본 useEffect 관련 강연 영상이 떠올랐습니다. 해당 영상에 큰 인사이트를 얻었고, 그 인사이트를 통해 경험했던 것들을 나눠보고 싶었습니다. 그래서 React 강의 파트가 시작하기전까지 조금조금씩 준비를 하고 발표를 하게 되었습니다. 많이 떨렸지만 괜찮았겠죠..? 괜찮은 내용이였겠죠?
발표를 준비하는 과정에서, 발표를 하는 과정에서 다른 사람에게 경험을 공유하고 지식을 공유하는 것도 매우 보람찼지만, 스스로의 지식을 정비할 수 있었다는 것도 매우 보람찼던 것 같습니다. 어디서든 “react hook 어느정도 알고 있어요.” 라고 말할 수 있게 된 것 같습니다. 실제로도 무언가 다른 사람들과 react 에 대해서 토론을 하게 될 때 좀 더 근거있는 의견을 낼 수 있게 된 것 같습니다. 혼자 공부하고 정리하는 것도 좋지만 다른 사람들과 공유하는 것도 매우 도움이 되는 것 같네요.
첫 공식 오피셜 오프라인 모각코? 가 진행되었습니다. 저는 매우 먼 남쪽나라에 있어서, 참가할 의사가 없었지만 팀원분들의 회유와…제주도에서도 오신다는 분의 소식을 듣고 안갈수가 없더라구요. 그래서 참가하게 됐습니다.
참가하길 잘 한 것 같습니다!
온라인으로 뵈는것과 오프라인으로 뵈는 것은 정말 큰 차이가 있네요. (이래서 회사 출근하는 걸 좋아했던 걸까요?) 이전 팀원분들도 너무 반가웠고 현재 팀원분들과는 한 층 더 가까워진 것 같아서 좋았습니다. 또 오프라인이라서 가능했던 실시간 토론도 너무 인상 깊었구요. 덕분에 useEffect 의 실행시점은 절대 안 까먹을 것 같네요.
저는 MBIT 가 INFP 랍니다. INFP 를 결정 짓는 중요한 질문 중 하나가 ”모임에 참석한다면 어디에 위치하고 싶으신가요?” 이라고 생각하는데 저는 고민1도 없이 구석 기둥 쪽을 선택하는 편이랍니다.
하지만… 많은 분들이 저에게 인사를 하러 와주셔서 얼마나 감사하고.. 얼마나 부끄럽고 쑥스러웠던지… 저는 인사를 하러 아무 에게도 가지 않았지만…ㅠㅠ 죄송한 마음이 드네요.. 나름 데브코스에서 긍정적인 영향을 조금이나마 행사한게 아닌가.. 하는 생각을 감히 해본답니다.
const childrenToArray = (children, types) => {
return React.Children.toArray(children).filter((element) => {
if (React.isValidElement(element) && types.includes(element.props.__TYPE)) {
return true;
}
console.warn(
`Only accepts ${
Array.isArray(types) ? types.join(", ") : types
} as it's children.`
);
return false;
});
};
const childrenToArray = (children, types) => {
return React.Children.toArray(children).filter((element) => {
if (React.isValidElement(element) && types.includes(element.props.__TYPE)) {
return true;
}
console.warn(
`Only accepts ${
Array.isArray(types) ? types.join(", ") : types
} as it's children.`
);
return false;
});
};
const Tab = ({ children, active, ...props }) => {
const [currentActive, setCurrentActive] = useState(() => {
if (active) {
return active;
} else {
const index = childrenToArray(children, "Tab.Item")[0].props.index;
return index;
}
});
const items = useMemo(() => {
return childrenToArray(children, "Tab.Item").map((element) => {
return React.cloneElement(element, {
...element.props,
key: element.props.index,
active: element.props.index === currentActive,
onClick: () => {
setCurrentActive(element.props.index);
},
});
});
}, [children, currentActive]);
const activeItem = useMemo(
() => items.find((element) => currentActive === element.props.index),
[currentActive, items]
);
return (
<div>
<TabItemContainer>{items}</TabItemContainer>
<div>{activeItem.props.children}</div>
</div>
);
};
Tab.Item = TabItem;
export default Tab;
children 컴포넌트를 렌더링 하기 전에 타입을 검사해서 허용된 자식 컴포넌트인지 확인을 하고 필터링을 한 뒤 해당 자식컴포넌트들을 복사하는 과정에서 필요한 props 들을 지정해서 사용하는 패턴 입니다. 해당 방식은 이번 강의를 통해서 알게된 방식이고, 매우 유용할 것 같아서 커스텀 훅으로 재사용성을 높여보고 싶었습니다.
const useValidateChildren = ({ children, types, cloneFn }) => {
const filteredChildren = React.Children.toArray(children).filter((child) => {
if (React.isValidElement(child) && types.includes(child.props.__TYPE))
return true;
console.warn(
`Only accepts ${
Array.isArray(types) ? types.join(", ") : types
} as it's children.`
);
return false;
});
const clonedChildren = useMemo(
() => cloneFn(filteredChildren),
[filteredChildren, cloneFn]
);
return { filteredChildren, clonedChildren };
};
export default useValidateChildren;
우선 기존 컴포넌트에 구현된 childrenToArray 함수를 그대로 사용해서 types 에 허용된 type 만을 가지는 자식 컴포넌트들을 걸러 냅니다. 그 후 걸러진 자식 컴포넌트들을 사용해서 clone 된 자식 컴포넌트들을 생성하고, 필터링된 자식컴포넌트, 클론된 자식 컴포넌트를 훅의 반환 값으로 사용 했습니다. 이를 사용하면 다음과 같이 기존 코드를 작성할 수 있게 됩니다.