React/React Native

React Native 002

salalsksjwnn 2022. 12. 30. 02:01
728x90

미국에 돌아온 지 3일째다 시차적응 때문에 힘들고.. 어제까지는 수업 수료하는 날이라 바쁘고 와이프 비자 발급 받으라 정신이 없었는데 오늘은 내 신분 챙기는 서류 보내느라 바빴다.  그래도 인터뷰때 한 마디라도 더 해보려면 어느정도 앱을 만들어 봐야 할 것 같아서 남은 시간 더 해보자..

 

Core Components

주로 사용되는 컴포넌트들은 이런게 있다

Todo App만들기

목표 : 리액트 네이티브의 core components를 최대한 많이 사용하면서 개발하기

코어 컴포넌트 확인 https://reactnative.dev/docs/components-and-apis

구조

rnfes - 코어 컴포넌트 사용

App.js에 있는 ui를 MainScreen으로 가져온다

import { SafeAreaView, StyleSheet, Text, View } from 'react-native'
import React from 'react'

const MainScreen = () => {
  return (
    <SafeAreaView>
      <Text>ToDo App</Text>
    </SafeAreaView>
  )
}

export default MainScreen

const styles = StyleSheet.create({})

 

<SafeAreaView>

이것의 목적은 장치의 안전 영역 경계 내에서 콘텐츠를 렌더링하는 것
(현재 iOS 버전 11 이상이 설치된 iOS기기 에만 적용된다.)

SafeAreaView를 적용하지 않으면 이렇게 된다.

<StatusBar> 컴포넌트

앱의 상태 표시줄을 제어하는 구성요소이다. 상태 표시줄은 일반적으로 화면 상단에 있는 영역으로 현재시간, WiFi 및 배터리 정보 아이콘을 표시한다. https://reactnative.dev/docs/statusbar

 

StatusBar · React Native

Component to control the app's status bar. The status bar is the zone, typically at the top of the screen, that displays the current time, Wi-Fi and cellular network information, battery level and/or other status icons.

reactnative.dev

적용하면서 바꿔볼 수 있다.

간단하게 만들어보자

import { SafeAreaView, StyleSheet, Text, View, StatusBar } from 'react-native'
import React from 'react'

const MainScreen = () => {
  return (
    <SafeAreaView>
        <StatusBar barStyle={'default'} />
        <Text>ToDo App</Text>
        <View>
            <Text>할 일</Text>
        </View>
        <View>
            <Text>완료된 일</Text>
        </View>        
    </SafeAreaView>
  )
}

export default MainScreen

const styles = StyleSheet.create({})

잘 출력된다.

StyleSheet 사용하기

https://reactnative.dev/docs/style

 

Style · React Native

With React Native, you style your application using JavaScript. All of the core components accept a prop named style. The style names and values usually match how CSS works on the web, except names are written using camel casing, e.g. backgroundColor rathe

reactnative.dev

web은 css를 사용해서 스타일링을 하는데 React Native에서는 css가 아닌 JS를 사용해서 스타일링을 한다.
코어 컴포넌트에 styles prop을 가지고 있다. 카멜케이스를 사용하면 된다.
인라인 스타일로 넣어줄 수도 있고 StyleSheet를 사용해 넣어줄 수도 있다. 역시 이 방법이 가독성이 좋기 때문에 더 추천된다. 이미 정해놓은 스타일을 캐시해주기 때문에 성능도 좋아지게 된다.

 

예시

import { Platform, SafeAreaView, StyleSheet, Text, View} from 'react-native'
import React from 'react'
import { StatusBar } from 'expo-status-bar'

const MainScreen = () => {
  return (
    <SafeAreaView style={styles.container}>
        <StatusBar barStyle={'default'}></StatusBar>
        <Text style={styles.pageTitle}>ToDo App</Text>
        <View style={styles.listView}>
            <Text style={styles.listTitle}>할 일</Text>
        </View>
        <View style={styles.separator} />
        <View style={styles.listView}>
            <Text style={styles.listTitle}>완료된 일</Text>
        </View>        
    </SafeAreaView>
  )
}

export default MainScreen

const styles = StyleSheet.create({
    container:{
        flex:1,
        paddingTop: Platform.OS==='android'? 20 : 0, //안드로이드일때는 20을 아니면 0
        backgroundColor: '#F7f8fa',
    },
    pageTitle:{
        marginBottom:35,
        paddingHorizontal:15,
        fontSize:54,
        fontWeight:'600',
    },
    separator:{
        marginHorizontal:10,
        marginTop:25,
        marginBottom:10,
        borderBottomWidth:1,
        borderBottomColor:'#rgba(0,0,0,0.2)',
    },
    listView:{
        flex:1,
    },
    listTitle:{
        marginBottom:25,
        paddingHorizontal:15,
        fontSize:41,
        fontWeight:'500',
    }
})

