[React Native] 인스타그램 UI 만들기 #2

in #kr6 years ago (edited)

리액트 네이티브(React Native)로 인스타그램 UI를 구현하는 두 번째 강의입니다. 이번에는 홈 화면에 피드 목록을 구현합니다. 이 포스팅은 아래 무료 동영상 강의를 참고하여 작성하였습니다.


CardComponent 만들기

Components 폴더 아래에 CardComponent.js 파일을 생성합니다. CardComponent는 우리가 앞으로 구현할 피드 목록에서 피드 항목 하나를 담당하게 될 컴포넌트입니다.

import React, { Component } from 'react';
import { View, Image, Text, StyleSheet } from 'react-native';
 
export default class CardCompnent extends Component{
    render() {
        return (
            <View style={style.container}>
                <Text>CardCompnent</Text>
            </View>
        );
    }
}
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    }
});

동영상에서는 create snippet 기능을 사용해서 컴포넌트 파일을 생성하는데, 무척 간편해 보입니다. 해당 기능이 궁금한 분은 여기를 참고하세요.


CardComponent에 추가로 필요한 native-base 컴포넌트를 import 합니다.

import { Card, CardItem, Thumbnail, Body, Left, Right, Button, Icon } from 'native-base';


그리고 CardComponentrender() 함수를 수정합니다.

export default class CardCompnent extends Component{
  render(){
    return (
      <Card>
        <CardItem>
          <Left>
            <Thumbnail source={{ uri: 'https://steemitimages.com/u/anpigon/avatar' }} />
            <Body>
              <Text>Anpigon</Text>
              <Text note>Jan 21, 2019</Text>
            </Body>
          </Left>
        </CardItem>
        <CardItem cardBody>
          <Image 
            source={{ uri: 'https://user-images.githubusercontent.com/3969643/51441420-b41f1c80-1d14-11e9-9f5d-af5cd3a6aaae.png' }} 
            style={{ height:200, width:null, flex: 1 }} />
        </CardItem>
        <CardItem style={{ height:45 }}>
          <Left>
            <Button transparent>
              <Icon name='ios-heart' style={{ color:'black' }}/>
            </Button>
            <Button transparent>
              <Icon name='ios-chatbubbles' style={{ color:'black' }}/>
            </Button>
            <Button transparent>
              <Icon name='ios-send' style={{ color:'black' }}/>
            </Button>
          </Left>
        </CardItem>
        <CardItem style={{ height: 20 }}>
          <Text>101 likes</Text>
        </CardItem>
        <CardItem>
          <Text>
            <Text style={{ fontWeight:'900'}}>Anpigon</Text>
              이번에는 리액트 네이티브(React Native)로 인스타그램 UI을 구현하는 포스팅입니다. 다른 앱을 따라 만들어 보는 것은 굉장히 재미있습니다. 구글에서 인스타그램 클론 코딩 강의를 찾아보니, 다른 개발자들이 올린 동영상 강의를 몇 개 찾을 수 있었습니다.
            </Text>
          </CardItem>
        </Card>
    );
  }
}

CardComponent는 작성자 프로필 영역, 메인 이미지 영역, 본문 영역으로 구성되어 있습니다. 일단은 화면에 피드가 어떻게 표시되는지 확인하기 위해, CardComponent에 임시 데이터를 입력해 놓았습니다.


HomeTab 컴포넌트 수정하기

./Components/AppTabNavigator/HomeTab.js 파일을 수정합니다. native-base에서 Container, Content 컴포넌트와 방금 만든 CardComponentImport 합니다. 그리고 render() 함수와 style를 수정합니다.

// ... 일부 import 생략 ...

import { Container, Content, Icon } from 'native-base'; // Container, Content 추가로 import
import CardComponent from '../CardComponent'; // 카드 컴포넌트 추가

export default class HomeTab extends Component {

    // ... navigationOptions 코드 생략 ...

    render() {
        return (
            <Container style={style.container}>
                <Content>
                    <CardComponent />
                </Content>
            </Container>
        );
    }
}
 
const style = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white'
    }
});


여기까지 작업한 화면입니다.


스팀잇 피드 가져와서 출력하기

동영상에서는 더미 데이터를 이용해서 피드 목록을 출력하고 있습니다. 저는 스팀잇 서버에서 데이터를 가져와서 화면에 출력해보겠습니다.

HomeTab.js 파일을 수정합니다. 그리고 스팀잇에서 피드를 가져오는 fetchFeeds() 함수를 구현합니다. 저는 kr 태그에서 최신글 20개를 가져오도록 구현하였습니다.

export default class HomeTab extends Component {

    fetchFeeds() {
        const data = {
            id: 1,
            jsonrpc: "2.0",
            method: "call",
            params: [
              "database_api",
              "get_discussions_by_created",
              [{ tag: "kr", limit: 20 }]
            ]
        };
        return fetch('https://api.steemit.com', {
            method: 'POST',
            body: JSON.stringify(data)
        })
        .then(res => res.json())
        .then(res => res.result)
    }
    
    // ... 일부 코드 생략 ...


그 다음은 HomeTab 컴포넌트가 마운트되기 전에 피드를 가져옵니다. state.feeds를 선언하고, componentWillMount() 함수를 구현합니다.

export default class HomeTab extends Component {

    state = {
        feeds: []
    }

    componentWillMount() {
        this.fetchFeeds().then(feeds => {
            this.setState({
              feeds
            })
        });
    }
    
