• 카테고리

    질문 & 답변
  • 세부 분야

    모바일 앱 개발

  • 해결 여부

    해결됨

Task 컴포넌트의 기능구현하기 삭제에서

21.11.28 16:01 작성 조회수 161

1

Task 컴포넌트의 기능구현하기 삭제에서
삭제아이콘을 누르면 전부 지워집니다
또한 이런 에러메세지가 뜨네요
 
Warning: Each child in a list should have a unique "key" prop.
 
또 님의 깃헙에서 질문을 올리려면
어떻게 하는지 잘 모르오니 갈켜주시와요
 
소스파일
App.jsty
 
import {StatusBar, Dimensions} from 'react-native';
import React, {useState} from 'react';
import {Text, View, LogBox} from 'react-native';
import styled, {ThemeProvider} from 'styled-components/native';
import {theme} from './src/theme';
import Input from './src/input';
import Task from './src/Task';

const Container = styled.SafeAreaView`
     flex: 1;
     background-color: ${({theme}) => theme.background};
     align-items: center;
     justify-content: flex-start;
     padding: 30px;
`;
const Title = styled.Text`
     font-size: 30px;
     font-weight: 600;
     color: ${({theme}) => theme.main};
     width: 100%;
     align-items: flex-end;
     padding: 0 20px;
`;

// 목록의 스크롤바를 스타일링
const List = styled.ScrollView`
     flex: 1;
     width: ${({width}) => width - 40}px; //목록화면의 좌우마진을 20으로 줌
`;

LogBox.ignoreLogs(['Remote debugger']);
export default function App() {
     const width = Dimensions.get('window').width;
     const tempData = {
          // Task list
          1: {id: '1', text: '리액트네이티브', completed: false},
          2: {id: '2', text: 'Expo', completed: true},
          3: {id: '3', text: '자바', completed: false},
     };
     const [tasks, setTasks] = useState(tempData);
     const [newTask, setNewTask] = useState('');

     // Task 목록추가하기
     const addTask = () => {
          if (newTask.length < 1) {
               // 공백인 자료입력시 추가가 않되게 함
               return;
          }
          const ID = Date.now().toString(); // 현재시간의 타임스탬프
          const newTaskObject = {
               [ID]: {id: ID, text: newTask, completed: false},
          };
          // alert(newTaskObject);
          setNewTask('');
          setTasks({...tasks, ...newTaskObject});
     };

     // 선택된 Task 삭제
     const deleteTask = (id) => {
          console.log(id);
          // 현재 Task항목들의 객체와 동일한 변수를 생성
          const currentTasks = Object.assign({}, tasks);
          // 해당되는 값을 가진 항목만 삭제
          delete currentTasks[id];
          // 선택된 항목만 삭제된 객체를 currentTask 에 대입ㄴ
          setTasks({currentTasks});
     };

     return (
          <ThemeProvider theme={theme}>
               <Container>
                    <Title>To Do List</Title>
                    <StatusBar
                         barStyle="light-content"
                         backgroundColor={theme.background}
                    />
                    <Input
                         placeholder="작업추가하기"
                         value={newTask}
                         onChangeText={(text) => setNewTask(text)}
                         onSubmitEditing={addTask}
                    />
                    <List width={width}>
                         {Object.values(tasks)
                              .reverse()
                              .map((item) => (
                                   <Task
                                        key={item.id}
                                        item={item}
                                        deleteTask={deleteTask}
                                   />
                              ))}
                         {/* reverse().map >>> 최근입력자료가 먼저나오게 함 */}
                    </List>
               </Container>
          </ThemeProvider>
     );
}
 
Task.js
import React from 'react';
import styled from 'styled-components/native';
import PropTypes from 'prop-types';
import IconButton from '../components/iconButton';
import {icons} from '../components/icons';
import {Text} from 'react-native';
import Input from './input';

const Container = styled.View`
     flex-direction: row;
     align-items: center;
     background-color: ${({theme}) => theme.itemBackGround};
     border-radius: 10px;
     padding: 5px;
     margin: 3px 0;
`;
const Contents = styled.Text`
     flex: 1;
     font-size: 16px;
     color: ${({theme}) => theme.text};
`;
const Task = ({item, deleteTask}) => {
     return (
          <Container>
               <IconButton icon={icons.uncheck} />
               <Contents>{item.text}</Contents>
               <IconButton icon={icons.edit} />
               <IconButton
                    icon={icons.delete}
                    item={item}
                    onPress={deleteTask}
               />
          </Container>
     );
};

Task.propTypes = {
     item: PropTypes.object.isRequired,
     deleteTask: PropTypes.func.isRequired,
};
export default Task;
 
 
IconButton.js
import React from 'react';
import {TouchableOpacity, View} from 'react-native';
import styled from 'styled-components/native';
import PropTypes from 'prop-types';
import {icons} from './icons';

const Icon = styled.Image`
     width: 30px;
     height: 30px;
     margin: 10px;
     tint-color: ${({theme}) => theme.text};
`;

const IconButton = ({icon, onPress, item}) => {
     const _onPress = () => {
          onPress(item.id);
     };
     return (
          <TouchableOpacity onPress={_onPress}>
               <View>
                    <Icon source={icon} />
               </View>
          </TouchableOpacity>
     );
};
IconButton.propTypes = {
     icon: PropTypes.oneOf(Object.values(icons)).isRequired,
     onPress: PropTypes.func,
     item: PropTypes.object,
};

