블록체인 개발자 양성과정 중 리액트 네이티브 관련 자료 모음

:information_source: 본 글을 블록체인 개발자 양성과정 중 앱 개발 관련한 교육과정에서 리액트 네이티브 관련 수업을 진행하면서 학생들과 공유했던 링크와 코드들 입니다. 리액트 네이티브 초급반에 해당하는 "Zero to App 과정"과 비슷한 내용 및 난이도를 가지고 있습니다.

자바스크립트 설명 사이트

색상 값 참고용 사이트

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

var {height, width} = Dimensions.get('window');
const isWidePhone = width > 350;

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text
          style={{fontSize: 16, color: 'grey', textAlign:'center',lineHeight:25}}
        >
          <Text style={styles.link}>이용약관</Text>과
          <Text style={styles.link}>개인정보취급정책</Text>에 동의하실 경우,
          { isWidePhone ? '\n' : ''}
          새 계정을 만들어 주세요.
        </Text>
        <View style={{marginTop: 30}}>
          <Text
            style={{
              fontSize: 14,
              color: 'skyblue',
              textDecorationLine: 'underline',
            }}
          >
            이미 가입하셨나요?
          </Text>  
        </View>
        
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center',
    borderColor: 'black',
    borderWidth: 10,
    
  },
  link: {
    textDecorationLine: 'underline',
    marginTop: 5,
    color: 'black'
  },
});

<TouchableOpacity
        style={{backgroundColor:'red', height:50, width:'100%', flexDirection:'row', justifyContent:'center', alignItems:'center', borderRadius:10}}
        onPress={ ()=>{ 
        alert('wow');
      }}>
          <Text style={{color:'#fff', fontSize: 30}}>회원가입</Text>
      </TouchableOpacity>

``
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';

class RoundButton extends React.Component {
  render(){
    return (
      <TouchableOpacity
        style={[
          {backgroundColor:'red', height:50, width:'100%', flexDirection:'row', justifyContent:'center', alignItems:'center', borderRadius:10}, 
          this.props.style
        ]}
        onPress={this.props.onPress}
      >
        <Text style={{color:'#fff', fontSize: 30}}> {this.props.title} </Text>
      </TouchableOpacity>
    )
  }
}

export default RoundButton;

좋아요 1

CarItem 실습 예 1 ./components/CarItem.js

import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import { AntDesign } from '@expo/vector-icons';

class CarItem extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <View
          style={{
            backgroundColor: 'transparent',
            height: 110,
            flexDirection: 'row',
            borderColor: 'grey',
            borderWidth: 2,
            marginBottom: 10,
            width: '100%',
            paddingTop: 5,
          }}
        >
          <Image
            style={{
              width: '25%',
              height: '100%',
              top: 0,
            }}
            source={{
              uri:
                'http://i1.daumcdn.net/thumb/P318x190/?fname=http://i1.daumcdn.net/cfile4/image/24710B3E1F972D37BD103C',
            }}
          />

          <View
            style={{
              width: '40%',
              height: '100%',
              paddingLeft: 5,
              flexDirection: 'column',
            }}
          >
            <Text
              style={{
                fontSize: 30,
                color: 'black',
                paddingLeft: 20,
              }}
            >
              Dog비싸
            </Text>
            <View
              style={{
                flexDirection: 'row',
                paddingLeft: 20,
              }}
            >
              <AntDesign
                name="like2"
                size={20}
                paddingBottom={20}
                color="black"
              />
              <Text
                style={{
                  fontSize: 18,
                  color: 'black',
                }}
              >
                우리집 안방에 모셔놔줘
              </Text>
            </View>
          </View>
          <View
            style={{
              flexDirection: 'column',
              alignItems: 'center',
              paddingLeft: 50,
            }}
          >
            <Text
              style={{
                fontSize: 30,
                color: 'black',
              }}
            >
              100언
            </Text>
          </View>
        </View>
      </View>
    );
  }
}

export default CarItem;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 20,
  },
});

CarItem을 사용하는 App.js 예

import React from 'react';
import { FlatList, View } from 'react-native';
import CarItem from './components/CarItem';

export default class App extends React.Component {
  render() {
    return (
      <View style={{flex:1}}>
        <FlatList
          data={[
            {key: 'a', title: '테슬라'}, 
            {key: 'b', title:'현대'}
          ]}
          renderItem={({item}) => <CarItem title={item.title} />}
        />
      </View>
    );
  }
}

