ソーシャルメディア・アプリを開発するには?

ソーシャルメディア・アプリのカバーを作る

この記事では、ソーシャル・ネットワーク、ソーシャルメディア・アプリの種類、その利点、必須の機能についてお話します。

その上で、ソーシャルネットワークの作り方を順を追って見ていきます。バックエンドにはBack4app、フロントエンドにはNext.jsを使います。

ソーシャルネットワークとは何か?

ソーシャル・ネットワークは、人々が互いにつながり、交流することを可能にするソーシャルメディア・アプリである。

2人のユーザーが接続すると、ユーザー情報を共有したり、メッセージや画像を交換したり、投稿を共有したりすることができる。

昨今、ソーシャルメディア・アプリの人気は高い。ほとんどの人が少なくとも1つのソーシャルメディアアプリに登録している。Bufferの調査によると、最も人気のあるソーシャルメディアプラットフォームは以下の通り:

  • フェイスブック(29.6億MAU)
  • ユーチューブ(22億MAU)
  • インスタグラム(20億MAU)
  • TikTok(10億MAU)
  • スナップチャット(MAU5億人)

MAUとは、月間アクティブユーザーのこと。これは、ソーシャルメディアプラットフォームと月間で交流するユニークユーザーの数です。

ソーシャルメディアアプリ市場が巨大であるにもかかわらず、ソーシャルメディアアプリの開発は困難な作業である。

最も複雑なITプロジェクトのひとつだ。多くの企業は、ソーシャル・ネットワーキング・アプリの構築がいかに難しいかを過小評価し、そして莫大な損失を出して惨敗する。

ソーシャルメディア・アプリケーションの種類

前節で述べたように、ソーシャルネットワークはソーシャルメディアアプリの種類の一つに過ぎない。他のソーシャルメディアアプリの種類は以下の通り:

  • メディア共有ネットワーク(Instagram、TikTok、YouTube)
  • コンテンツ共有ネットワーク(Pinterest、Tumblr、Flickr)
  • 消費者レビューネットワーク(Trustpilot、Angi、Choice)
  • ブログと出版ネットワーク(ミディアム、ツイッター)
  • ディスカッション・フォーラム(Reddit、Quora、HackerNews)
  • 恋愛ネットワーク(Tinder、Bumble)

ソーシャルメディアアプリ開発のメリット

ソーシャルメディアアプリの構築にはいくつかのメリットがある。広告収入、収益化、貴重なユーザー情報の収集、高度な分析、他社とのスポンサーシップなどだ。

ソーシャルメディアアプリのもう一つの素晴らしい点は、その圧倒的な再販価値だ。アプリが比較的成功すれば(つまり、それなりのユーザーベースがあれば)、すぐに他社に売ることができる。例えば、ツイッターは440億ドルで売却され、マイスペースは8,700万ドルで売却された。

開発者の立場からすると、シンプルなソーシャルネットワークを構築することで、自分が使っているツールを知ることができ、このようなものを構築することがいかに難しいかを知ることができる。

ソーシャルメディアアプリの必須機能

ソーシャルメディア・アプリケーションの機能性は千差万別だ。それでも、成功するソーシャルメディアアプリには欠かせない機能がいくつかある。

ユーザーアカウント

すべてのソーシャルメディアアプリは、ユーザーがアカウントを作成することができます。アカウントを作成すると、ユーザーは個人情報を追加し、自分のニーズに合わせてアプリをカスタマイズすることができる。例えば、自分の好きな機能を選んだり、自分の興味を追加したり、特定のコンテンツを非表示にしたりすることができる。

ビジネスの観点から見たユーザーアカウントの最大のメリットは、「ユーザープロファイル」を構築できることだ。ユーザープロフィール」とは、特定のユーザーが何を好み、誰と交流しているかを把握し、それに応じて広告を調整することを意味する。

ユーザーとの接続

ソーシャル・メディア・アプリを使えば、ユーザーはつながることができる。例えば、誰かを友達に追加したり、フォローしたり、購読したりすることができる。いったん2人のユーザーがつながると、それに応じてフィードも変更される。