스타일을 입히는거는 사실 별반 다를게 없어 보인다. 근데 스타일시트를 따로 컴포넌트로 떼어서는 적용할 수 없는건가?

FlexBox

flex는 항목이 주 축을 따라 사용 가능한 공간을 채울 방법을 정의한다 각 요소의 속성 공간에 따라 분할된다.
web과 사용방법이 다르지 않다.

InputForm

<KeyboardAvoidingView>

가상 키보드에서 벗어나야 하는 뷰의 일반적이 뭄ㄴ제를 ㅐ결하기 위한 구성요소. 키보드 높이에 따라 높이, 위치, 또는 아래쪽 패딩을 자동으로 조정한다.

 

behavior prop에 속성값을 줄 수 있다.

  • padding 키보드가 열렸을 때 뷰의 하단에 패딩 설정
  • height 뷰의 높이 자체 변경
  • position 뷰의 위치 설정
import { KeyboardAvoidingView, Pressable, StyleSheet, Text, TextInput, View } from 'react-native'
import React from 'react'

const InputForm = () => {
  return (
    <KeyboardAvoidingView
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        style={styles.addFormContainer}>
            <TextInput
                style={styles.inputField}
                placeholder="할 일을 작성해 주세요" 
            />
            <Pressable style={styles.addButton}>
                <Text style={styles.addButtonText}>+</Text>
            </Pressable>
    </KeyboardAvoidingView>
  )
}

export default InputForm

const styles = StyleSheet.create({
    addFormContainer:{
        flexDirection:'row',
        marginTop:'auto',
        marginBottom:30,
        paddingHorizontal:20,
        backgroundColor:'f7f8fa',        
    },
    inputField:{
        flex:1,
        height:42,
        padding:5,
        marginRight:25,
        borderRadius:5,
        borderWidth:1,
        borderColor:'rgba0,0,0,0.2',
        color:'#000000',
        fontSize:16,
        textAlignVertical:'center',   
    },
    addButton:{
        justifyContent:'center',
        alignItems:'center', 
        width:42,
        height:42,
        borderRadius:4,
        borderWidth:1,
        backgroundColor:'rgba0,0,0,0.7',
        shadowOpacity:0.14,
        shadowRadius:8,
        shadowOffset: {
            width: 0,
            height: 4,
        }
    },
    addButtonText:{
        color:'#000000',
        fontSize:25,
    },
})

위 코드를 사용해 스타일까지 어느정도 준 모습이다.

안드로이드도 잘 나오고 아이폰도 잘 나온다

할일 체크리스트 생성하기

Pressable

누르는 것의 여러가지 state를 감지할 수 있다 얼마나 누르느냐에 따라 다양한 event 설정

핸드폰 화면은 작기때문에 체크박스의 조금 옆을 눌러도 체크되게 하는게 HitRect hitSlop

이런식으로 지정해줄 수 있는 것

PressRect

터치를(혹은 클릭을)하고 있는 와중에도(활성화 되고 있는 와중에) 어느정도 거리까지 활성화가 될지를 정할 수 있는 것

 

TodoItem.js

import { Pressable, StyleSheet, Text, View } from 'react-native'
import React from 'react'

const TodoItem = () => {
  return (
    <View style={styles.itemContainer}>
        <Pressable
            style={styles.itemTextChecked}
            hitSlop={10}
        >
        </Pressable>
        <Text style={[styles.itemText, styles.itemTextChecked]}>
            코딩하기
        </Text>
        <Pressable 
            style={[
                styles.deleteButton, styles.deleteButtonDone
            ]}
            hitSlop={10}
            >
        </Pressable>
      <Text>

      </Text>
    </View>
  )
}

export default TodoItem

const styles = StyleSheet.create({})

리엑트 네이티브에서 svg 사용

리액트 네이티브는 svg 파일 지원을 안해서 모듈을 설치해야 한다.

  • react-native-svg
npm install react-native-svg
  • react-native-svh-transformer
    임포트해서 사용하려면 이게 필요
npm install -D react-native-svg-transformer

metro.config.js 파일안에 넣어줄 코드가 있는데 npm웹사이트에서 확인이 가능하다.

https://www.npmjs.com/package/react-native-svg-transformer 

 

react-native-svg-transformer