export default IconButton;
 

답변 2

·

답변을 작성해보세요.

1

안녕하세요, shafeel2 님, 

  

deleteTask 함수에서 마지막에 setTasks(...)를 할 때, 중괄호 { } 를 빼고, 
setTasks(currentTasks); 로 작성하셔야 합니다.

key경고문구도 이 문제를 해결하면 함께 해결될 것으로 보입니다. 

  

차분하게 강의의 코드와 본인의 코드를 비교해보면서 다시 확인해보면
생각보다 어렵지 않게 문제를 해결 할 수 있습니다. 
혹은, 에러 메시지가 나타난다면 에러 메시지에서 알려주는 문제가 되는 부분의 코드를 다시 잘 확인하거나,
관련된 메시지를 검색해 보시기 바랍니다. 

key 경고문구처럼 한가지 문제가 또다른 문제를 발생시키기도 합니다. 
이런 경우에도 당황하지 않고, "어떤 행동을 했을때 문제가 발생했는가"를 생각하면서, 
차분하게 문제에 다가가면서 하나씩 해결해 보시기 바랍니다. 
만약 문제가 발생한 부분때문에 영향을 받아서 경고(혹은 에러)가 나타난 것이라면 함께 해결됩니다. 

  

깃헙에서 질문을 올리는것이 아니라,
shafeel2님이 작업중인 프로젝트를 깃헙에 저장소(repo)를 만들어서 올리고(commit, push)
해당 저장소의 링크를 이곳에서 질문할때 남겨주시면 됩니다. 
혹시 깃헙 사용에 익숙하지 않으시면, 구글 혹은 유튜브에서 검색해서 익혀두시는 것을 권장합니다.

이곳에서 깃헙 사용법에 대해 설명하는것은
강의와 관련이 없고 관련된 내용의 양이 많을 뿐만 아니라,
텍스트로만 설명하기 어려운점 양해 부탁드립니다. 

깃헙에 프로젝트를 올리고 링크를 받는 이유는,
예제를 진행하는 상황에 따라 버전이 조금씩 다르기 때문에 동일한 버전으로 문제를 확인하기 위해서이기도 하고, 
파일명이나 폴더 구조가 조금씩 다를경우, 정확한 원인 확인하는데 더 오랜 시간이 걸리기 때문입니다. 
되도록 깃헙을 활용하시는것을 권장합니다. 

 

즐거운 하루 되세요

감사합니다. 

  

0

shafeel2님의 프로필

shafeel2

질문자

2021.11.28

항상 자상하신 답변 감사드립니다 

문제는 해결되었구요  

앞으로는 좀더 에러부분에 집중해서 살펴보겠습니다 

그리고 깃헙 사용법은 유튜버에서 배워 계정을 만들어 두었습니다

 

https://github.com/dongguntechnology/rn_study

안녕하세요, 

깃헙에 작업중인 파일을 올릴때, 폴더까지 함께 커밋해 주셔야 합니다. 

간단하게, 프로젝트 전체를 커밋해 주시면 됩니다. (단, node_modules는 제외)

그래야 제가 shafeel2님의 레포를 받아서 그대로 실행할 수 있습니다. 

아래 링크처럼 설정 파일과 폴더 까지 모두 커밋 해주셔야 합니다. 
https://github.com/Alchemist85K/inflearn-react-native/tree/main/rn-todo-app

 

자세한 설명은 빼고, 간단하게 설명하면, 

1. 깃헙에서 레포 생성

- 생성할 프로젝트 이름과 동일하게 하는것을 권장합니다. 
- 프로젝트 이름과 깃헙 레포 이름이 달라도 문제가 되진 않지만, 되도록 같은 이름으로 유지하는것을 권장합니다. 

2. expo 프로젝트 생성 및 프로젝트 디렉토리로 이동

- 1번에서 생성한 깃헙 레포 이름과 동일한 이름으로 프로젝트 생성
- expo init <프로젝트 이름>
- cd <프로젝트 이름>

3. expo 프로젝트에 깃헙 레포 연결

- git remote add origin <깃헙 레포 주소>

- ex) git remote add origin git@github.com:Alchemist85K/inflearn-react-native.git 
- ex) git remote add origin https://github.com/Alchemist85K/inflearn-react-native.git

4. 브랜치 이름 변경 및 푸시

- git branch -M main

- 필수는 아닙니다.

- git push -u origin main

 

위의  과정을 진행하면, 생성된 expo 프로젝트 전체가 해당 레포에 푸시됩니다. 

이 외에도 코드 관리와 관련되어 많은 내용들이 있지만, 
이 강의는 깃헙 강의가 아닐뿐더러, 양도 많아서 텍스트로 설명하기 어려운점 이해해 주시기 바랍니다. 

커맨드라인으로 진행하는것을 선호하지 않으면,
깃헙에서 나온 GitHub Desktop을 다운로드 받아 이용하시는것도 괜찮고, (https://desktop.github.com/)
소스트리(https://www.sourcetreeapp.com/)나 GitKraken(https://www.gitkraken.com/)도 괜찮습니다. 
모두 많은 사람들이 이용하는만큼 직관적인 UI와 다양한 기능을 제공하니 사용해 보시고 가장 마음에 드는 툴을 이용하는것도 좋은 방법입니다. 

 

즐거운 하루 되세요

감사합니다.