flastlist의 refresh 예제

import React from 'react';
import { FlatList, View,StyleSheet } from 'react-native';
import CarItem from './components/CarItem';

export default class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      isRefreshing: false,
      data : [
        {key: 'a', title: '테슬라'}, 
        {key: 'b', title:'현대'}
      ]
    }
  }
  render() {
    return (
      <View style={{flex:1, paddingTop:30}}>
        <FlatList
          data={this.state.data}
          renderItem={ ({item}) => <CarItem title={item.title}/>}
          ItemSeparatorComponent={ () => (
            <View style={{
              height: StyleSheet.hairlineWidth, 
              marginLeft:20, 
              backgroundColor:'red'
            }} />
          )}
          refreshing = {this.state.isRefreshing}
          onRefresh={ ()=>{
            this.setState({
              isRefreshing : true
            })
            setTimeout(() => {
              this.setState({
                isRefreshing: false,
                data : [
                  {key: 'a', title: '테슬라'}, 
                  {key: 'b', title:'현대'},
                  {key: 'c', title:'BMW'}
                ]
              })
            }, 5000);
          }}
        />
      </View>
    );
  }
}

배열을 Text로 변환해서 화면에 보여주는 예

import React, { Component } from 'react';
import { TouchableOpacity, SectionList, StyleSheet, Text, View } from 'react-native';

export default class App extends Component {
  render() {
    const data = [
      {name: 'ios-car', text: '자동차이름'},
      {name: 'cat', text: '고양이'},
    ]

    const iterator = function(item){
      return (
        <Text>{item.text}</Text>
      );
    }
    
    const items = data.map(iterator);


    return (
      <View style={{flex: 1,justifyContent:'center', alignItems:'center'}}>
        {items}
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
   flex: 1,
   paddingTop: 22
  },
  sectionHeader: {
    paddingTop: 2,
    paddingLeft: 10,
    paddingRight: 10,
    paddingBottom: 2,
    fontSize: 14,
    fontWeight: 'bold',
    backgroundColor: 'rgba(247,247,247,1.0)',
  },
  item: {
    padding: 10,
    fontSize: 18,
    height: 44,
  },
})

flexWrap 속성을 이용해서 한 줄에 두개씩 View를 보여주고 가운데 구분선 넣기

import React, { Component } from 'react';
import { TouchableOpacity, SectionList, StyleSheet, Text, View } from 'react-native';

