소셜 미디어 앱을 개발하는 방법은 무엇인가요?

소셜 미디어 앱 커버 제작

이 글에서는 소셜 네트워크, 소셜 미디어 앱의 종류, 장점 및 필수 기능에 대해 설명합니다.

또한 소셜 네트워크를 만드는 방법을 단계별로 살펴보겠습니다. 백엔드에는 Back4app을, 프론트엔드에는 Next.js를 사용하겠습니다.

소셜 네트워크란 무엇인가요?

소셜 네트워크는 사람들이 서로 연결하고 상호 작용할 수 있는 소셜 미디어 앱입니다.

두 사용자가 연결되면 사용자 정보를 공유하고, 메시지와 이미지를 교환하고, 게시물을 공유하는 등의 작업을 할 수 있습니다.

요즘은 소셜 미디어 앱의 인기가 매우 높습니다. 거의 모든 사람이 하나 이상의 소셜 미디어 앱에 가입되어 있습니다. Buffer의 조사에 따르면 가장 인기 있는 소셜 미디어 플랫폼은 다음과 같습니다:

  • Facebook(29억 6천만 MAU)
  • YouTube(22억 MAU)
  • Instagram(20억 MAU)
  • 틱톡(10억 MAU)
  • Snapchat(5억 MAU)

MAU는 월간 활성 사용자를 의미합니다. 이는 매월 소셜 미디어 플랫폼과 상호작용하는 순 사용자 수입니다.

소셜 미디어 앱 시장은 엄청나게 크지만 소셜 미디어 앱을 개발하는 것은 쉽지 않은 작업입니다.

소셜 네트워킹 앱은 가장 복잡한 IT 프로젝트 중 하나입니다. 많은 기업이 소셜 네트워킹 앱을 구축하는 것이 얼마나 어려운지 과소평가하다가 막대한 손실을 입고 비참하게 실패합니다.

소셜 미디어 애플리케이션의 유형

이전 섹션에서 언급했듯이 소셜 네트워크는 소셜 미디어 앱 유형 중 하나에 불과합니다. 다른 소셜 미디어 앱 유형은 다음과 같습니다:

  • 미디어 공유 네트워크(인스타그램, 틱톡, 유튜브)
  • 콘텐츠 공유 네트워크(핀터레스트, 텀블러, 플리커)
  • 소비자 리뷰 네트워크(트러스트파일럿, 엔지, 초이스)
  • 블로그 및 퍼블리싱 네트워크(Medium, Twitter)
  • 토론 포럼(Reddit, Quora, HackerNews)
  • 관계 네트워크(틴더, 범블)

소셜 미디어 앱 개발의 이점

소셜 미디어 앱을 구축하면 여러 가지 이점이 있습니다. 광고 수익, 수익 창출, 귀중한 사용자 정보 수집, 고급 분석, 다른 회사와의 스폰서십 등 다양한 이점이 있습니다.

소셜 미디어 앱의 또 다른 장점은 엄청난 재판매 가치입니다. 앱이 비교적 성공적이라면(즉, 상당한 사용자 기반을 확보하고 있다면) 다른 회사에 빠르게 판매할 수 있습니다. 예를 들어 트위터는 440억 달러에, 마이스페이스는 8,700만 달러에 매각되었습니다.

개발자의 입장에서 간단한 소셜 네트워크를 구축하면 작업하는 도구에 대해 알 수 있고, 이런 것을 구축하는 것이 얼마나 어려운지 알 수 있습니다.

소셜 미디어 앱의 기능이 있어야 합니다.

소셜 미디어 앱의 기능은 매우 다양합니다. 그럼에도 불구하고 모든 성공적인 소셜 미디어 앱에는 몇 가지 필수 기능이 포함되어 있습니다.

사용자 계정

모든 소셜 미디어 앱에서 사용자는 계정을 만들 수 있습니다. 계정을 생성한 사용자는 개인 정보를 추가하고 필요에 따라 앱을 맞춤 설정할 수 있습니다. 예를 들어, 좋아하는 기능을 선택하고, 관심사를 추가하고, 특정 콘텐츠를 숨기는 등의 작업을 할 수 있습니다.

비즈니스 관점에서 사용자 계정의 가장 큰 장점은 ‘사용자 프로필’을 구축할 수 있다는 점입니다. ‘사용자 프로필’이란 특정 사용자가 무엇을 좋아하고 누구와 소통하는지 파악한 다음 그에 따라 광고를 맞춤 설정하는 것을 의미합니다.

사용자 연결

소셜 미디어 앱을 통해 사용자는 누군가를 친구로 추가하고, 팔로우하고, 구독하는 등의 방법으로 연결할 수 있습니다. 두 사용자가 연결되면 그에 따라 피드가 변경됩니다.

콘텐츠 공유

