Develop/React & React Native

[React Native/Inflearn] React Native로 ToDo 앱 만들기

안다희 2019. 6. 24. 11:47
728x90

강의마다 commit 해놓음!

 

README.md를 포함한 git repository를 만들고 

프로젝트 폴더에서

git remote add origin https://github.com/daheeahn/190623_KawaiToDo.git

를 해준 후

 

git pull origin master

git add .

git commit -m "msg"

git push origin master

 

이렇게 하더라!

 

READMD를 프로젝트 폴더에 가져오기 위함!

 

 

name으로 앱 네임 변경 가능!

Coding the UI part 1

Android에서는 fontWeight가 안먹는다

https://github.com/react-native-training/react-native-fonts

 

react-native-training/react-native-fonts

Fonts available out of the box in a React Native project - react-native-training/react-native-fonts

github.com

fontFamily 이용하기!

 

Coding the UI part 2

ToDo.js : 클래스 컴포넌트! 왜 stateless component가 아니냐!?여기서 수정 누르면 state를 수정모드로 변경해야해서

stateful component인겅

 

Coding the UI part 3 : To Do Component

Styling the To Do Component part 1

state 는 App.js에서 관리할거임

margin

 

marginVertical, marginHorizontal을 줬더니 yellow 영역이 생긴 것!

yellow 영역을 터치해도 터치가 된다!

 

수정 편집 확인 버튼 기능 구현 시 toggle 버튼을 왜 안하냐?

_toggleComplete

복잡해질까봐.

10:30 보기

 

Styling the To Do Component part 2

여기까지 App.js

import React, { Component } from 'react';
import { 
  StyleSheet, 
  Text, 
  View,
  StatusBar, 
  TextInput, 
  Dimensions, 
  Platform,
  ScrollView } from 'react-native';
import ToDo from "./ToDo"

const { height, width } = Dimensions.get("window");

export default class App extends Component {
  
  state = {
    newToDo: ""
  };

  render() {
    const { newToDo } = this.state;
    return (
      <View style={styles.container}>
        <StatusBar 
          backgroundColor="#F23657"
          barStyle="light-content" />
          <Text style={styles.title}>Kawai To Do</Text>
          <View style={styles.card}>
            <TextInput 
              style={styles.input} 
              placeholder={"New To Do"} 
              value={newToDo} 
              onChangeText={this._controlNewToDo} 
              placeholderTextColor={"#999"}
              returnKeyType={"done"}
              autoCorrect={false}/>

              <ScrollView contentContainerStyle={styles.toDos} >
                <ToDo text={"Hello I'm a ToDo"} />
              </ScrollView>
          </View>
      </View>
    );

  }
  _controlNewToDo = text => { // 텍스트를 가져와서 text인거래
    this.setState({
      newToDo: text
    });
  }
}


const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#F23657',
    alignItems: 'center'
  },

  title: {
    color: 'white',
    fontSize: 30,
    marginTop: 50,
    fontFamily: 'sans-serif-light',
    marginBottom: 30
  },

  card: {
    backgroundColor: 'white',
    flex: 1,
    width: width - 25, // 위에서 Dimensions에서 width, height를 window만큼 설정하고 25만큼 뺀거임. container에서 alignItems해서 가운데에 있는거고
    borderTopLeftRadius: 10,
    borderTopRightRadius: 10, // 그냥 borderRadius하면 아래도 둥그래지니까 위쪽 양옆만 적용한 것!

    ...Platform.select({
      ios: {
        shadowColor: "rgb(50, 50, 50)",
        shadowOpacity: 0.5,
        shadowRadius: 5,
        shadowOffset: {
          height: -1, // 위아래로 움직이는게 싫으니까 -1로 설정. 쉐도우가 위에 있는게 좋다. 다양하게 해보기
          width: 0 // 보더에 있기를 원하거든. 1로 설정하면 움직이게 될거야
        }
      },

      android: {
        elevation: 3
      }
    })

  },

  input: {
    padding: 20,
    borderBottomColor: "#bbb", 
    borderBottomWidth: 1, 
    // borderBottomWidth: StyleSheet.hairlineWidth, // 이것도 가능
    fontSize: 20,
  },

  toDos: {
    alignItems: "center"
  }
});

 

ToDo.js

import React, { Component } from "react";
import { 
    View, 
    Text, 
    TouchableOpacity, 
    StyleSheet,
    Dimensions ,
    TextInput
} from "react-native";

const { width, height } = Dimensions.get("window");

export default class ToDo extends Component {

    state = {
        isEditing: false,
        isCompleted: false,
        toDoValue: ""
    };