export default class App extends Component {
  render() {
    const data = [
      {name: 'ios-car', text: '자동차이름'},
      {name: 'cat', text: '고양이'},
      {name: 'cat', text: '고양이'},
      {name: 'cat', text: '고양이'},
      {name: 'cat', text: '고양이'},
      {name: 'cat', text: '고양이'},
      {name: 'cat', text: '고양이'},
    ]

    const items = data.map( (x)=>{
      return (
        <View style={{height: 50, width:'50%', borderColor:'green',borderWidth:3, alignItems:'center'}}>
          <Text>{x.text}</Text>
        </View>
      );
    });

    return (
      <View style={{flex: 1,justifyContent:'center', alignItems:'stretch'}}>
        <View style={[styles.bd, {flexDirection: 'row', flexWrap:'wrap'}]}>
          {items}
          <View style={{
            position:'absolute', 
            width:10, height:'90%',
            left:'50%', backgroundColor:'blue'}}></View>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  bd : {
    borderColor: 'red',
    borderWidth:3
  },
  container: {
   flex: 1,
   paddingTop: 22
  },
  sectionHeader: {
    paddingTop: 2,
    paddingLeft: 10,
    paddingRight: 10,
    paddingBottom: 2,
    fontSize: 14,
    fontWeight: 'bold',
    backgroundColor: 'rgba(247,247,247,1.0)',
  },
  item: {
    padding: 10,
    fontSize: 18,
    height: 44,
  },
})

SectionList 기본 예제

// Example 1 (Homogeneous Rendering)
<SectionList
  renderItem={({item, index, section}) => <Text key={index}>{item}</Text>}
  renderSectionHeader={({section: {title}}) => (
    <Text style={{fontWeight: 'bold'}}>{title}</Text>
  )}
  sections={[
    {title: 'Title1', data: ['item1', 'item2']},
    {title: 'Title2', data: ['item3', 'item4']},
    {title: 'Title3', data: ['item5', 'item6']},
  ]}
  keyExtractor={(item, index) => item + index}
/>

Geolocation 관련 예제 시작 코드

import React, { Component } from 'react';
import { TouchableOpacity, SectionList, StyleSheet, Text, View } from 'react-native';
import CarDetailScreen from './screens/CarDetailScreen';

export default class App extends Component {
  constructor(props){
    super(props);
    this.state = {
    }
  }
  componentDidMount(){
    navigator.geolocation.getCurrentPosition( 
      (position) => {
        this.setState({
          //여기에 뭔가를 지정하시고
        });
      },
      (error) => {alert(error.message)},
      {
        enableHighAccuracy: true, 
        timeout: 20000, 
        maximumAge: 1000
      } 
    );
  }
  render() {
    return (
      <View>
        <Text>{this.state.xxx}</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  bd : {
    borderColor: 'red',
    borderWidth:3
  },

})

Geolocation 관련 예제 완성

import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import {MapView} from 'expo';
export default class App extends Component {
  constructor(props){
    super(props);
    this.state = {
    }
  }
  componentDidMount(){
    navigator.geolocation.getCurrentPosition( 
      (position) => {
        const {coords} = position;
        this.setState({
          //여기에 뭔가를 지정하시고
          latitude : coords.latitude,
          longitude: coords.longitude
        });
      },
      (error) => {alert(error.message)},
      {
        enableHighAccuracy: true, 
        timeout: 20000, 
        maximumAge: 1000
      } 
    );
  }
  render() {
    return (
      <View style={{flex:1, justifyContent:'center', alignItems: 'stretch'}}>
        { this.state.latitude ? 
          <MapView
            style={{flex:1}}
            initialRegion={{
              latitude: this.state.latitude,
              longitude: this.state.longitude,
              latitudeDelta: 0.0922,
              longitudeDelta: 0.0421,
            }}
          />  
          :<Text>위치 읽어오는 중...</Text>   
        }
      </View>
    );
  }
}

const styles = StyleSheet.create({
  bd : {
    borderColor: 'red',
    borderWidth:3
  },

})

react-navigation 기본 예제

공식 문서 : https://reactnavigation.org/docs/en/hello-react-navigation.html

// In App.js in a new project

import React from 'react';
import { View, Text } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import VehicleList from './screens/MyVehicleListScreen';
import VehicleDetail from './screens/VehicleDetailScreen';

class HomeScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Home Screen</Text>
      </View>
    );
  }
}

const AppNavigator = createStackNavigator({
  List: {
    screen: VehicleList,
  },
  Detail: {
    screen: VehicleDetail,
  },
});

export default createAppContainer(AppNavigator);

Naver 책 검색 API 예제

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

class App extends Component {
  constructor(props){
    super(props);
    this.state = {

    }
  }
  fetchBooks(page = 1) {
    const display = 10;
    const start = display * (page-1) + 1;
    const query = 'javascript';
    return fetch(`https://openapi.naver.com/v1/search/book.json?query=${query}&display=${display}&start=${start}`, {
      headers : {
        'X-Naver-Client-Id': 'vTiJhVKTgkFtmAOe1aRw',
        'X-Naver-Client-Secret': 'KNnOp1CgQd'
      }
    })
    .then(response => response.json())
    .then(responseJson => {
      return responseJson.items;
    })
    .catch(error => {
      console.error(error);
    });
  }
  render() {
    this.fetchBooks().then(items => {
      console.log(items[0]);
    });
    return (
      <View></View>
    );  
  }
}

export default App;


// {
//   "author": "에반 버차드",
//   "description": "더 나은 자바스크립트 코드를 만드는 최선의 방법
// 리팩토링 자바스크립트!코드의 기본 품질이 좋지 않으면 항상 버그와 성능 문제가 생긴다. 버그는 마술처럼 사라지지 않고, 또 다른 버그를 만들기도 한다. 이 책은 자바스크립트의 품질에 집중해 더 나은 코드를 만들기 위한 최선의 방법들을 소개한다. 코드... ",
//   "discount": "32400",
//   "image": "https://bookthumb-phinf.pstatic.net/cover/140/491/14049175.jpg?type=m1&udate=20181011",
//   "isbn": "1160505896 9791160505894",
//   "link": "http://book.naver.com/bookdb/book_detail.php?bid=14049175",
//   "price": "36000",
//   "pubdate": "20181012",
//   "publisher": "길벗",
//   "title": "리팩토링 자바스크립트 (지저분한 자바 스크립트 코드에서 벗어나자!)",
// }