모든 소셜 미디어 앱의 핵심은 콘텐츠를 공유하는 것입니다. 앱에서 사용자가 콘텐츠를 빠르게 공유할 수 없다면 앱은 성공할 수 없습니다.

소셜 미디어 앱을 구현할 때는 모범 UI/UX 사례를 따르세요. 버튼을 한두 번 누르는 것만큼이나 쉽게 게시물을 올릴 수 있어야 합니다.

검색 및 발견

훌륭한 검색 및 검색 알고리즘은 모든 성공적인 소셜 앱의 필수 요소입니다.

소셜 미디어 앱은 사용자가 관심 있는 콘텐츠를 쉽게 찾을 수 있어야 합니다. 또한 앱은 개인화된 피드와 고급 검색 기능을 제공해야 합니다.

알림

참여를 유도하고 앱 사용을 늘리려면 푸시 알림을 구현하는 것을 고려해야 합니다.

푸시 알림은 친구의 게시물이 올라오거나 이벤트가 있거나 한동안 앱을 사용하지 않은 경우 등 어떤 일이 발생했을 때 사용자에게 알릴 수 있는 강력한 커뮤니케이션 채널입니다.

푸시 알림과 프로젝트에 통합하는 방법에 대해 자세히 알아보려면 푸시 알림이란 무엇인가요?

소셜 미디어 앱은 어떻게 만드나요?

이 튜토리얼 섹션에서는 소셜 미디어 앱을 구축하는 방법을 단계별로 살펴보겠습니다. 백엔드로는 Back4app을 사용하고 프런트엔드에는 Next.js 프레임워크로 React를 사용하겠습니다.

전제 조건

이 프로젝트에 사용할 기술 스택은 다음과 같습니다:

Back4app이란 무엇인가요?

Back4app은 최신 웹 및 모바일 앱을 빠르게 구축할 수 있는 훌륭한 로우코드 백엔드입니다. 실시간 데이터베이스, 사용자 관리, 클라우드 코드 기능, 푸시 알림, 소셜 통합, API, SDK 등 다양한 기능이 포함되어 있습니다!

Back4app을 사용하면 백엔드 작업의 대부분을 아웃소싱하고 핵심 비즈니스 로직과 프론트엔드에 집중할 수 있습니다.

또한 기본 인프라나 앱 확장에 대해 걱정할 필요가 없습니다. Back4app은 이 모든 것을 지원합니다. 소셜 미디어 앱 개발 속도를 높일 수 있는 훌륭한 옵션입니다.

Back4app은 테스트 및 프로토타이핑에 적합한 무료 티어를 제공합니다. 앱이 확장되면 나중에 예측 가능한 가격의 프리미엄 티어로 업그레이드할 수 있습니다.

소셜 네트워크 구축에 Back4app을 사용하는 이유는 무엇인가요?

프로젝트 소개

이 글에서는 간단한 소셜 네트워크를 구축해 보겠습니다. 구현된 소셜 네트워크를 통해 사용자는 계정을 만들고, 자신을 인증하고, 프로필을 설정하고, 게시물을 작성할 수 있습니다.

백엔드에서는 Back4app을 사용하고, 프론트엔드에서는 Next.js 프레임워크와 함께 React를 사용하여 소셜 미디어 앱을 만들겠습니다.

먼저 Back4app 앱을 만들고 데이터베이스 모델을 설정한 다음 프론트엔드로 이동하겠습니다.

프런트엔드에서 Parse SDK를 설치하고, 인증을 설정하고, 로그인, 가입, 프로필 등 특정 보기에 대한 작업을 수행해야 합니다.

최종 결과물은 다음과 같습니다:

Back4app 소셜 네트워크

앱 만들기

다음 단계를 진행하려면 백4앱 계정이 필요합니다. 아직 계정이 없는 경우 지금 바로 무료로 계정을 만드세요.

Back4app 계정에 로그인하면 앱 목록이 표시됩니다. “새 앱 만들기”를 클릭하여 앱 생성 프로세스를 시작합니다.

Back4app 새 앱 구축

Back4app에서는 두 가지 유형의 앱을 만들 수 있습니다:

  1. 서비스형 백엔드(BaaS)
  2. 서비스형 컨테이너(CaaS)

BaaS는 본격적인 Parse 기반 백엔드 솔루션이며, CaaS는 Docker를 통해 컨테이너화된 애플리케이션을 배포하는 데 사용됩니다.

소셜 네트워크를 구축하는 것이므로 ‘서비스형 백엔드’ 옵션을 사용하겠습니다.

Back4app BaaS 구축

그런 다음 앱에 설명이 포함된 이름을 지정하고 데이터베이스로 “NoSQL”을 선택한 다음 “만들기”를 클릭합니다.

Back4app은 애플리케이션에 필요한 모든 것을 준비하는 데 약 2분이 소요됩니다. 완료되면 앱의 데이터베이스 보기로 리디렉션됩니다.

Back4app 데이터베이스 보기

데이터베이스 클래스