コンテンツの共有

すべてのソーシャルメディアアプリのポイントは、コンテンツを共有することです。ユーザーがコンテンツを素早く共有できないアプリは、間違いなく成功しない。

ソーシャルメディアアプリを導入する際は、UI/UXのベストプラクティスに従おう。何かを投稿するのは、ボタンを1つか2つ押すのと同じくらい簡単であるべきだ。

検索と発見

優れた検索と発見のアルゴリズムは、成功するソーシャルアプリに不可欠な要素だ。

ソーシャルメディアアプリは、ユーザーが興味のあるコンテンツを簡単に見つけられるようにする必要があります。その上で、アプリはパーソナライズされたフィードと高度な検索機能を提供すべきです。

お知らせ

エンゲージメントを促進し、アプリの利用を増やすためには、プッシュ通知の導入を検討する必要があります。

プッシュ通知は、友達に投稿された、イベントがあった、しばらくアプリを使っていないなど、ユーザーに何かが起こったときに通知できる強力なコミュニケーション・チャネルです。

プッシュ通知についての詳細と、それをプロジェクトに統合する方法については、プッシュ通知とは?

ソーシャルメディアアプリの作り方

このチュートリアルでは、ソーシャルメディアアプリの作り方を順を追って見ていきます。バックエンドにはBack4appを使用し、フロントエンドにはNext.jsフレームワークと Reactを使用します。

前提条件

これがこのプロジェクトで使用する技術スタックだ:

Back4appとは?

Back4appは、モダンなウェブアプリやモバイルアプリを迅速に構築するための優れたローコードバックエンドです。リアルタイムデータベース、ユーザー管理、Cloud Code機能、プッシュ通知、ソーシャル統合、API、SDKなど、多くの機能を備えています!

Back4appを使用することで、バックエンド業務のほとんどをアウトソースし、コアビジネスロジックとフロントエンドに集中することができます。

また、基盤となるインフラやアプリのスケーリングを心配する必要もありません。Back4appがその全てをカバーします。ソーシャルメディアアプリ開発をスピードアップするための素晴らしい選択肢です。

Back4appはテストやプロトタイピングに最適な無料ティアを提供しています。アプリの規模が大きくなれば、予測可能な価格設定のプレミアム層にアップグレードすることができます。

ソーシャルネットワークの構築にBack4appを使う理由は?

プロジェクト紹介

この記事では、シンプルなソーシャルネットワークを構築します。実装したソーシャルネットワークでは、ユーザーがアカウントを作成し、自分自身を認証し、プロフィールを設定し、投稿を作成できるようにします。

バックエンドではBack4appを使用し、フロントエンドではReactとNext.jsフレームワークを使ってソーシャルメディアアプリを作成します

まずBack4appアプリを作成し、データベースモデルを設定し、次にフロントエンドに移る。

フロントエンドでは、Parse SDKをインストールし、認証を設定し、ログイン、サインアップ、プロファイルなどの特定のビューを作成する必要があります。

最終的にはこのようになる:

Back4app ソーシャルネットワーク

アプリ作成

次のステップでは、Back4appのアカウントが必要です。まだお持ちでない方は、無料でアカウントを作成してください。

Back4appアカウントにログインすると、アプリ一覧が表示されます。Build new app “をクリックしてアプリの作成プロセスを開始します。

Back4app 新しいアプリを作る

Back4appでは2種類のアプリを作成できます:

  1. サービスとしてのバックエンド(BaaS)
  2. サービスとしてのコンテナ(CaaS)

BaaSはParseを利用した本格的なバックエンド・ソリューションであり、CaaSはDocker経由でコンテナ化されたアプリケーションをデプロイするために使用される。

私たちはソーシャル・ネットワークを構築しているので、”Backend as a Service “オプションを使うことにする。

Back4app Build BaaS

次に、アプリに分かりやすい名前を付け、データベースとして「NoSQL」を選択し、「Create」をクリックする。