Animated 예제

공식 문서에 나와 있는 예제를 조금 변경함

import React from 'react';
import { Animated, Text, View } from 'react-native';

class FadeInView extends React.Component {
  state = {
    fadeAnim: new Animated.Value(0),  // Initial value for opacity: 0
  }

  componentDidMount() {
    Animated.spring(                  // Animate over time
      this.state.fadeAnim,            // The animated value to drive
      {
        toValue: 25,                   // Animate to opacity: 1 (opaque)
        speed: 3,
        bounciness: 15            // Make it take a while
      }
    ).start();                        // Starts the animation
  }

  render() {
    let { fadeAnim } = this.state;

    return (
      <Animated.View                 // Special animatable View
        style={{
          ...this.props.style,
          borderRadius: fadeAnim,         // Bind opacity to animated value
          position: 'absolute',
          left: fadeAnim
        }}
      >
        {this.props.children}
      </Animated.View>
    );
  }
}

// You can then use your `FadeInView` in place of a `View` in your components:
export default class App extends React.Component {
  render() {
    return (
      <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
        <FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
          <Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
        </FadeInView>
      </View>
    )
  }
}

Naver 책 검색 API 검색까지 구현한 실습 결과

import React, { Component } from "react";
import {
  StyleSheet,
  Text,
  View,
  FlatList,
  Image,
  TextInput,
  Button
} from "react-native";

function BookItem(props) {
  return (
    <View
      style={{
        flexDirection: "row"
      }}
    >
      <View
        style={{
          justifyContent: "center",
          alignItems: "center",
          height: 200,
          width: "40%"
        }}
      >
        <Image
          style={{ width: "80%", height: "80%" }}
          source={{ uri: props.image }}
        />
      </View>
      <View>
        <Text>{props.title}</Text>
        <Text>{props.publisher}</Text>
        <Text>{props.pubdate}</Text>
        <Text>{props.price}</Text>
      </View>
    </View>
  );
}

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      key: "javascript"
    };
  }
  fetchBooks(page = 1) {
    const display = 10;
    const start = display * (page - 1) + 1;
    var query = this.state.key; //검색어 초기설정값 //key라고만 적으면 못찾음. fetchBooks 라는 함수 안에 key가 없어서

    return fetch(
      `https://openapi.naver.com/v1/search/book.json?query=${query}&display=${display}&start=${start}`,
      {
        headers: {
          "X-Naver-Client-Id": "vTiJhVKTgkFtmAOe1aRw",
          "X-Naver-Client-Secret": "KNnOp1CgQd"
        }
      }
    )
      .then(response => response.json())
      .then(responseJson => {
        return responseJson.items;
      })
      .catch(error => {
        console.error(error);
      });
  }

  componentDidMount() {
    this.fetchBooks().then(items => {
      //네이버 책검색 api 에서 개별 검색 결과를 items라는 이름의 변수로 지정해놨다
      console.log(items);

      this.setState({
        bookItems: items
      });
    });
  }

  render() {
    return (
      <View style={styles.container}>
        <View
          style={{
            flexDirection: "row"
          }}
        >
          <TextInput
            style={{
              height: 40,
              width: "80%",
              borderColor: "gray",
              borderWidth: 1
            }}
            onChangeText={text => this.setState({ key: text })}
          />

          <Button
            onPress={() => {
              this.fetchBooks().then(items => {
                //네이버 책검색 api 에서 개별 검색 결과를 items라는 이름의 변수로 지정해놨다
                console.log(items);

                this.setState({
                  bookItems: items
                });
              });
            }}
            title="search"
            color="#841584"
          />
        </View>
        <FlatList
          data={this.state.bookItems}
          renderItem={({ item }) => (
            <BookItem {...item}/>
          )}
          ItemSeparatorComponent={({ highlighted }) => (
            <View
              style={{
                height: StyleSheet.hairlineWidth,
                marginLeft: 20,
                backgroundColor: "grey"
              }}
            />
          )}
        />
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 30
  },

  text: {
    color: "black",
    fontSize: 20
  }
});

책을 선택하는 실습 참고 url

책 별 선택 예제 결과 (extraData 사용)

import React, { Component } from "react";
import {
  StyleSheet,
  Text,
  View,
  FlatList,
  Image,
  TextInput,
  Button,
  TouchableOpacity
} from "react-native";
import {Ionicons} from '@expo/vector-icons';