이제 소셜 미디어 애플리케이션을 개발하기 위한 데이터베이스를 준비해 보겠습니다.

이미 눈치챘겠지만 데이터베이스에 이미 두 개의 클래스가 있습니다. 첫 번째는 사용자이고 두 번째는 역할입니다. 기본적으로 모든 Back4app 클래스에는 다음과 같은 필드가 있습니다:

+-----------+-------------------------------------------------------------------------+
| Name      | Explanation                                                             |
+-----------+-------------------------------------------------------------------------+
| objectId  | Object's unique identifier                                              |
+-----------+-------------------------------------------------------------------------+
| updatedAt | Date time of the object's last update.                                  |
+-----------+-------------------------------------------------------------------------+
| createdAt | Date time of object's creation.                                         |
+-----------+-------------------------------------------------------------------------+
| ACLs      | Allow you to control the access to the object (eg. read, update).       |
+-----------+-------------------------------------------------------------------------+

설명avatarUrl 필드를 추가하여 User 클래스를 약간 수정해 보겠습니다. 사용자는 나중에 설정에서 이 두 필드를 편집할 수 있습니다.

화면 오른쪽 상단의 ‘+ 열’ 버튼을 클릭하고 다음 두 필드를 추가합니다:

+-----------+-------------+--------------------+----------+
| Data type | Name        | Default value      | Required |
+-----------+-------------+--------------------+----------+
| String    | description | Another cool user! | yes      |
+-----------+-------------+--------------------+----------+
| String    | avatarUrl   | <some_image_url>   | yes      |
+-----------+-------------+--------------------+----------+

를 를 .png, .jpg 또는 .jpeg로 끝나는 실제 이미지 URL로 바꿔야 합니다. 아이디어가 떠오르지 않는다면 이미지를 사용해도 됩니다.

Back4app 데이터베이스 열 추가

다음으로 Post라는 이름의 클래스를 만들어 보겠습니다. 각 게시물에는 작성자와 일부 텍스트 콘텐츠가 있습니다.

화면 왼쪽 상단의 “클래스 만들기” 버튼을 사용하여 클래스 만들기 프로세스를 시작합니다. 글을 게시하고‘보호됨’으로 설정한 다음 ‘클래스 만들기 및 열 추가’를 클릭합니다.

그런 다음 다음 두 열을 추가합니다:

+-----------------+---------+---------------+----------+
| Data type       | Name    | Default value | Required |
+-----------------+---------+---------------+----------+
| Pointer -> User | author  | <leave blank> | yes      |
+-----------------+---------+---------------+----------+
| String          | content | <leave blank> | yes      |
+-----------------+---------+---------------+----------+
Back4app 데이터베이스 생성 클래스

Back4app 데이터베이스 보안

Back4app 데이터베이스 보안과 관련하여 클래스 및 객체를 보호할 수 있는 두 가지 방법이 있습니다. 다음 중에서 선택할 수 있습니다:

  1. 클래스 수준 권한(CLP)
  2. 액세스 제어 수준(ACL)

CLP는 클래스 수준에서 액세스 제한을 정의하는 데 중점을 두므로 데이터 액세스 및 수정을 세밀하게 제어할 수 있습니다. 반대로 ACL은 특정 개체에 대한 액세스를 허용하거나 제한하며 사용자 정의 역할 또는 권한을 기반으로 합니다.

Parse 보안에 대해 자세히 알아보려면 Parse 서버 보안 문서를 확인하세요.

인증된 사용자만 글을 작성할 수 있고, 글 작성자만 글을 업데이트하고 삭제할 수 있어야 합니다. 이를 위해 게시물 CLP를 설정합니다.

사이드바에서 클래스 게시를 선택한 다음 화면 오른쪽 상단의 점 3개와 ‘보안 > 클래스 수준 권한’을 사용합니다. 다음과 같이 CLP를 설정합니다:

Back4app 포스트 CLP

이제 끝났습니다. 이제 백엔드가 완성되었습니다. 그리 어렵지 않았습니다.

코드 프론트엔드

이 글 섹션에서는 소셜 네트워크의 프론트엔드 부분을 다뤄보겠습니다.

프로젝트 초기화

먼저 create-next-app 도구를 사용하여 새 Next.js 프로젝트를 부트스트랩합니다:

$ npx create-next-app@latest back4app-social-network

√ Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... No
√ Would you like to use `src/` directory? ... No
√ Would you like to use App Router? (recommended) ... No
√ Would you like to customize the default import alias? ... No

Created a new Next.js app in ~\back4app-social-network.

이 도구는 여러 가지 질문을 묻는 메시지를 표시합니다. 제공되는 다른 기능은 사용하지 않을 것이며 프로젝트를 더 복잡하게 만들 수 있으므로 ESLint만 활성화하는 것이 좋습니다.

