0. task 코드 간결화
return (
<ThemeProvider theme={theme}>
<Container>
<StatusBar
backgroundColor={theme.background}
barStyle="light-content"
/>
<Title>ToDo List</Title>
<Input
placeholder="+ Add a Task"
value={newTask}
onChangeText={text => setNewTask(text)}
onSubmitEditing={addTask}
></Input>
<List width={width}>
{Object.values(tasks)
.reverse()
.map(item => {
return <Task key={item.id} item={item} />;
})}
</List>
</Container>
</ThemeProvider>
);
1. 기능 구현하기 - 추가
- sample date 만들기
배열로 만들거라 생각했는데 객체로 생성한점이 다르다.
const tempData = {
1: { id: '1', text: 'react native', completed: false },
2: { id: '2', text: 'expo', completed: true },
3: { id: '3', text: 'javascript', completed: false },
};
const [tasks, setTasks] = useState(tempData);
const addTask = () => {
if (newTask.length < 1) {
return;
}
const ID = Date.now().toString();
const newTaskObject = {
[ID]: { id: ID, text: newTask, completed: false },
};
setTasks({ ...tasks, ...newTaskObject });
alert('새로운 할일이 추가되었습니다.');
setNewTask('');
};
.......
return (
<ThemeProvider theme={theme}>
<Container>
<StatusBar
backgroundColor={theme.background}
barStyle="light-content"
/>
<Title>ToDo List</Title>
<Input
placeholder="+ Add a Task"
value={newTask}
onChangeText={text => setNewTask(text)}
onSubmitEditing={addTask}
></Input>
2. 기능 구현하기 - 삭제
- 삭제 함수 작성
데이터 삭제시 기존 데이터 유지하기 위하여 사본 데이터 생성
편하게 삭제하기 위하여 delete 메소드 사용
(이를 위해 객체형태로 tempData 를 만들었음.)
const deleteTask = id => {
const currentTasks = Object.assign({}, tasks);
delete currentTasks[id];
setTasks(currentTasks);
};
return (
<ThemeProvider theme={theme}>
<Container>
<StatusBar
backgroundColor={theme.background}
barStyle="light-content"
/>
<Title>ToDo List</Title>
<Input
placeholder="+ Add a Task"
value={newTask}
onChangeText={text => setNewTask(text)}
onSubmitEditing={addTask}
></Input>
<List width={width}>
{Object.values(tasks)
.reverse()
.map(item => {
return <Task key={item.id} item={item} deleteTask={deleteTask} />;
})}
</List>
</Container>
</ThemeProvider>
);
const Task = ({ item, deleteTask }) => {
return (
<Container>
<IconButton icon={icons.check} />
<Contents>{item.text}</Contents>
<IconButton icon={icons.edit} />
<IconButton icon={icons.delete} id={item.id} onPress={deleteTask} />
</Container>
);
};
- 삭제 함수 보충
혼자 했으면 상위단에서 작성했을거 같고 delete 함수 등을 따로 전달했을거 같으나 한번에 처리할수 있게 코드를 만들었음.
const IconButton = ({ icon, onPress, id }) => {
const _onPress = () => {
onPress(id);
};
return (
<TouchableOpacity onPress={_onPress}>
<View>
<Icon source={icon}></Icon>
</View>
</TouchableOpacity>
);
};
3. 기능 구현하기 - 완료
- 완료 함수 작성 및 전달
객체명[속성명].속성명 또는 객체명[속성명]['속성명']
const toggleTask = id => {
const currentTasks = Object.assign({}, tasks);
currentTasks[id].completed = !currentTasks[id].completed;
setTasks(currentTasks);
};
.......
<List width={width}>
{Object.values(tasks)
.reverse()
.map(item => {
return (
<Task
key={item.id}
item={item}
deleteTask={deleteTask}
toggleTask={toggleTask}
/>
);
})}
</List>
const Contents = styled.Text`
flex: 1;
font-size: 24px;
// completed 에 따라 글자 색상 변경
color: ${({ theme, completed }) => (completed ? theme.done : theme.text)};
// completed 에 따라 글자 데코레이션 추가
text-decoration-line: ${({ completed }) =>
completed ? 'line-through' : 'none'};
`;
const Task = ({ item, deleteTask, toggleTask }) => {
return (
<Container>
<IconButton
icon={item.completed ? icons.check : icons.uncheck}
item={item}
onPress={toggleTask}
/>
<Contents completed={item.completed}>{item.text}</Contents>
{item.completed === false ? <IconButton icon={icons.edit} /> : null}
<IconButton icon={icons.delete} item={item} onPress={deleteTask} />
</Container>
);
};
const Icon = styled.Image`
width: 30px;
height: 30px;
margin: 10px;
tint-color: ${({ theme, completed }) =>
completed ? theme.done : theme.text};
`;
const IconButton = ({ icon, onPress, item }) => {
const _onPress = () => {
onPress(item.id);
};
return (
<TouchableOpacity onPress={_onPress}>
<View>
<Icon source={icon} completed={item.completed}></Icon>
</View>
</TouchableOpacity>
);
};
IconButton.proptype = {
icon: propTypes.oneOf(Object.values(icons)).isRequired,
onPress: propTypes.func,
item: propTypes.object,
};
IconButton.defaultProps = {
item: { completed: false },
};
export default IconButton;
4. 기능 구현하기 - 수정
const updateTask = item => {
const currentTasks = Object.assign({}, tasks);
currentTasks[item.id] = item;
setTasks(currentTasks);
};
.......
<List width={width}>
{Object.values(tasks)
.reverse()
.map(item => {
return (
<Task
key={item.id}
item={item}
deleteTask={deleteTask}
toggleTask={toggleTask}
updateTask={updateTask}
/>
);
})}
</List>
- 수정 버튼 클릭시 Task 컴포넌트는 Input 컴포넌트로 변경
변경되면서 기존 item.text가 나와야 하며
완료시 다시 Task 컴포넌트 로 변경되어야 한다.
const Task = ({ item, deleteTask, toggleTask, updateTask }) => {
const [isEditing, setIsEditing] = useState(false);
const [text, setText] = useState(item.text);
const _onSubmit = () => {
if (isEditing) {
const updatedItem = Object.assign({}, item);
updatedItem.text = text;
setIsEditing(false);
updateTask(updatedItem);
}
};
return isEditing ? (
<Input
value={text}
onChangeText={text => setText(text)}
onSubmitEditing={_onSubmit}
onBlur={() => {
setText(item.text);
setIsEditing(false);
}}
/>
) : (
<Container>
<IconButton
icon={item.completed ? icons.check : icons.uncheck}
item={item}
onPress={toggleTask}
/>
<Contents completed={item.completed}>{item.text}</Contents>
{item.completed || (
<IconButton icon={icons.edit} onPress={() => setIsEditing(true)} />
)}
<IconButton icon={icons.delete} item={item} onPress={deleteTask} />
</Container>
);
};
Task.propTypes = {
item: propTypes.object.isRequired,
deleteTask: propTypes.func.isRequired,
toggleTask: propTypes.func.isRequired,
updateTask: propTypes.func.isRequired,
};
export default Task;