function BookItem(props) {
  return (
    <View
      style={{
        flexDirection: "row"
      }}
    >
      <View
        style={{
          justifyContent: "center",
          alignItems: "center",
          height: 200,
          width: "40%"
        }}
      >
        <Image
          style={{ width: "80%", height: "80%" }}
          source={{ uri: props.image }}
        />
      </View>
      <TouchableOpacity onPress={props.onPressStar}>
        <Ionicons name={props.selected ? 'ios-star' : 'ios-star-outline'} size="50"/>
      </TouchableOpacity>
      <View>
        <Text>{props.title}</Text>
        <Text>{props.publisher}</Text>
        <Text>{props.pubdate}</Text>
        <Text>{props.price}</Text>
      </View>
      
    </View>
  );
}

export default class App extends Component {
  state = {
    key: "javascript",
    selected : {
      // 저장 형태
      //'213123123' : false
    }
  }
  fetchBooks(page = 1) {
    const display = 10;
    const start = display * (page - 1) + 1;
    var query = this.state.key; //검색어 초기설정값 //key라고만 적으면 못찾음. fetchBooks 라는 함수 안에 key가 없어서

    return fetch(
      `https://openapi.naver.com/v1/search/book.json?query=${query}&display=${display}&start=${start}`,
      {
        headers: {
          "X-Naver-Client-Id": "vTiJhVKTgkFtmAOe1aRw",
          "X-Naver-Client-Secret": "KNnOp1CgQd"
        }
      }
    )
      .then(response => response.json())
      .then(responseJson => {
        return responseJson.items;
      })
      .catch(error => {
        console.error(error);
      });
  }
  componentDidMount() {
    this.fetchBooks().then(items => {
      //items : 네이버 책검색 api 에서 개별 검색 결과가 담긴 배열([])
      this.setState({
        bookItems: items
      });
    });
  }

  render() {
    return (
      <View style={styles.container}>
        <View
          style={{
            flexDirection: "row"
          }}
        >
          <TextInput
            style={{
              height: 40,
              width: "80%",
              borderColor: "gray",
              borderWidth: 1
            }}
            onChangeText={text => this.setState({ key: text })}
          />

          <Button
            onPress={() => {
              this.fetchBooks().then(items => {
                //네이버 책검색 api 에서 개별 검색 결과를 items라는 이름의 변수로 지정해놨다
                console.log(items);

                this.setState({
                  bookItems: items
                });
              });
            }}
            title="search"
            color="#841584"
          />
        </View>
        <FlatList
          data={this.state.bookItems}
          extraData={this.state.selected}
          renderItem={({ item }) => (
            // items의 배열에 있는 item 1개의 모습 예
            // {
            //   title : 'bbb',
            //   author: 'aaaa'
            // }
            // 이 것을 ...items 으로 사용하면 아래와 동일
            // <BookItem title={item.title} author={item.author}/>
            <BookItem {...item} 
              selected={ this.state.selected[item.isbn] }
              onPressStar={()=>{
              // 함수를 props으로 넘기는 이유 item에 쉽게 접근가능하고
              // App component에 해당하는 this에도 접근 가능

              // alert(item.isbn);
              // this.state.selected
              // {
              //    'xxxxx' : true
              //    'yyyy' : false
              // }
              this.setState({ // state의 변경은 반드시 setState
                selected : {
                  ...this.state.selected,
                  [item.isbn] : !this.state.selected[item.isbn]
                  // 들어 가는 모습 "03204023 3204" : true 
                }
              });
            }}/>
          )}
        />
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 30
  },

  text: {
    color: "black",
    fontSize: 20
  }
});

책 별 선택 예제 ( 선택된 정보로 Flatlist의 data를 다시 만드는 방법으로…)

import React, { Component } from "react";
import {
  StyleSheet,
  Text,
  View,
  FlatList,
  Image,
  TextInput,
  Button,
  TouchableOpacity
} from "react-native";
import {Ionicons} from '@expo/vector-icons';

function BookItem(props) {
  return (
    <View
      style={{
        flexDirection: "row"
      }}
    >
      <View
        style={{
          justifyContent: "center",
          alignItems: "center",
          height: 200,
          width: "40%"
        }}
      >
        <Image
          style={{ width: "80%", height: "80%" }}
          source={{ uri: props.image }}
        />
      </View>
      <TouchableOpacity onPress={props.onPressStar}>
        <Ionicons name={props.selected ? 'ios-star' : 'ios-star-outline'} size={50}/>
      </TouchableOpacity>
      <View>
        <Text>{props.title}</Text>
        <Text>{props.publisher}</Text>
        <Text>{props.pubdate}</Text>
        <Text>{props.price}</Text>
      </View>
      
    </View>
  );
}