기본 Next.js 프로젝트에는 몇 가지 “쓸모없는” 파일과 디렉터리가 포함되어 있습니다. 프로젝트 크기를 줄이려면 다음을 삭제하세요:

  • 페이지/API 폴더
  • 스타일 폴더
  • public/next.svg
  • public/vercel.svg

또한 pages/_app.js에서 globals.css 가져오기를 제거하는 것을 잊지 마세요:

// pages/_app.js

import "@/styles/globals.css";  // remove this line

그런 다음 pages/index.js의 내용을 다음과 같이 바꿉니다:

// pages/index.js

export default function Home() {
  return (
    <>
      <p>Hello world!</p>
    </>
  );
}

다음 개발 서버를 시작합니다:

$ next dev

마지막으로 웹 브라우저를 열고 http://localhost:3000 으로 이동합니다. 모든 것이 정상적으로 작동하면 앱이 컴파일되고 “Hello world!” 메시지가 표시되어야 합니다.

차크라UI 설정

UI 구축 프로세스의 속도를 높이기 위해 ChakraUI를 사용하겠습니다. ChakraUI에는 사전 빌드된 컴포넌트, 스타일 시스템, 특수 후크 등이 포함된 훌륭한 React 라이브러리입니다.

NPM을 통해 설치하세요:

$ npm i @chakra-ui/react @chakra-ui/next-js @emotion/react @emotion/styled framer-motion

그런 다음 컴포넌트를 다음과 같이 차크라프로바이더로 래핑합니다:

// pages/_app.js

import {ChakraProvider} from "@chakra-ui/react";

function MyApp({Component, pageProps}) {
  return (
    <ChakraProvider>
      <Component {...pageProps} />
    </ChakraProvider>
  );
}

export default MyApp;

파일 상단에서 가져오는 것을 잊지 마세요:

import {ChakraProvider} from "@chakra-ui/react";

차크라가 올바르게 작동하려면 컬러 모드 스크립트를 포함해야 합니다. 이 스크립트는 로컬 스토리지 동기화가 올바르게 작동하도록 하고 ‘색상 깜박임’을 제거합니다.

페이지/_document.js를 다음과 같이 수정합니다:

// pages/_document.js

import { Html, Head, Main, NextScript } from "next/document";
import {ColorModeScript, extendTheme} from "@chakra-ui/react";

export const theme = extendTheme();

export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        <ColorModeScript initialColorMode={theme}/>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

초기 차크라 설정은 여기까지입니다.

리액트 아이콘

앱을 좀 더 멋지게 만들기 위해 리액트 아이콘을 설치하겠습니다. React 아이콘은 프로젝트에 인기 있는 아이콘을 빠르게 포함할 수 있는 라이브러리입니다. 여기에는 Ant, 부트스트랩, 영웅 아이콘, 폰트 어썸 아이콘 등이 포함되어 있습니다.

실행하여 설치합니다:

$ npm install react-icons --save

그런 다음 아이콘을 가져와서 이렇게 사용할 수 있습니다:

import {FaMusic} from "react-icons/fa";

return (
    <FaMusic/>
);

아이콘 목록은 공식 문서에서 확인하세요.

레이아웃 및 구성 요소

대부분의 소셜 네트워크에는 표준화된 레이아웃이 있습니다. 모든 페이지의 상단에는 동일한 헤더가 있고 하단에는 동일한 바닥글이 있습니다. 레이아웃을 구현해 보겠습니다.

먼저 프로젝트 루트에 구성 요소라는 폴더를 만듭니다. 그런 다음 그 안에 다음 파일을 만듭니다:

components/
├── header.js
├── footer.js
└── layout.js

다음으로 header.js 파일에 다음을 입력합니다:

// components/header.js

import NextLink from "next/link";
import {Box, Container, Divider, Heading, HStack, Link} from "@chakra-ui/react";

export default function Header() {
  return (
    <Box py={4}>
      <Container 
        maxW="container.lg" 
        display="flex" 
        alignItems="center" 
        justifyContent="space-between"
      >
        <Heading as="h1" size="md">
          <Link as={NextLink} href="/">
            back4app-social-network
          </Link>
        </Heading>
        <HStack spacing="1em">
          <Heading size="sm">
            <Link as={NextLink} href="/login">
              Log in
            </Link>
          </Heading>
          <Heading size="sm">
            <Link as={NextLink} href="/signup">
              Sign up
            </Link>
          </Heading>
        </HStack>
      </Container>
      <Divider my={4}/>
    </Box>
  );
}

그런 다음 footer.js 파일에 대해서도 동일한 작업을 수행합니다:

// components/footer.js

import NextLink from "next/link";
import {Box, Container, Divider, Heading,
  HStack, Link, Tag, Text, VStack} from "@chakra-ui/react";
import {FaGithub} from "react-icons/fa";

