React list component with Redux - TEAM-ARK/inflearn-clone-front GitHub Wiki
- 컴포넌트에 list 자체를 전달해서 컴포넌트 안에서 처리 하는 방법
- 좋지 않음 : 기존에 설정된 값들(store read-only 속성제거)을 변경해야 함(방금 작업한 코드)
// course_info.tsx
const [textArray, setTextArray] = useState<string[]>();
<TextListBox list={textArray} setTextArray={setTextArray} />;
// TextListBox.tsx
type Prop = {
list?: string[];
setTextArray: React.Dispatch<React.SetStateAction<string[] | undefined>>;
};
const TextListBox = ({ list = [], setTextArray }: Prop) => {
const onClickDelete = (textList: string[], index: number) => {
textList.splice(index, 1);
setTextArray([...textList]);
console.log('after remove', textList);
};
return (
<button onClick={() => onClickDelete(list, index)} type="button">
<DeleteIcon />
</button>
);
};
- 컴포넌트 밖에서 array.map() 을 사용해서 그리기 : good
- redux에서 read-only로 설정한 것을 해치지 않으면서 강제로 re-rendering을 위해 useState를 억지로 사용하지 않아도 된다.
- 단, 각 경우에 맞게 dispatch를 다르게 날려서 원하는 데이터가 변경된 것을 반영하도록 해줘야 한다.
1. read-only의 불변성 보장
// course_info.tsx -> 재사용 컴포넌트의 부모 컴포넌트에서 map을 사용
// 대신 onClick 을 전달
<ul>
{lectureData?.courseInfo.whatYouCanLearn.map((item, index) => (
<TextListBox
key={index}
item={item}
onClick={() => onClickTextBoxDelete(lectureData?.courseInfo.whatYouCanLearn, index, 'whatYouCanLearn')}
/>
))}
</ul>
const onClickTextBoxDelete = (
textList: string[],
index: number,
boxType: 'whatYouCanLearn' | 'expectedStudents' | 'requiredKnowledge'
) => {
// textList.splice(index, 1); // slice를 사용해서 기존의 read-only를 해치지 않게 해야 함
const textArray = [...textList];
textArray.splice(index, 1);
// dispatch() 각각 다르게 만들어서 사용
switch (boxType) {
case 'whatYouCanLearn':
dispatch({
type: DELETE_ITEM_WHATYOUCANLEARN,
data: textArray,
});
break;
case 'expectedStudents':
break;
case 'requiredKnowledge':
break;
default:
console.error('boxType is wrong');
}
console.log('after remove', textList);
};
1방식에서 list를 직접 전달할 땐 불변성을 지키지도 않고 redux store의 값을 직접 변경했지만 2번 방법에서 불변성을 지키고 reducer를 사용해서 데이터를 변경하니 자동으로 렌더링까지 됨
- 재사용 컴포넌트엔 list를 전달하기 보단 그 부모 컴포넌트에서 list의 map method를 이용하여 컴포넌트를 재사용하는 것이 올바른 방법이다.