    // ... 일부 코드 생략 ...

스팀잇 서버에서 가져온 피드 목록 데이터를 state.feeds에 저장합니다.


그다음은 HomeTabrender() 함수를 수정합니다.

export default class HomeTab extends Component {

  render() {
    return (
      <Container style={style.container}>
        <Content>
          {
            this.state.feeds.map(feed => <CardComponent data={ feed }/>)
          }
        </Content>
      </Container>
    );
  }
    
  // ... 일부 코드 생략 ...

피드 목록을 구현하기 위해 Arraymap 함수을 사용하였습니다. state.feeds 배열을 루프돌면서 CardComponentdata에 각 피드 항목 데이터를 전달합니다.


CardCompnent 수정하기

마지막으로 HomeTab에서 전달 받은 피드 항목 데이터를 CardCompnent에 출력합니다.

export default class CardCompnent extends Component {
  render() {
    const { data } = this.props; // 피드 항목 데이터
    const { image } = JSON.parse(data.json_metadata); // json_metadata에서 이미지 url을 파싱
    return (
        <Card>
            <CardItem>
              <Left>
                <Thumbnail source={{ uri: `https://steemitimages.com/u/${data.author}/avatar` }} />
                <Body>
                  <Text>{data.author}</Text>
                  <Text note>{new Date(data.created).toDateString()}</Text>
                </Body>
              </Left>
            </CardItem>
            {
              image && image.length ?
              <CardItem cardBody>
                <Image 
                  source={{ uri: image[0] }} 
                  style={{ height:200, width:null, flex: 1 }} />
              </CardItem> : null
            }
            <CardItem style={{ height: 20 }}>
              <Text>{ data.active_votes.length } likes</Text>
            </CardItem>
            <CardItem>
              <Text style={{ fontWeight:'900'}}>{ data.title }</Text>
            </CardItem>
            <CardItem>
              <Text>
              { data.body.replace(/\n/g,' ').slice(0, 200) }
              </Text>
            </CardItem>
            <CardItem style={{ height:45 }}>
              <Left>
                <Button transparent>
                  <Icon name='ios-heart' style={{ color:'black', marginRight: 5 }}/> 
                  <Text>{ data.active_votes.length }</Text>
                </Button>
                <Button transparent>
                  <Icon name='ios-chatbubbles' style={{ color:'black', marginRight: 5 }}/>
                  <Text>{ data.children }</Text>
                </Button>
                <Button transparent>
                  <Icon name='ios-send' style={{ color:'black' }}/>
                </Button>
              </Left>
              <Right>
                <Text>{ data.pending_payout_value }</Text>
              </Right>
            </CardItem>
        </Card>
    );
  }
}

대문 이미지는 json_metadata에 이미지 URL이 있는 경우에만 표시되도록 하였습니다.


여기까지 작업한 화면입니다.


작업한 코드는 모두 깃허브에 업로드되어 있습니다.

https://github.com/anpigon/rn_instagram_clone


여기까지 읽어주셔서 감사합니다.


시리즈

Sponsored ( Powered by dclick )
DCLICK: An Incentivized Ad platform by Proof of Click - 스팀 기반 애드센스를 소개합니다.

안녕하세요 스티미언 여러분. 오늘 여러분께 스팀 블록체인 기반 광고 플랫폼 DCLICK을 소개...

Sort:  

Hi @anpigon!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your UA account score is currently 2.853 which ranks you at #12051 across all Steem accounts.
Your rank has dropped 25 places in the last three days (old rank 12026).

In our last Algorithmic Curation Round, consisting of 240 contributions, your post is ranked at #105.

Evaluation of your UA score:
  • Only a few people are following you, try to convince more people with good work.
  • The readers like your work!
  • Good user engagement!

Feel free to join our @steem-ua Discord server

짱짱맨 호출에 응답하여 보팅하였습니다.

우와 멋있습니다 :)

뽀돌님 감사합니다.

오호 괜찮네요!
이걸 이용해서 딴거를 만들어 봐야 겠네요.

리액트는 만능인거 같아요. 재미있습니다. ㅋ

역시 리엑트 ! 이쁘네요 ㅎㅎ

구성도 쉽고여 :)

플러터 어느정도 수준에 올라가면 리엑트도 기웃거려 봐야겠네요 ㅎㅎ

Posted using Partiko Android

플러터보다는 리액트 네이티브가 오픈소스나 공부할수 있는 자료가 많아서 푹빠져버렸습니다.
빨리 공부해서 리액트 네이티브로 앱을 만들고 싶은데.. 공부할 것이 많습니다.
유료 강의도 듣고, 무료 강의도 듣고, 인터넷 자료도 찾아서 읽고.... 공부할 시간이 절대적으로 부족하네요.ㅎㅎ

플러터가 초기라 으윽

대신 이번에 구글에서 발표한 os 프시아(fuchsia)도 플러터 지원이 되는지라 전 한번 플러터로 쭈우욱 해보려고여 :)

구글이 초기긴 하지만 탈 java 땜시 플러터 밀어주고 있는거 같내요

안피곤님도 리엑트로 가즈아~~

Posted using Partiko Android

원사마님 이야기 듣고 나니 다시 플러터를 하고 싶네요.ㅎㅎ
하지만, 저는 플러터 강의 자료가 많이 생기면 그때 공부 시작할려구요. 지금은 플러터 학습 장벽이 너무 높습니다.

예쁘게 잘나오네요 ㅎㅎ
인스타 스타일로 스팀보면 좋겠어요! ㅎㅎ

강의만 따라하면 인스타그램 UI의 스팀잇 앱이 나올 것만 같습니다. ㅎㅎ