export default function Footer() {
  return (
    <Box py={4}>
      <Divider my={4}/>
      <Container
        maxW="container.lg"
        display="flex"
        justifyContent="space-between"
        alignItems="center"
      >
        <VStack alignItems="left">
          <Heading size="sm">
            A simple social network powered by Back4app.
          </Heading>
          <Link
            as={NextLink}
            href="https://blog.back4app.com/how-to-develop-a-social-media-app/"
          >
            Click here to learn how to build it!
          </Link>
        </VStack>
        <Link href="https://github.com/duplxey/back4app-social-network">
          <Tag background="black" color="white" py={2}>
            <HStack>
              <FaGithub size="1.5em"/>
              <Text>View on GitHub</Text>
            </HStack>
          </Tag>
        </Link>
      </Container>
    </Box>
  );
}

여기서 설명할 수 있는 것은 많지 않습니다. 내장된 Chakra 컴포넌트를 사용하여 멋진 머리글과 바닥글을 만들었습니다. Next.js를 사용하고 있으므로 Chakra의 링크와 Next의 링크를 결합했습니다.

마지막으로 새로 만든 머리글 및 바닥글 컴포넌트를 사용하여 레이아웃을 구성합니다:

// components/layout.js

import {Container} from "@chakra-ui/react";
import Header from "@/components/header";
import Footer from "@/components/footer";

export default function Layout({children}) {
  return (
    <>
      <Header/>
      <Container maxW="container.lg">
        {children}
      </Container>
      <Footer/>
    </>
  );
}

그런 다음 index.js에 레이아웃을 적용합니다:

// pages/index.js

import Layout from "@/components/layout";

export default function Home() {
  return (
    <Layout>
      <p>Hello world!</p>
    </Layout>
  );
}

다음 개발 서버가 코드를 다시 컴파일할 때까지 기다린 다음 http://localhost:3000 을 방문합니다. 모든 것이 정상적으로 작동하면 새 레이아웃이 적용된 것을 확인할 수 있습니다.

백4앱 소셜 네트워크 헬로월드

Parse.js 설정

먼저 NPM을 통해 Parse를 설치하세요:

$ npm install parse

다음으로 _app.js 가져오기 아래에 다음 구성을 추가합니다:

// pages/_app.js

// ...

import Parse from "parse/dist/parse";

const PARSE_APPLICATION_ID = process.env.NEXT_PUBLIC_PARSE_APPLICATION_ID;
const PARSE_JAVASCRIPT_KEY = process.env.NEXT_PUBLIC_PARSE_JAVASCRIPT_KEY;
Parse.initialize(PARSE_APPLICATION_ID, PARSE_JAVASCRIPT_KEY);
Parse.serverURL = "https://parseapi.back4app.com/";

// ...

자격 증명을 하드 코딩하는 대신 환경 변수를 사용했습니다. Next.js를 사용하면 환경 변수를 활성화하기 위해 아무것도 구성할 필요가 없습니다. .env.local 파일에서 자동으로 로드됩니다.

프로젝트 루트에 다음 내용으로 .env.local 파일을 만듭니다:

NEXT_PUBLIC_PARSE_APPLICATION_ID=<parse_app_id>
NEXT_PUBLIC_PARSE_JAVASCRIPT_KEY=<parse_javascript_key>

교체해야 합니다. 및 를 실제 ID와 키로 바꾸세요. 자격 증명을 얻으려면 Back4app 앱으로 이동하여 사이드바에서 ‘앱 설정 > 보안 및 키’를 선택합니다.

컨텍스트

컴포넌트 계층 구조의 여러 레이어를 통해 Parse 인스턴스를 전달하는 대신 React 컨텍스트를 사용하겠습니다. React 컨텍스트를 사용하면 프롭을 통해 데이터를 전달하지 않고도 한 컴포넌트에서 다른 컴포넌트로 데이터를 ‘텔레포트’할 수 있습니다.

먼저 context라는 이름의 새 폴더를 만들고 그 안에 parseContext.js 파일을 넣습니다:

// context/parseContext.js

import {createContext} from "react";

const ParseContext = createContext();

export default ParseContext;

그런 다음 컴포넌트를 파스컨텍스트.프로바이더로 래핑하고 파스 인스턴스를 전달합니다:

// pages/_app.js

// ...

function MyApp({Component, pageProps}) {
  return (
    <ChakraProvider>
      <ParseContext.Provider value={Parse}>
        <Component {...pageProps} />
      </ParseContext.Provider>
    </ChakraProvider>
  );
}

export default MyApp;

다시 말하지만, ParseContext 가져오기를 잊지 마세요:

import ParseContext from "@/context/parseContext";

이제 뷰에서 useContext() 훅을 통해 Parse 인스턴스를 가져올 수 있습니다. index.js에서 Parse 연결을 테스트해 보겠습니다.

pages/index.js의 내용을 다음과 같이 바꿉니다:

// pages/index.js

import {useContext} from "react";
import ParseContext from "@/context/parseContext";
import {Button} from "@chakra-ui/react";
import Layout from "@/components/layout";