Back4appはアプリケーションに必要なものを全て準備するのに約2分かかります。それが終わると、アプリのデータベースビューにリダイレクトされます。

Back4appデータベースビュー

データベースクラス

続いて、ソーシャルメディア・アプリケーションを開発するためのデータベースを準備しよう。

お気づきかもしれませんが、2つのクラスがすでにデータベースにあります。1つ目はUser、2つ目はRoleです。デフォルトでは、すべての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).       |
+-----------+-------------------------------------------------------------------------+

descriptionと avatarUrlフィールドを追加して、Userクラスを少し変更してみましょう。ユーザーは後で設定でこの2つのフィールドを編集できるようになります。

画面右上の「+列」ボタンをクリックし、以下の2つのフィールドを追加する:

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

必ず を.png.jpg.jpeg で終わる実際の画像URLに置き換えてください。アイディアがない場合は、こちらをお使いください。

Back4app データベース カラムの追加

次に、Postというクラスを作りましょう。それぞれの投稿には作者とテキスト・コンテンツがある。

画面左上の “Create a class “ボタンでクラス作成プロセスを開始します。クラス名を「Post」とし、「Protected」にして、「Create class & add columns」をクリックします。

そこに次の2列を追加する:

+-----------------+---------+---------------+----------+
| Data type       | Name    | Default value | Required |
+-----------------+---------+---------------+----------+
| Pointer -> User | author  | <leave blank> | yes      |
+-----------------+---------+---------------+----------+
| String          | content | <leave blank> | yes      |
+-----------------+---------+---------------+----------+
Back4app データベース作成クラス

Back4app データベースのセキュリティ

Back4appデータベースのセキュリティに関して、クラスとオブジェクトを保護する方法は2つあります。下記から選択できます:

  1. クラス・レベル権限(CLP)
  2. アクセス制御レベル(ACL)

CLPはクラスレベルでのアクセス制限の定義に重点を置き、データへのアクセスや変更をきめ細かく制御することができます。逆に、ACL は特定のオブジェクトへのアクセスを許可または制限するもので、ユーザー定義のロールや権限に基づいています。

Parseのセキュリティについて詳しくは、Parse Server Securityの記事をご覧ください。

認証されたユーザだけが投稿を作成でき、投稿作成者だけが更新と削除ができるようにしたい。そのために、投稿CLPを設定します。

サイドバーでPostクラスを選択し、画面右上の3つの点から「Security > Class Level Permissions」を選択します。このように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プロジェクトには、いくつかの「無駄な」ファイルとディレクトリが含まれています。プロジェクトのサイズを小さくするには、以下を削除してください:

  • pages/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開発サーバーを起動します:

$ next dev

最後に、ウェブ・ブラウザを開き、http://localhost:3000。すべてがうまくいけば、アプリがコンパイルされ、「Hello world!

ChakraUIのセットアップ

UI構築プロセスをスピードアップするために、ChakraUIを使おう。ChakraUIは、ビルド済みのコンポーネント、スタイル付きシステム、特化したフックなどを備えた優れたReactライブラリだ。

NPM経由でインストールする:

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

次に、Componentを ChakraProviderで次のようにラップする:

// 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";

Chakraが正しく動作するためには、カラーモードスクリプトを含める必要があります。このスクリプトは、ローカルストレージの同期が正しく機能するようにし、「色の点滅」を取り除きます。

pages/_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-iconsをインストールしよう。React iconsは、人気のあるアイコンをプロジェクトに素早く取り入れることができるライブラリだ。Ant、Bootstrap、Heroicons、Font Awesomeアイコンなどが付属しています。

を実行してインストールする:

$ npm install react-icons --save

そうすれば、どんなアイコンでもインポートして使うことができる:

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

return (
    <FaMusic/>
);

アイコンのリストについては、公式ドキュメントを参照されたい。

レイアウトとコンポーネント

ほとんどのソーシャルネットワークは、標準的なレイアウトを持っています。すべてのページの上部のヘッダーと下部のフッターは同じです。私たちのレイアウトを実装してみましょう。