SVG transformer for react-native. Latest version: 1.0.0, last published: a year ago. Start using react-native-svg-transformer in your project by running `npm i react-native-svg-transformer`. There are 95 other projects in the npm registry using react-nativ

www.npmjs.com

프로젝트에 우클릭 New File을 해서 이름을 metro.config.js 로 지정해주고 아래 코드를 붙여넣기 한다.

const { getDefaultConfig } = require("expo/metro-config");

module.exports = (() => {
  const config = getDefaultConfig(__dirname);

  const { transformer, resolver } = config;

  config.transformer = {
    ...transformer,
    babelTransformerPath: require.resolve("react-native-svg-transformer"),
  };
  config.resolver = {
    ...resolver,
    assetExts: resolver.assetExts.filter((ext) => ext !== "svg"),
    sourceExts: [...resolver.sourceExts, "svg"],
  };

  return config;
})();

이제 svg 사용할 준비는 되어있는데 https://www.svgrepo.com/ 이곳에서 다운 받을 수 있다.

 

다운 받은 파일들을 assets폴더에 넣어주고 이름에 맞춰 임포트도 해준다.

 

import { Pressable, StyleSheet, Text, View } from 'react-native';
import React from 'react';
import checkboxIcon from '../assets/checkbox.svg';
import checkboxCheckedIcon from '../assets/checkbox-checked.svg';
import deleteIcon from '../assets/delete.svg';
const TodoItem = () => {
  return (
    <View style={styles.itemContainer}>
        <Pressable
            style={styles.itemTextChecked}
            hitSlop={10}
        >
            <checkboxIcon />
            <checkboxCheckedIcon style={[styles.itemCheckboxCheckedIcon]} />
        </Pressable>
        <Text style={[styles.itemText, styles.itemTextChecked]}>
            코딩하기
        </Text>
        <Pressable 
            style={[
                styles.deleteButton, styles.deleteButtonDone
            ]}
            hitSlop={10}
        >
            <deleteIcon />
        </Pressable>
      <Text>

      </Text>
    </View>
  )
}

export default TodoItem

const styles = StyleSheet.create({})

적용을 해 주고 실행을 하면 짜잔

에러가 뜬다 - 버젼이 안맞는다 뭐라나 인데

하란대로 해주자 터미널에 아래를 입력해 설치한다.

npx expo install react-native-svg@13.4.0

그리고 나서 다시 실행하고 R을 눌러 리로드를 해주면 

나온다! 혹시 아이콘이 크게 나오면 svg 파일로 들어가 크기를 수정 할 수 있다.

import { Pressable, StyleSheet, Text, View } from 'react-native';
import React from 'react';
import CheckboxUnchecked from '../assets/checkbox-unchecked.svg';
import CheckboxChecked from '../assets/checkbox-checked.svg';
import DeleteIcon from '../assets/delete.svg';
const TodoItem = () => {
  return (
    <View style={styles.itemContainer}>
        <Pressable
            style={styles.itemCheckbox}
            hitSlop={10}
        >
            <CheckboxUnchecked />
            <CheckboxChecked style={[styles.itemCheckboxCheckedIcon]} />
        </Pressable>
        <Text style={[styles.itemText, styles.itemTextChecked]}>
            코딩하기
        </Text>
        <Pressable 
            style={[
                styles.deleteButton, 
                styles.deleteButtonDone
            ]}
            hitSlop={10}
        >
            <DeleteIcon />
        </Pressable>
      <Text>

      </Text>
    </View>
  )
}

export default TodoItem
    
const styles = StyleSheet.create({
    itemContainer:{
        flexDirection: 'row',
        alignItems: 'center',
        paddingTop: 10,
        paddingBottom: 15,
        paddingHorizontal: 15,
        backgroundColor:'#f7f8fa',
    },
    itemCheckbox:{
        width: 20,
        height: 20,
        marginRight: 10,
        borderRadius: 5
    },
    itemCheckboxCheckedIcon:{
        shadowColor: 'black',
        shadowOpacity:0.14,
        shadoeRadius: 10,
        shadowOffset: {
            width: 0,
            height: 4
        },
    },
    itemText:{
        marginRight:'auto',
        paddingRight:'auto',
        fontsize:15,
        lineHeight:20,
        color:'#737373'
    },
    itemTextChecked:{
        opacity:0.3,
        textDecorationLine:'line-through'
    },
    deleteButton:{
        opacity:0.8
    },
    deleteButtonDone:{
        opacity:0.3
    }
})

대충 styles도 해줬고 결과

 

 

여기까지 하고 다음번에 기능을 입혀보자

728x90