export default function Home() {

  const parse = useContext(ParseContext);

  async function testConnection() {
    try {
      await new parse.Query("TestClass").first();
      console.log("Connection successful");
    } catch (error) {
      console.error("Connection failed: " + error);
    }
  }

  return (
    <Layout>
      <p>Hello world!</p>
      <Button onClick={() => testConnection()}>Parse.js test</Button>
    </Layout>
  );
}

다음 개발 서버가 다시 컴파일될 때까지 기다렸다가 http://localhost:3000 을 방문합니다 . 그런 다음 콘솔을 열고 “Parse.js 테스트” 버튼을 클릭합니다. 모든 것이 정상적으로 진행되면 “연결 성공” 메시지가 표시됩니다.

인증

“Back4app이란 무엇인가요?” 섹션에서 언급했듯이 Back4app에는 인증 시스템이 내장되어 있습니다. 사용자 인증 설정은 몇 가지 메소드를 호출하는 것만큼이나 간단합니다. 세션 저장도 Parse SDK를 통해 자동으로 처리됩니다.

사용자 인증 양식에 대해 작업해 보겠습니다.

먼저 signup.js라는 새 페이지를 만들고 그 안에 다음을 넣습니다:

// pages/signup.js

import NextLink from "next/link";
import {useState} from "react";
import {Button, Card, CardBody, CardFooter, CardHeader, FormControl, 
    FormLabel, Heading, HStack, Input, Link, Text, VStack,
} from "@chakra-ui/react";
import {FaUserPlus} from "react-icons/fa";
import Layout from "@/components/layout";

export default function SignUp() {

  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const onSubmit = async (event) => {
    // implement logic
  };

  return (
    <Layout>
      <Card>
        <CardHeader>
          <HStack>
            <FaUserPlus/>
            <Heading as="h2" size="md"> Sign up</Heading>
          </HStack>
        </CardHeader>
        <CardBody py={0}>
          <VStack spacing="1em" alignItems="left">
            <FormControl>
              <FormLabel>Username</FormLabel>
              <Input
                placeholder="Username"
                value={username}
                onChange={(e) => setUsername(e.target.value)}
              />
            </FormControl>
            <FormControl>
              <FormLabel>Password</FormLabel>
              <Input
                type="password"
                placeholder="Password"
                value={password}
                onChange={(e) => setPassword(e.target.value)}
              />
            </FormControl>
          </VStack>
        </CardBody>
        <CardFooter 
            w="full" 
            display="flex" 
            alignItems="center" 
            justifyContent="space-between"
        >
          <Text>
            Already have an account?{" "}
            <Link as={NextLink} href="/login">
              Log in
            </Link>
          </Text>
          <Button colorScheme="teal" onClick={onSubmit}>Sign up</Button>
        </CardFooter>
      </Card>
    </Layout>
  );
}

이 코드는 /signup에 새 페이지를 생성하고 가입 양식을 렌더링합니다. 계정을 만들려면 사용자는 사용자 아이디와 비밀번호를 입력해야 합니다.

그런 다음 로직을 포함하도록 pages/signup.js를 수정합니다:

// pages/signup.js

// ...

import {useRouter} from "next/router";
import {useContext, useEffect} from "react";
import ParseContext from "@/context/parseContext";

export default function SignUp() {

  const router = useRouter();
  const parse = useContext(ParseContext);

  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  // redirect the user if already logged in
  useEffect(() => {
    (async () => {
      if (parse.User.current() !== null) {
        await router.push("/");
      }
    })();
  }, [router, parse.User]);

  const onSubmit = async (event) => {
    event.preventDefault();

    if (!username || !password) {
      console.error("Please fill out all the fields.");
      return;
    }

    try {
      await parse.User.signUp(username, password).then(() => {
        router.push("/");
        console.log("Successfully signed up.");
      });
    } catch (error) {
      console.error(error.message);
    }
  };

  return (
    // ...
  );
}
  1. 사용자가 이미 로그인한 상태라면 이제 Next의 사용 라우터() 훅을 통해 리디렉션됩니다.
  2. 사용자 세션을 생성하고 사용자 브라우저에 쿠키를 저장하는 User.signUp()을 호출하도록 onSubmit()을 수정했습니다.

pages/login.js 파일에 대해서도 동일한 작업을 수행합니다. GitHub 리포지토리에서 소스 코드를 가져옵니다.

이제 인증 시스템이 어느 정도 완성되었습니다. 마지막으로 header.js를 약간 수정하여 로그인한 사용자 또는 인증되지 않은 경우 로그인/가입 링크를 표시하는 작업을 수행합니다.

components/header.js를 다음과 같이 수정합니다:

// components/header.js

import NextLink from "next/link";
import {Avatar, Box, Container, Divider, Heading, HStack, Link} from "@chakra-ui/react";
import {useContext, useEffect, useState} from "react";
import ParseContext from "@/context/parseContext";

