원시 탑입은 불변성을 가지고 있고 참조타입은 가지고 있지않다.
- 원시타입 : Boolean, String ... (불변성O)
- 참조타입 : Object, Array (주소값을 저장한다)
결론 : 원시는 실제 변경 X, 참조는 실제 변경 O
- 참조 타입에서 객체난 배열의 값이 변할 때 원본 데이터가 변경되기에 이 원본 데이터를 참조하고 있는 다른 객체에서 예상치 못한 오류가 발생할 수 있어서 프로그래밍 복잡도가 올라간다.
- 리액트에서 화면을 업데이트할 때 불변성을 지켜서 값을 이전 값과 비교해서 변경된 사항을 확인한 후 업데이트하기 때문에 불변성을 지켜줘야 한다.
참조 타입에서는 값을 바궜을 때 Call Stack 주소 값은 같은데 Heap 메모리 값만 바뀌기에 불변성 유지 불가하므로 아예 새로운 배열을 반환하는 메소드 사용
- spread operator, map, filter, slice, reduce ...
원본 데이터 변경 메소드 => splice, push !
List안에 각 리스트들을 컴포넌트로 생성하기 위해
Lists.js라는 파일을 새로만든다.
원래 s빼야하는데 기존에 있던걸 List라고해서 Lists로 진행하자 !
그러고 list div들을 빼고 필요 함수들을 Lists.js로 옮겨주고
List.js에서는 < Lists /> 해서 컴포넌트를 불러와주면 끝 !
그러고 필요한 값들을 List.js에서 전달해주자
//rfce
import React from 'react'
const Lists = (
{id,title,completed,todoData,setTodoData,provided,snapshot}
) =>{
const handleCompleteChange = (id) =>{
let newTodoData = todoData.map(data=>{
if(data.id === id){
data.completed = !data.completed;
}
return data;
});
setTodoData(newTodoData);
this.setState({todoData:newTodoData});
};
//할일 목록 삭제 함수
const hanndleClick=(id)=>{
//filter method를 사용해서
//id가 같은거를 필터링 해버리자
let newTodoData = todoData.filter(data=> data.id !== id);
console.log('newTodoData',newTodoData);
//list의 id가 와서 데이터의 아이디가 아닌것만 트루를 반환해서 살린다
setTodoData(newTodoData);
};
return (
<div
key={id}
{...provided.draggableProps}
ref={provided.innerRef}
{...provided.dragHandleProps}
className={`${snapshot.isDragging ? "bg-gray-400":"bg-gray-100"} flex items-center justify-between w-full px-4 py-2 my-2 text-gray-600 border rounded`}
>
<div className="items-center" >
<input type="checkbox" defaultChecked={completed} onChange={()=>handleCompleteChange(id)}></input>
<span className={completed ? "line-through" :undefined}>{title}</span>
</div>
<div className="items-center">
<button className="px-4 py-2 float-right" onClick={()=>hanndleClick(id)}>X</button>
</div>
</div>
)
}
export default Lists
// rfc 엔터하면 함수형 컴포넌트 만들기 가능
import React from 'react'
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
import Lists from './Lists';
export default function List({todoData, setTodoData}) {
const handleEnd = (result) =>{
//result 매개변수에는 source 항목 및 대상 위치와 같은 드래그 이벤트에 대한 정보가 포함됩니다.
console.log(result);
// 목적지가 없으면 함수 종료
if(!result.destination) return;
// 리액트 불변성 지키기 위한 새로운 tododata생성
const newTodoData = todoData;
// 1. 변경시키는 아이템을 배열에서 지움
// 2. return 값으로 지워진 아이템을 잡음
const [reorderItem] = newTodoData.splice(result.source.index, 1);
// 원하는 자리에 reoderedItem을 invert 한다
newTodoData.splice(result.destination.index, 0, reorderItem);
setTodoData(newTodoData);
};
return (
<div>
{/* // this는 클래스를 가리키고 클래스 안에 todoData라는 리스트객체를 가지고 와서 그 안에 데이터를 꺼내는데 map함수를 써서 꺼낸다
// map은 객체별 요소를 data라는 변수로 정해주고 data객체 안에 id,completed,title을 가져온다
// style같은경우도 겹치는 경우가 많으니 this를 사용해서 클래스 내에 만들어둔 스타일을 가지고 와서 사용한다
// react에서는 반복되는 값들을 가지고올때 유니크한 값와 같은 key값을 줘야한다 */}
<DragDropContext onDragEnd={handleEnd}>
<Droppable droppableId="todo">
{(provided)=> (
<div {...provided.droppableProps} ref={provided.innerRef}>
{todoData.map((data,index)=>(
<Draggable
key={data.id}
draableId={data.id.toString()}
index={index}
>
{(provided,snapshot)=>(
<Lists
key={data.id}
id={data.id}
title={data.title}
completed={data.completed}
todoData={todoData}
setTodoData={setTodoData}
provided={provided}
snapshot={snapshot}
/>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
</div>
)
}
이렇게 된다..!
현재 투두앱은 컴포넌트가 나눠져있다
이렇게 나눠진 이유는 재사용성을 위해서이기도 하지만 각 컴포넌트의 렌더링 최적화를 위해서이다.
예를들어 Form에서 글을 타이핑 할 때 원래는 Form컴포넌트와 그 State값을 가지고 있는 App 컴포넌트만 렌더링 돼야하는데 현재는....
다 렌더링되고 있는 문제점이 있다..
이 문제점을 React.memo를 통해 해결하자
React.memo를 감싸주고,
이렇게 Lists.js,List.js를 모두 감싸주면된다.
함수를 만들때 최상위 컴포넌트에 자주 만든다!
handleClick함수를 제일 최상위 컴포넌트 App.js로 옮겨주자
그러면 App.js->List.js->Lists.js로 하나씩 전달해줘야지
Lists.js가 handleClick함수를 App.js에서 가져올 수 있다.
그래서handleClick함수를 useCallback으로 감싸주면
const hanndleClick=useCallback((id)=>{
//filter method를 사용해서
//id가 같은거를 필터링 해버리자
let newTodoData = todoData.filter(data=> data.id !== id);
console.log('newTodoData',newTodoData);
//list의 id가 와서 데이터의 아이디가 아닌것만 트루를 반환해서 살린다
setTodoData(newTodoData);
},
[todoData] //todoData가 변할때만 다시생성할 수 있게한다!
);
이렇게 감싸주고 두번째 인수로 todoData를 전달하여 데이터가 변할때마다만 다시 생성 할 수 있게 만들어 준다.
메모이제이션은 비용이 많이 드는 함수 호출의 결과를 저장하고 동일한 입력이 다시 발생할 때 캐시된 결과를 반환하여 컴퓨터 프로그램의 속도를 높이는데 주로 사용되는 최적화 기술
useMemo로 감싸준 후에 첫번째 인수에 의존성 배열에 compute 함수에서 사용하는 값을 넣어준다.
이런걸 추가하면 리액트 검사할때 좋당