Как стать автором
Обновить

Создание мобильного приложения чата на React Native

Время на прочтение3 мин
Количество просмотров7.2K
Это вторая часть статьи (первая тут), посвященная созданию чата, используя apollo-server-koa и react-native. В ней будет рассмотрено создание мобильного приложения чата. В предыдущей части уже был создан бекенд для этого чата, подробнее с описанием этого процесса вы можете ознакомиться по ссылке.

Первым делом с помощью expo-cli создадим новый expo проект, для этого выполним в терминале команду:

expo init

И проследуем по всем шагам визарда для создания пустого приложения.

После того, как мы получили созданное приложение, необходимо добавить зависимости, которые будут использованы в дальнейшем:

yarn add apollo/react-hooks apollo-cache-inmemory apollo-client apollo-link-http apollo-link-ws apollo-utilities graphql graphql-tag native-base react-router-native subscriptions-transport-ws

Готово, следующий шаг — подключение и настройка apollo client’a для работы с нашим бекендом. Для этого добавим код ниже в App.js. Отмечу, что здесь мы настроим apollo для подключение к нашему бекенду по http и websocket протоколам, а так же создадим in-memory кеш для apollo, а так же создадим 2 роута: один для формы входа и второй для страницы чата.

get link() {
  const BACKEND_URL = Platform.OS === 'ios'
    ? 'localhost:3000'
    : '10.0.2.2:3000';

  const httpLink = new HttpLink({
    uri: `http://${BACKEND_URL}/graphql`
  });

  const wsLink = new WebSocketLink({
    uri: `ws://${BACKEND_URL}/graphql`,
    options: {
      reconnect: true
    }
  });

  return split(
    // split based on operation type
    ({ query }) => {
      const definition = getMainDefinition(query);
      return (
        definition.kind === 'OperationDefinition' &&
        definition.operation === 'subscription'
      );
    },
    wsLink,
    httpLink,
  );
 }
 
async componentDidMount() {
  const cache = new InMemoryCache();
  this.client = new ApolloClient({
    link: this.link,
    cache
  });
  ….
 }

render() {
  return (
    ...
    <ApolloProvider client={this.client}>
      <NativeRouter>
        <Route exact path="/" component={UsernameForm}/>
        <Route path="/chat" component={Chat}/>
      </NativeRouter>
    </ApolloProvider>
  )
}

Я не буду подробно описывать создание формы, думаю, вы и так видели это неоднократно, скажу только, что код формы входа можно найти здесь, для простоты я решил не добавлять авторизацию и поле для ввода пароля, однако при желании вы можете легко сделать это самостоятельно.

Остановлюсь на интересном моменте:

const [ findOrCreateUser ] = useMutation(FIND_OR_CREATE_USER, {
 update(cache, { data: { findOrCreateUser: { id, username } } }) {
   cache.writeQuery({
     query: GET_CURRENT_USER,
     data: { id, username },
   });
 }
});

Здесь происходит вызов мутации добавления/получения юзера по его username, а так же запись результата в кеш для дальнейшего его использования в других частях приложения.

После того, как форма входа реализована, следующий пункт — чат.

Опять же, не будем подробно останавливаться на верстке, весь код можно посмотреть здесь.

Используем функционал подписки, для получения оповещений о новом сообщении в чате и обработаем только ту ветку, когда сообщение было создано не текущим пользователем, так как в противном случае, сообщение уже попадет к кеш apollo:

useSubscription(MESSAGE_CREATED, {
 onSubscriptionData: ({ client, subscriptionData: { data: { messageCreated } } }) => {
   const { getLast100Messages } = client.readQuery({ query: GET_LAST_100_MESSAGES });

   if (messageCreated.user.id !== id) {
     client.writeQuery({
       query: GET_LAST_100_MESSAGES,
       data: {
         getLast100Messages: [
           ...getLast100Messages,
           messageCreated
         ]
       }
     });
   }
 }
});

Еще один интересный момент, при загрузке чата с уже имеющимися сообщениями в нем, в верхней части экрана будет отображено наиболее старое сообщение, это непривычно для пользователей, сделаем поведение приложения более естественным, для этого добавим следующие строки кода:

const scrollEl = useRef(null);
…
<Content
  ref={scrollEl}
  onContentSizeChange={() => {
    scrollEl.current.wrappedInstance.scrollToEnd({ animated: true });
  }}
>

Теперь при получении начальных данных или при добавлении нового сообщения чат будет плавно скроллиться до самого последнего сообщения.

Остальной код не имеет смысла рассматривать, так как он похож на то, что уже было сделано, реализация приложения хранится в репозитории.

После того как весь функционал приложения был реализован остается только протестировать работоспособность приложения вместе с бекендом из предыдущей статьи. Запущенное на эмуляторе приложение выглядит так:

image
Теги:
Хабы:
Всего голосов 16: ↑10 и ↓6+4
Комментарии0

Публикации

Истории

Работа

Ближайшие события