export default function Header() {

  const parse = useContext(ParseContext);
  const [user, setUser] = useState(null);

  useEffect(() => {
    setUser(parse.User.current());
  }, [parse.User]);

  return (
    <Box py={4}>
      <Container 
        maxW="container.lg" 
        display="flex" 
        alignItems="center" 
        justifyContent="space-between"
      >
        <Heading as="h1" size="md">
          <Link as={NextLink} href="/">
            back4app-social-network
          </Link>
        </Heading>
        {user != null ? (
          <HStack>
            <Avatar 
              size="sm" 
              name={user.attributes.username} 
              src={user.attributes.avatarUrl}
            />
            <Heading size="sm">
              <Link as={NextLink} href="/settings">
                {user.attributes.username}
              </Link>
            </Heading>
          </HStack>
        ) : (
          <HStack spacing="1em">
            <Heading size="sm">
              <Link as={NextLink} href="/login">
                Log in
              </Link>
            </Heading>
            <Heading size="sm">
              <Link as={NextLink} href="/signup">
                Sign up
              </Link>
            </Heading>
          </HStack>
        )}
      </Container>
      <Divider my={4}/>
    </Box>
  );
}

다음 개발 서버가 인증 시스템을 다시 컴파일하고 테스트할 때까지 기다립니다. 계정을 만들고 헤더가 변경되는지 확인합니다.

아직 로그아웃 기능이 제공되지 않으므로 로그아웃하려면 쿠키를 수동으로 삭제해야 합니다.

Back4app 소셜 네트워크 동적 헤더

사용자를 생성한 후에는 Back4app 데이터베이스 보기로 이동하여 사용자 클래스 행을 확인할 수 있습니다. 새 사용자가 추가된 것을 확인할 수 있습니다.

Back4app 데이터베이스 신규 사용자

사용자 설정

User 클래스에 추가한 descriptionavatarUrl 필드를 편집 가능하게 만들어 보겠습니다.

페이지 디렉터리에 settings.js라는 새 파일을 만듭니다:

// pages/settings.js

import React, {useContext, useEffect, useState} from "react";
import {useRouter} from "next/router";
import {Button, Card, CardBody, CardFooter, CardHeader, FormControl, FormLabel,
  Heading, HStack, Input, VStack} from "@chakra-ui/react";
import {FaCog} from "react-icons/fa";
import ParseContext from "@/context/parseContext";
import Layout from "@/components/layout";

export default function Settings() {

  const router = useRouter();
  const parse = useContext(ParseContext);

  const [description, setDescription] = useState("");
  const [avatarUrl, setAvatarUrl] = useState("");

  useEffect(() => {
    (async () => {
      const user = parse.User.current();

      // redirect the user if not logged in
      if (user === null) {
        await router.push("/");
        return;
      }

      // load data from the database
      setDescription(await user.get("description"));
      setAvatarUrl(await user.get("avatarUrl"));
    })();
  }, [router, parse.User]);

  const onSave = async () => {
    const user = parse.User.current();
    user.set("description", description);
    user.set("avatarUrl", avatarUrl);
    await user.save();

    console.log("Successfully saved settings.");
  };

  const onLogout = async () => {
    await parse.User.logOut();
    await router.push("/");

    console.log("Successfully logged out.");
  };

  return (
    <Layout>
      <Card>
        <CardHeader>
          <HStack>
            <FaCog/>
            <Heading as="h2" size="md"> Settings</Heading>
          </HStack>
        </CardHeader>
        <CardBody py={0}>
          <VStack spacing="1em">
            <FormControl>
              <FormLabel>Description</FormLabel>
              <Input
                placeholder="Description"
                value={description}
                onChange={e => setDescription(e.target.value)}
              />
            </FormControl>
            <FormControl>
              <FormLabel>Avatar URL</FormLabel>
              <Input
                placeholder="Avatar URL"
                value={avatarUrl}
                onChange={e => setAvatarUrl(e.target.value)}
              />
            </FormControl>
          </VStack>
        </CardBody>
        <CardFooter display="flex" justifyContent="right">
          <HStack>
            <Button colorScheme="red" onClick={onLogout}>Log out</Button>
            <Button colorScheme="teal" onClick={onSave}>Save</Button>
          </HStack>
        </CardFooter>
      </Card>
    </Layout>
  );
}
  1. 사용자가 인증되지 않은 경우 리디렉션하기 위해 React의 useEffect() 훅을 사용했습니다. 또한 이 훅은 사용자의 설명과 avatarUrl을 가져옵니다.
  2. 상태 데이터로 사용자 정보를 업데이트하는 onSave() 메서드를 구현했습니다.
  3. Parse의 logOut()을 호출하는 onLogout() 메서드를 구현했습니다. Parse의 logOut() 은 데이터베이스에서 세션을 삭제하고 사용자의 브라우저에서 쿠키를 제거합니다.

