To-Do App (2)

Sang heon lee·2022년 2월 16일
0

0. task 코드 간결화

// App.js
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 만들기
    배열로 만들거라 생각했는데 객체로 생성한점이 다르다.
// App.js
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);
  • 추가 함수 작성 및 전달
// App.js
  const addTask = () => {
    // 빈 문자열 방지
    if (newTask.length < 1) {
      return;
    }

    // 현재 시간대로 ID 설정
    const ID = Date.now().toString();

    // 새로운 task 객체 생성
    const newTaskObject = {
      [ID]: { id: ID, text: newTask, completed: false },
    };

    // 기존 tasks 에 새로운 task 추가
    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 를 만들었음.)

// App.js
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>
  );
  
// Task.js
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 함수 등을 따로 전달했을거 같으나 한번에 처리할수 있게 코드를 만들었음.
// IconButton.js
const IconButton = ({ icon, onPress, id }) => {
  const _onPress = () => {
    onPress(id);
  };

  return (
    <TouchableOpacity onPress={_onPress}>
      <View>
        <Icon source={icon}></Icon>
      </View>
    </TouchableOpacity>
  );
};  

3. 기능 구현하기 - 완료

  • 완료 함수 작성 및 전달
    객체명[속성명].속성명 또는 객체명[속성명]['속성명']
// App.js
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>
  • Task 함수 수정
// Task.js

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>
      // completed 에 따라 이미지 변경 및 함수 전달
      <IconButton
        icon={item.completed ? icons.check : icons.uncheck}
        item={item}
        onPress={toggleTask}
      />
      <Contents completed={item.completed}>{item.text}</Contents>
      // completed 에 따라 edit 이미지 표시/숨김
      {item.completed === false ? <IconButton icon={icons.edit} /> : null}
      <IconButton icon={icons.delete} item={item} onPress={deleteTask} />
    </Container>
  );
};
  • IconButton 수정
// IconButton.js
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,
};

// edit IconButton 의 경우 item props가 전달되지 않기에 추가
IconButton.defaultProps = {
  item: { completed: false },
};

export default IconButton;

4. 기능 구현하기 - 수정

  • 수정 함수 작성 및 전달
// App.js
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;
profile
개초보

0개의 댓글

관련 채용 정보