    render() {
        const { isCompleted, isEditing, toDoValue } = this.state;
        const { text } = this.props;

        return (
            <View style={styles.container}>
                <View style={styles.column}>
                    <TouchableOpacity onPress={this._toggleComplete}>
                        <View style={[ styles.circle,
                                isCompleted ? styles.completedCircle : styles.uncompletedCircle ]} />
                    </TouchableOpacity>
                    {isEditing 
                        ? (
                            <TextInput 
                                style={[
                                    styles.input, // input과 text 순서를 바꾸면 text가 덮어쓴다
                                    styles.text, 
                                    isCompleted 
                                        ? styles.completedText 
                                        : styles.uncompletedText]}
                                value={toDoValue}
                                multiline={true}
                                onChangeText={this._controlInput}
                                returnKeyType={"done"} 
                                onBlur={this._finishtEditing}/>
                                // onChangeText를 해줘야 새로운 텍스트가 계속 입력됨 이걸 안하면 자꾸 새로 입력한게 사라짐
                        )
                        : (
                            <Text
                                style={[styles.text, isCompleted ? styles.completedText : styles.uncompletedText]}>
                                {text}
                            </Text>
                        )
                    }
                </View>
                {isEditing
                    ? (
                        <View style={styles.actions}>
                            <TouchableOpacity onPressOut={this._finishtEditing}>
                                <View style={styles.actionContainer}>
                                    <Text style={styles.actionText}>✅ </Text>
                                </View>
                            </TouchableOpacity>
                        </View>
                    )
                    : (
                        <View style={styles.actions}>
                            <TouchableOpacity onPressOut={this._startEditing}>
                                <View style={styles.actionContainer}>
                                    <Text style={styles.actionText}>✏</Text>
                                </View>
                            </TouchableOpacity>
                            <TouchableOpacity>
                                <View style={styles.actionContainer}>
                                    <Text style={styles.actionText}>❌</Text>
                                </View>
                            </TouchableOpacity>
                        </View>
                    )
                }
            </View>
        );
    }

    _toggleComplete = () => {
        this.setState(prevState => {
            return {
                isCompleted: !prevState.isCompleted
            };
        });
    };

    _startEditing = () => {
        const { text } = this.props;
        
        this.setState({
            isEditing: true,
            toDoValue: text
        });
    };

    _finishtEditing = () => {
        this.setState({
            isEditing: false
        });
    };

    _controlInput = (text) => {
        this.setState({
            toDoValue: text
        });
    };
}

const styles = StyleSheet.create({
    container: {
        width: width - 50,
        borderBottomColor: "#bbb",
        borderBottomWidth: StyleSheet.hairlineWidth,
        flexDirection: "row",
        alignItems: 'center',
        justifyContent: 'space-between',
    },  

    text: {
        fontFamily: "sans-serif-medium",
        fontSize: 20,
        marginVertical: 20, // 상단과 하단의 마진
    },

    circle: {
        width: 30,
        height: 30,
        borderRadius: 15, // 가로 세로의 절반 -> 원
        borderWidth: 3,
        marginRight: 20,
    }, 

    completedCircle: {
        borderColor: "#bbb",
    },

    uncompletedCircle: {
        borderColor: "#F23657",
    },

    completedText: {
        color: "#bbb",
        textDecorationLine: "line-through",
    },

    uncompletedText: {
        color: "#353839"
    },

    column: {
        flexDirection: 'row',
        alignItems: 'center',
        width: width / 2,
        justifyContent: 'space-between',
    },

    actions: {
        flexDirection: 'row',
        // backgroundColor: 'yellow', // for 영역 확인
    },

    actionContainer: {
        marginVertical: 10, // 약간 위아래 양옆을 터치해도 되도록!
        marginHorizontal: 10,
        // backgroundColor: 'red', // for 영역 확인
    },

    input: {
        marginVertical: 10,
        width: width / 2,
    },
})

Introducing AppLoading

디스크에서 투두를 로딩해야해

 

Saving To Dos part 1

onSubmitEditing : 완료를 클릭할 때

array를 생성할거야

todo를 저장해야하거든

 

For using ID

$ npm install uuid --save

 

Saving To Dos part 2

newToDo를 state를 저장했으니 리스트에 추가하고 디스크에 추가하고 화면에 보여주자구

state를 db처럼 생각한다

너의 서버에 데이터베이스가 있고

state를 데이터베이스처럼 다뤄야 함

 

npm install prop-types

prop check

 

Complete and Uncomplete To Do

더이상 어려워서 못하겠다,,, 일단 중단

user@DESKTOP-3OU4T9D MINGW64 ~/Desktop/dev/expo/kawaiToDoApp (master)