게시물

간단한 소셜 네트워크가 완성되기 전에 마지막으로 해야 할 일은 게시물을 구현하는 것입니다. 이미 데이터베이스 클래스를 만들었습니다. 이제 게시물을 생성하기 위한 양식을 만들고 데이터베이스에서 가져오는 작업만 남았습니다.

먼저 post.js라는 새 컴포넌트를 추가합니다:

// components/post.js

import {Avatar, Box, Card, CardBody, CardHeader, Heading, HStack, Text} from "@chakra-ui/react";

export default function Post(props) {
  return (
    <Card mt={2}>
      <CardHeader pb={0}>
        <HStack spacing="1em">
          <Avatar name={props.author.username} src={props.author.avatarUrl}/>
          <Box>
            <Heading size="sm">{props.author.username}</Heading>
            <Text>{props.author.description}</Text>
          </Box>
        </HStack>
      </CardHeader>
      <CardBody>
        <Text>{props.content}</Text>
      </CardBody>
    </Card>
  );
}

그런 다음 index.js를 다음과 같이 수정합니다:

// pages/index.js

import {useContext, useEffect, useState} from "react";
import {Alert, AlertIcon, Button, Card, CardBody, CardFooter,
  CardHeader, Heading, HStack, Textarea} from "@chakra-ui/react";
import {FaPlus} from "react-icons/fa";
import ParseContext from "@/context/parseContext";
import Layout from "@/components/layout";
import Post from "@/components/post";

export default function Home() {

  const parse = useContext(ParseContext);

  const [user, setUser] = useState(null);
  const [postContent, setPostContent] = useState("");
  const [posts, setPosts] = useState([]);

  const onCreatePost = async () => {
      // implement logic
  };

  return (
    <Layout>
      {user ? (
        <Card mb={2}>
          <CardHeader>
            <HStack>
              <FaPlus/>
              <Heading as="h2" size="md"> Create post</Heading>
            </HStack>
          </CardHeader>
          <CardBody py={0}>
            <Textarea
              placeholder="What's on your mind?"
              value={postContent}
              onChange={(event) => setPostContent(event.target.value)}
            />
          </CardBody>
          <CardFooter display="flex" justifyContent="right">
            <Button colorScheme="teal" onClick={onCreatePost}>Post</Button>
          </CardFooter>
        </Card>
      ) : (
        <Alert status="warning" mb={2}>
          <AlertIcon/>
          You need to log in to create posts.
        </Alert>
      )}
      {posts.map(post => (
        <Post
          key={post.id}
          content={post.attributes.content}
          author={{...post.attributes.author.attributes}}
        />
      ))}
    </Layout>
  );
}

그런 다음 다음과 같이 onCreatePost() 를 구현합니다:

const onCreatePost = async () => {
  if (!user == null) return;

  const post = new parse.Object("Post");
  post.set("content", postContent);
  post.set("author", user);
  await post.save();

  setPostContent("");
  setPosts([post, ...posts]);
};

마지막으로, 사용효과() 훅을 추가하여 게시물을 가져옵니다:

useEffect(() => {
  setUser(parse.User.current());

  (async () => {
    const posts = await new parse.Query("Post")
      .include("author").descending("createdAt").find();
    setPosts(posts);
  })();
}, []);

객체 및 쿼리 구문 분석에 대해 자세히 알아보려면 공식 구문 분석 문서를 확인하세요.

다음 개발 서버를 다시 한 번 시작합니다:

$ next start

몇 개의 샘플 글을 작성하고 페이지를 새로 고칩니다. 모든 것이 정상적으로 작동하면 게시물이 데이터베이스에 저장되고 페이지를 방문할 때 가져와야 합니다.

Back4app 데이터베이스 게시물

결론

이 글에서는 간단한 소셜 미디어 앱을 성공적으로 구축했습니다. 이 앱을 통해 사용자는 가입, 본인 인증, 프로필 편집, 게시물 작성 등의 작업을 수행할 수 있습니다.

지금쯤이면 Back4app의 작동 방식과 소셜 네트워크 구축을 시작하는 방법에 대해 어느 정도 이해하셨을 것입니다.

이 글에서 구축한 프로젝트는 향후 개발을 위한 탄탄한 토대가 될 수 있습니다. 좋아요/싫어요 기능, 공유 기능, 댓글 등 새로운 기능을 구현하여 지식을 테스트해 보세요.

소스 코드는 back4app-social-network GitHub 리포지토리에서 확인할 수 있습니다.

향후 단계

  1. 이 문서에 따라 Next.js 프론트엔드를 Back4app 컨테이너에 배포하세요.
  2. 클라우드 코드 함수를 살펴보고 백엔드에 고급 기능을 추가하세요.
  3. 가입 시 사용자 이메일 인증을 시행하여 봇을 방지하세요.

Leave a reply

Your email address will not be published.