まず、プロジェクトルートにcomponentsという名前のフォルダを作成します。そして、その中に以下のファイルを作成します:

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のLinkとNextのLinkを組み合わせました。

最後に、新しく作成したヘッダーとフッターのコンポーネントを使い、レイアウトを形成する:

// 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/>
    </>
  );
}

次に、Layoutを index.jsに適用する:

// pages/index.js

import Layout from "@/components/layout";

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

ネクスト開発サーバーがコードを再コンパイルするまで待ってから、http://localhost:3000。すべてがうまくいっていれば、新しいレイアウトが適用されていることが確認できるはずです。

Back4app ソーシャルネットワーク ハローワールド

Parse.jsのセットアップ

まずはNPM経由でParseをインストールする:

$ npm install parse

次に、_app.jsのimportsの下に以下の設定を追加する:

// 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コンテキストを使えば、あるコンポーネントから別のコンポーネントへ、propsを介さずにデータを「テレポート」できる。

まず、contextという名前の新しいフォルダを作成し、その中にparseContext.jsファイルを入れる:

// context/parseContext.js

import {createContext} from "react";

const ParseContext = createContext();

export default ParseContext;

次に、Componentを ParseContext.Providerでラップし、Parseインスタンスを渡します:

// 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>
  );
}

Next開発サーバーがリコンパイルされ、http://localhost:3000。コンソールを開き、「Parse.js test」ボタンをクリックします。すべてがうまくいけば、「Connection successful(接続に成功しました)」というメッセージが表示されるはずです。

認証

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のuseRouter()フックを使って/にリダイレクトされます。
  2. onSubmit()を User.signUp()を呼び出すように修正し、ユーザー・セッションを作成し、ユーザーのブラウザにクッキーを保存しました。

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>
  );
}

Next開発サーバーが再コンパイルし、認証システムをテストするのを待ちます。アカウントを作成し、ヘッダーが変更されるか確認してみてください。

ログアウト機能はまだありませんので、ログアウトしたい場合は手動でクッキーを削除する必要があります。

Back4app ソーシャルネットワーク ダイナミックヘッダー

ユーザーを作成したら、Back4appのデータベースビューに移動し、Userクラスの行を確認してください。新しいユーザが追加されていることがわかります。

Back4app データベース 新規ユーザー

ユーザー設定

Userクラスに追加したdescriptionと avatarUrlフィールドを編集可能にしてみましょう。

pagesディレクトリに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()フックを使って、ユーザーが認証されていない場合にリダイレクトするようにした。その上、このフックはユーザーの説明と アバターURLを取得します。
  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()フックを追加します:

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

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

Parseオブジェクトとクエリーの詳細については、Parseの公式ドキュメントをご覧ください。

Next開発サーバーをもう一度起動します:

$ next start

いくつかのサンプル投稿を作成し、ページを更新する。すべてがうまくいけば、投稿はデータベースに保存され、ページにアクセスしたときに取得されるはずです。

Back4appデータベースの投稿

結論

この記事では、シンプルなソーシャルメディアアプリの構築に成功した。このアプリでは、ユーザーがサインアップし、自分自身を認証し、プロフィールを編集し、投稿を作成することができます。

ここまでで、Back4appの仕組みとソーシャルネットワーク構築の始め方について、きちんと理解できたはずです。

この記事で構築したプロジェクトは、さらなる開発のための強固な基盤として役立つだろう。新しい機能、例えば、「いいね!」/「嫌い」機能、共有機能、コメントなどを実装して、あなたの知識を試してみてください。

ソースコードはback4app-social-networkのGitHubリポジトリで公開されている。

今後のステップ

  1. この記事に従って、Next.jsフロントエンドをBack4app Containersにデプロイしてください。
  2. バックエンドに高度な機能を追加するには、Cloud Code Functionsを調べてください。
  3. ボット対策として、ユーザー登録時にEメール認証を実施する。

Leave a reply

Your email address will not be published.