export default class App extends Component {
  state = {
    key: "javascript",
    bookItems: [],
    selected : {
      // 저장 형태
      //'213123123' : false
    }
  }
  fetchBooks(page = 1) {
    const display = 10;
    const start = display * (page - 1) + 1;
    var query = this.state.key; //검색어 초기설정값 //key라고만 적으면 못찾음. fetchBooks 라는 함수 안에 key가 없어서

    return fetch(
      `https://openapi.naver.com/v1/search/book.json?query=${query}&display=${display}&start=${start}`,
      {
        headers: {
          "X-Naver-Client-Id": "vTiJhVKTgkFtmAOe1aRw",
          "X-Naver-Client-Secret": "KNnOp1CgQd"
        }
      }
    )
      .then(response => response.json())
      .then(responseJson => {
        return responseJson.items;
      })
      .catch(error => {
        console.error(error);
      });
  }
  componentDidMount() {
    this.fetchBooks().then(items => {
      //items : 네이버 책검색 api 에서 개별 검색 결과가 담긴 배열([])
      this.setState({
        bookItems: items
      });
    });
  }

  render() {
    let bookItemsWithSelected = this.state.bookItems.map( (book) => {
      return {
        ...book,
        selected : this.state.selected[book.isbn]
      }
    });

    return (
      <View style={styles.container}>
        <View
          style={{
            flexDirection: "row"
          }}
        >
          <TextInput
            style={{
              height: 40,
              width: "80%",
              borderColor: "gray",
              borderWidth: 1
            }}
            onChangeText={text => this.setState({ key: text })}
          />

          <Button
            onPress={() => {
              this.fetchBooks().then(items => {
                //네이버 책검색 api 에서 개별 검색 결과를 items라는 이름의 변수로 지정해놨다
                console.log(items);

                this.setState({
                  bookItems: items
                });
              });
            }}
            title="search"
            color="#841584"
          />
        </View>
        <FlatList
          data={bookItemsWithSelected}
          keyExtractor={(item)=>item.isbn}
          renderItem={({ item }) => (
            // items의 배열에 있는 item 1개의 모습 예
            // {
            //   title : 'bbb',
            //   author: 'aaaa'
            // }
            // 이 것을 ...items 으로 사용하면 아래와 동일
            // <BookItem title={item.title} author={item.author}/>
            <BookItem {...item} 
              onPressStar={()=>{
              // 함수를 props으로 넘기는 이유 item에 쉽게 접근가능하고
              // App component에 해당하는 this에도 접근 가능

              // alert(item.isbn);
              // this.state.selected
              // {
              //    'xxxxx' : true
              //    'yyyy' : false
              // }
              this.setState({ // state의 변경은 반드시 setState
                selected : {
                  ...this.state.selected,
                  [item.isbn] : !this.state.selected[item.isbn]
                  // 들어 가는 모습 "03204023 3204" : true 
                }
              });
            }}/>
          )}
        />
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 30
  },

  text: {
    color: "black",
    fontSize: 20
  }
});

화면 전환 / 화면 전환시 데이터 전달 / webview

// 보내는 쪽
this.props.navigation.navigate('Details', {
  itemId: 86,
  otherParam: 'anything you want here',
});

// 받는 쪽
const itemId = navigation.getParam('itemId');
import React, { Component } from 'react';
import { WebView } from 'react-native';

class MyWeb extends Component {
  render() {
    return (
      <WebView
        source={{uri: 'https://github.com/facebook/react-native'}}
        style={{marginTop: 20}}
      />
    );
  }
}

Barcode

isbn으로 해당 책 정보 얻어오는 함수

fetchBookByISBN(isbn) {
    return fetch(
      `https://openapi.naver.com/v1/search/book_adv.json?d_isbn=${isbn}`,
      {
        headers: {
          "X-Naver-Client-Id": "vTiJhVKTgkFtmAOe1aRw",
          "X-Naver-Client-Secret": "KNnOp1CgQd"
        }
      }
    )
      .then(response => response.json())
      .then(responseJson => {
        return responseJson.items[0];
      })
      .catch(error => {
        console.error(error);
      });
  }