Рубрики
Без рубрики

Построить полностью оффлайн приложение, используя реагировать родной и армелондб

Посмотрите, как вы можете построить полнофункциональный автономный приложение, используя React Reaction для Frontend и WatermeLondb для хранения данных.

Автор оригинала: Foysal.

Этот пост был спонсирован и изначально опубликован на logocebocke blog .

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

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

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

Что вам нужно довести в стол

Ничего – ты добро пожаловать в стол, независимо от того, что вы принесете.

Тем не менее, этот пост предполагает, что у вас есть некоторое знакомство с помощью Typeycript и React Nature, а также базовое понимание баз данных. Если вы не знакомы с одним или всем вышеперечисленным, вы все еще можете прочитать, но некоторые вещи могут показаться слишком загадочным, и потребуется больше исследований на вашем конце.

Для нетерпевших, таких как я, кто хочет сначала посмотреть код, прежде чем совершить чтение по почте, вот Вся кодовая база на Github Отказ

Начиная

Что первая и прежде всего проблема для любого бизнеса? Поток дохода, верно?

Неправильный! Это имя. Выбор правильного имени всегда главное, чтобы каждый должен сосредоточиться на том, прежде чем что-либо еще при создании приложения.

Итак, конечно, до того, как я даже начал писать этот пост, я придумал имя велосипедистов, который, если вы не заметили, это очень умный WordPlay на том факте, что приложение отслеживает ваш вес. Удивительно, верно?

Какие? Вы думаете, что можете сделать лучше, чем это? Ну, я хотел бы видеть, как ты попробуешь – Чирикать мне Если вы можете придумать лучшее имя для приложения для отслеживания веса!

Нажмите здесь, чтобы увидеть полную демонстрацию сетевых запросов

Хорошо, достаточно шучу. Давайте сейчас дойдем до работы.

Если вы новичок, чтобы реагировать на родных, прежде чем начать, вам придется настроить машину с некоторыми инструментами. Перейти к Rn Официальная настройка среды Документация И пройдите через процесс установки. После того, как у вас все настроили, вы можете иметь RECAND NANINAL CLI создать приложение Boeterplate для вас, просто запущенным:

npx react-native init weightress --template react-native-template-typescript

Это будет генерировать новую папку с именем велосипед и бросить кучу файлов в нем. Откройте папку с вашим любимым редактором кода и перейдите внутри папки из окна терминала.

Для хранения данных пользователей на своих устройствах мы будем использовать Watermelondb Отказ Во-первых, мы будем устанавливать его в качестве зависимости с помощью пряжи, которая является диспетчером пакета по умолчанию для нативного приложения BoaterPlate Rect. Запустите следующие команды:

cd weightress
yarn add @nozbe/watermelondb @nozbe/with-observables
yarn add --dev @babel/plugin-proposal-decorators

Первая команда устанавливает зависимости, связанные с WABLEMELONDB, и вторая устанавливает пакет только для DEV, который нам потребуется использовать синтаксис декоратора ES6 в нашем коде.

Просто установка пакета не будет работать из коробки; Вы все еще должны позволить Вавилее знать о его существовании. Откройте babel.config.js Файл и добавьте новое свойство плагина так:

module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    ["@babel/plugin-proposal-decorators", { "legacy": true }]
  ]
};

Теперь, в зависимости от того, на какой платформе вы наращиваете, вам придется выполнить другой набор инструкций для завершения настройки БД. Для iOS, пожалуйста, следуйте за Эти шаги и для Android, следуйте за Эти шаги Отказ

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

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

Это должно открыть приложение на вашем устройстве/эмуляторе, и вы должны увидеть такой экран:

Реагировать нативный шаблон стартера

Структура данных

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

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

Кроме того, это, вероятно, было бы неплохо позволить пользователю вводить дополнительные ноты, когда они записывают свой вес. Может быть, они хотели бы записать, как они чувствуют себя в тот день, что они ели, и т. Д. Примечания также полезны для быстрого поиска конкретных вещей. Теперь давайте содействуем этому хранению данных с помощью WatermelondB.

Создать новую папку с именем данные/ и новый файл внутри именованного Схема и поместите следующий код в нем:

import {appSchema, tableSchema} from '@nozbe/watermelondb';

export default appSchema({
  version: 1,
  tables: [
    tableSchema({
      name: 'weights',
      columns: [
        {name: 'weight', type: 'number'},
        {name: 'created_at', type: 'number'},
        {name: 'note', type: 'string', isOptional: true},
      ],
    }),
  ],
});

В вышеупомянутом коде мы настроили схему для таблицы с именем весов с тремя столбцами. Обратите внимание, что Примечание колонна имеет Isoptional Недвижимость набор на правда Отказ Мы не хотим заставлять пользователю вводить записку для каждой записи, поэтому мы делаем его необязательным.

Кроме того, Create_at У столбца есть номер числа, даже если это дата. Это потому, что даты хранятся как временные метки UNIX в WatermelondB. Ох, и Isindexed устанавливается только для Примечание и create_at Потому что мы будем позволять пользователю поискать свои заметки или найти записи из определенного дня. Индексирование делает запросы намного быстрее, когда эти столбцы участвуют.

Это все для настройки базы данных, но наш код все еще должен взаимодействовать с этими данными. Вот где приходят модели. Модели являются представлениями необработанных данных в коде. Обычно у вас будет одна модель для каждой таблицы. Итак, давайте создадим нашу модель для таблицы весов.

Создать новый файл с именем Вес внутри данные/ папка и заполнить ее:

import {Model} from '@nozbe/watermelondb';
import {field, readonly, date} from '@nozbe/watermelondb/decorators';

export default class Weight extends Model {
  static table = 'weights';

  @field('note') note;
  @field('weight') weight;
  @readonly @date('created_at') createdAt;
}

Как видите, это в значительной степени зеркало схемы, которую мы только что создали для таблицы базы данных. Это просто создает карты между столбцами базы данных и свойствах нашей модели объекта. Одна волшебная вещь здесь – @date Декоратор, который автоматически генерирует текущий меток времени и вставляет его для нас всякий раз, когда новая запись вставлена в базу данных.

Мы почти сделаны с фазой настройки. Теперь внутри данные/ Папка, создайте другой файл с именем База данных и положить в следующий контент:

import {Database} from '@nozbe/watermelondb';
import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite';

import Weight from './weight';
import schema from './schema';

const adapter = new SQLiteAdapter({
  schema,
});

export const database = new Database({
  adapter,
  modelClasses: [Weight],
  actionsEnabled: true,
});

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

Тем не менее, в духе сохранения опасений отдельно, мы собираемся сохранить все наши код, связанные с данными в одном месте вместо доступа к/манипулирования базой данных непосредственно из компонентов. Давайте создадим последний файл внутри данные/ Папка по имени помощники .ts и поместите следующий код там:

import {database} from './database';

export type Weight = {
  createdAt?: Date;
  weight: string | number;
  note: string | undefined;
};

const weights = database.collections.get('weights');

export const observeWeights = () => weights.query().observe();
export const saveWeight = async ({weight, note}: Weight) => {
  await database.action(async () => {
    await weights.create((entry) => {
      entry.weight = Number(weight);
      entry.note = note;
    });
  });
};

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

На данный момент мы определяем только добыча и сеттер. Наблюдательные весы Функция устанавливает подписку на Вес Таблица и каждый раз, когда в базе данных есть изменение, слушатель этой подписки получит изменение. Изменение может быть создаваемой новой записью, существующая запись обновляется или удаляется запись.

Последнее, что экспортируется, это функция, которая, учитывая вес и примечание, создаст новую запись в базе данных Вес Таблица. Одно следует отметить, что вход веса будет приходить от поля ввода, которые обычно приведены в виде строк из реагирования на родных. Но в базе данных мы хотим хранить их как цифры, поэтому мы преобразуем строку на номер перед сохранением.

Пользовательский интерфейс

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

Как и раньше, мы начнем с плана и построены с нуля. Итак, давайте подумаем о нашем приложении с точки зрения пользовательского интерфейса на несколько. Он может быть легко отделен на два основных раздела: форма, которая позволяет пользователю вставить весовую запись и список, который отображает все ранее вставленные веса. Чтобы сделать его немного интереснее, вместо простого старого списка, давайте будем использовать диаграмму, чтобы показать исторические данные.

Для приятного UX давайте всегда будем держать диаграмму в поле зрения и отображать входную форму только по требованию. Для всего этого мы можем отделить приложение в трех компонентах: Заголовок , Создатель и Диаграмма Отказ С этим в виду, откройте App.tsx Файл, удалите все там и положите в следующий код:

import React, {useState} from 'react';
import {SafeAreaView, ScrollView, StatusBar} from 'react-native';

import Chart from './components/chart';
import Header from './components/header';
import Creator from './components/creator';

const App = () => {
  const [showCreator, setShowCreator] = useState(false);
  return (
    <>
      
      
        
          
setShowCreator(true)} /> setShowCreator(false)} />
); }; export default App;

Это довольно просто. Мы приносим три компонента, на которые мы планировали, поставив Статус BAR Компонент сверху и упаковка все в Safeareaview Компонент, чтобы убедиться, что наш контент не перекрывается со строкой состояния или отключить ужасную ношу. Тогда у нас еще одна оболочка, ScrollView , это позволит пользователю прокрутить вниз, если содержимое внутри переполняет вертикальную высоту экрана.

Мы видим местное логическое государство по имени Showcreator , что определит ли Создатель показано пользователю. При рендерии Заголовок Компонент, пропустим функцию опоры, onopencreator это просто наборы Showcreator правда, когда вызывается.

В Создатель Компонент, мы передаем Showcreator Состояние и функция, чтобы скрыть создателя, установив Showcreator к ложе.

Тогда, наконец, у нас есть Диаграмма Компонент, который не требует от опоры. В какой-то момент через некоторое взаимодействие пользователей, Заголовок Компонент будет вызвать onopencreator , и это принесет Создатель Ввиду, что позволит пользователю ввести свой вес.

Теперь давайте просмотрим и посмотрите поближе к каждому из этих компонентов. Создать новую папку с именем Компоненты И создать три новых файла внутри: Chart.tsx , Creator.tsx и Header.tsx Отказ

Компонент заголовка

Откройте Компоненты/Header.tsx Файл и положить в следующий код:

import React, {FC} from 'react';
import {View, Text, TouchableHighlight} from 'react-native';
import {headerStyles} from './styles';

const Header: FC<{onOpenCreator: () => void}> = ({onOpenCreator}) => {
  return (
    <>
      
        Weightress
         onOpenCreator()}>
          + Add
        
      
    
  );
};

export default Header;

Это небольшой компонент, который отображает текст заголовка только с именем приложения, весовой кнопки и кнопки, которая вызывает onopencreator Функция опоры при нажатии. Кнопка отображается с помощью Touchablehighlight Компонент, но вы могли бы играть с Кнопка или Нажатием составная часть.

Обратите внимание, что мы используем заголовки Чтобы применить стили на всех трех компонентах, которые импортируются из файла, который мы еще не создали. Так что давайте создадим файл Компоненты/стили. и положить в следующий код:

import {StyleSheet} from 'react-native';

export const primaryColor = '#FB8C00';

export const headerStyles = StyleSheet.create({
  container: {
    alignItems: 'center',
    paddingVertical: 20,
    flexDirection: 'row',
    paddingHorizontal: 15,
    justifyContent: 'space-between',
  },
  addButton: {
    borderColor: primaryColor,
    paddingHorizontal: 20,
    paddingVertical: 8,
    borderRadius: 3,
    borderWidth: 1,
  },
  headerTitle: {
    fontSize: 25,
    fontWeight: 'bold',
    borderLeftWidth: 3,
    paddingLeft: 10,
    borderLeftColor: primaryColor,
  },
});

Как вы можете видеть, заголовки это реагированная нативная таблица стилей, которая имеет три свойства. Каждое свойство содержит стиль для одного компонента. Контейнер помещает некоторое пространство по всему заголовозу и гарантирует, что текст заголовка и кнопка «Добавить» расположены на противоположных сторонах экрана, используя оправдываниеcontent: «Место между» Отказ

Addbutton Удаляет некоторое пространство вокруг кнопки на правую сторону и добавляет округлый (но не слишком округлый) гранику вокруг текста, чтобы он выглядел больше кнопки. Обратите внимание, что цвет границы устанавливается с использованием PrivareColor Переменная. Изолирующая основной цветной акцент поможет нам повторно использовать его в других стилях компонентов и позволяет легко изменить брендинг приложения в одном месте.

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

Предварительный просмотр нашего компонента заголовка

Создатель компонент

Откройте Компоненты/Creator.tsx Файл и положить в следующий код:

import React, {FC, useState} from 'react';
import {
  Button,
  Modal,
  Text,
  TextInput,
  TouchableHighlight,
  View,
} from 'react-native';
import {saveWeight} from '../data/helpers';
import {creatorStyles, primaryColor} from './styles';

const Creator: FC<{
  isCreatorVisible: boolean;
  onHideCreator: () => void;
}> = ({onHideCreator, isCreatorVisible}) => {
  const [isSaving, setIsSaving] = useState(false);
  const [weight, setWeight] = useState('');
  const [note, setNote] = useState('');

  const handleSavePress = async () => {
    setIsSaving(true);
    await saveWeight({weight, note});
    // hide modal
    onHideCreator();
    // Clear out the inputs
    setWeight('');
    setNote('');
    // Make button active again
    setIsSaving(false);
  };

  return (
    
      
        
          
            Add your weight
             {
                onHideCreator();
              }}>
              ×
            
          
           setWeight(text)}
            value={weight}
          />
           setNote(text)}
            value={note}
          />
          
        
      
    
  );
};

export default Creator;

Этот немного более мясистый, чем Заголовок Компонент, не так ли? Давайте распадаем это, начиная с местных состояний. У нас есть три из них: Выдача , Вес и Примечание Отказ

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

Помните, что мы сказали, что мы покажем только Создатель по запросу, по требованию? Мы достигаем этого через React Nature’s Модал составная часть. Прохождение правда к Видимый Подп этого компонента принесет его в поле зрения, а ложь выберу это. Мы делаем переход и чувствовать себя хорошо, передавая AnimationType = "слайд" пропры

Модал Компонент охватывает весь экран, но для небольшой формы с двумя входами нам не нужен так много недвижимости. Итак, мы обертываем содержание в два Вид Компоненты, и обертка помещает все внутри него в нижней части экрана, используя Magic Flexbox.

Давайте посмотрим на стили, которые могут достичь этого. Вернитесь к styles.ts Файл и создать новую таблицу стилей:

import {Dimensions, StyleSheet} from 'react-native';
// previous code.....
const windowDim = Dimensions.get('window');
export const windowHeight = windowDim.height;
export const creatorStyles = StyleSheet.create({
  centeredView: {
    flex: 1,
    justifyContent: 'flex-end',
    backgroundColor: 'rgba(255, 255, 255, 0.6)',
  },
  modalView: {
    backgroundColor: '#FFFFFF',
    borderTopLeftRadius: 20,
    borderTopRightRadius: 20,
    padding: 10,
    height: windowHeight / 2,
    shadowColor: '#cacaca',
    shadowOffset: {
      width: 0,
      height: 1,
    },
    shadowOpacity: 0.1,
    shadowRadius: 2,
    elevation: 1,
  },
}

CenterDView Является ли родительская обертка, которая инкапсулирует все внутри и имеет полупрозрачный фон. ОправданныйContent: «Flex-End» Обеспечивает, что любой элемент внутри он помещен в нижней части элемента. Для Вид внутри, мы используем modalview Стиль, который имеет белый фон и принимает половину высоты экрана.

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

Хорошо, давайте обратимся обратно в компонент. Внутри модаль сначала мы видим это:


            Add your weight
             {
                onHideCreator();
              }}>
              ×
            
          

Это добавляет текст заголовка внутри модала и кнопки справа, который загорит Onhidecreator функция опоры при нажатии. Помните, что мы передаем это от App.tsx И это позволяет пользователю закрыть модаль. Давайте создадим стили для этого обратно в styles.ts файл:

export const creatorStyles = StyleSheet.create({
  // previous code...
  topActions: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  topCloseButton: {
    padding: 10,
    color: '#494949',
    fontWeight: 'bold',
    fontSize: 25,
  },

Он имеет аналогичную настройку для Заголовок Компонент, где мы разделяем обертку в два горизонтальных секциях с помощью Flexbox. Кнопка «Закрыть справа» имеет некоторое пространство вокруг него, чтобы легко было легко кликабельным, и текст остается слева.

Теперь основное содержание модального:

 setWeight(text)}
            value={weight}
          />
           setNote(text)}
            value={note}
          />
          

У нас есть два TextInput Компоненты и A Кнопка здесь. Первый TextInput принимает номер ввода только потому, что мы устанавливаем KeyboardType = «Декомасштабная колодка» опоры на нем, и это связано с Вес государственный. Второй для любой дополнительной ноты; Следовательно, это связано с Примечание государственный. Наконец, у нас есть Кнопка который уволяет HandlesavePress функция при нажатии.

Обратите внимание, что для отключения кнопки, когда вход сохраняется, мы устанавливаем Отключено = {eassaving} и сделать его сопоставлением нашего брендинга, мы настраиваем Color = {PrivareColor} Отказ Мы еще не определили стили для этих полей, поэтому давайте вернемся к styles.ts Файл и добавьте это:

export const creatorStyles = StyleSheet.create({
// previous code...
  input: {
    height: 50,
    borderWidth: 1,
    borderRadius: 3,
    marginBottom: 10,
    paddingVertical: 10,
    paddingHorizontal: 15,
    borderColor: '#c9c9c9',
  },
});

Мы просто добавляем некоторые расстояния вокруг поля и добавляя границу, чтобы она выглядела хорошо. Теперь давайте узнаем, что HandlesavePress делает:

const handleSavePress = async () => {
    setIsSaving(true);
    await saveWeight({weight, note});
    // hide modal
    onHideCreator();
    // Clear out the inputs
    setWeight('');
    setNote('');
    // Make button active again
    setIsSaving(false);
  };

Когда уволено, сначала переключится государство Выдача true, который, в свою очередь, отключает Сохранить кнопка. Затем он называет вес для сохранения Функция с весом и примечанием входных данных из состояния. Это будет асинхронно сохранять данные в армелондб.

После завершения мы сначала увольняем Onhidecreator Функциональная опора, которая, если вы вспоминаете, скрывает саму модуль. Затем мы просто очищаем входы, чтобы, когда модаль открывается резервным копированием, пользователи видят пустые входные поля вместо их ранее вставленного веса и примечания. Наконец, мы переключаем Выдача Вернуться к ложе, чтобы повторно включить Сохранить Кнопка в следующий раз, когда пользователь открывает модаль.

Опять же, мы еще не видим его в нашем приложении, так что вот скриншот, чтобы намочить клюв …

Предварительный просмотр компонента нашего создателя

Компонент диаграммы

Нативная экосистема RACT не хватает некоторых из великолепных библиотек данных Charting и Data Viz, доступных в Интернете или для нативных платформ. Однако для наших потребностей React – Nature-Chart-kit предлагает все из коробки. Библиотека зависит от библиотеки RACT-NATION-SVG, поэтому давайте установим оба беги пряжа добавляет реагистративно-SVG React-Nation-Chart-Kit Отказ

Теперь открыть Компоненты/Chart.tsx Файл и положить в следующий код:

import React, {FC} from 'react';
import withObservables from '@nozbe/with-observables';
import {LineChart} from 'react-native-chart-kit';

import {observeWeights, Weight} from '../data/helpers';
import {chartConfig, chartStyles, windowWidth} from './styles';

const Chart: FC<{weights: Weight[]}> = ({weights}) => {
  if (weights.length < 1) {
    return null;
  }

  const labels: string[] = [];
  const data: number[] = [];
  weights.forEach((w) => {
    labels.push(`${w?.createdAt.getDate()}/${w.createdAt.getMonth() + 1}`);
    data.push(w.weight);
  });
  return (
    
  );
};

const enhanceWithWeights = withObservables([], () => ({
  weights: observeWeights(),
}));

export default enhanceWithWeights(Chart);

Во-первых, мы настроили Диаграмма Компонент должен быть функциональным компонентом, который получает массив весов. Если массив пуст, мы просто ничего не сделаем. В противном случае мы зацикливаемся через массив весов и построить этикетки Массив, содержащий даты для каждой записи в ДД/мм формат.

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

данные опора, где мы проходим этикетки и данные Массивы, которые мы только что построили. Безье опоры делает диаграмму линии экстраполировать, чтобы иметь изогнутый внешний вид. Мы проезжаем Высота и а ширина , где высота заканчивается, но ширина получена из A WindowWidth Переменная, которая импортируется из styles.ts Файл вместе с ChartConfig и Chartstyles Отказ

Давайте посмотрим, что они возвращаются в styles.ts файл:

export const windowWidth = windowDim.width;
export const chartStyles = StyleSheet.create({
  chart: {
    marginLeft: 15,
    borderRadius: 10,
  },
});

export const chartConfig = {
  backgroundColor: primaryColor,
  backgroundGradientFrom: primaryColor,
  backgroundGradientTo: '#FFA726',
  decimalPlaces: 2,
  color: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
  labelColor: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
  style: {
    borderRadius: 16,
  },
  propsForDots: {
    r: '6',
    strokeWidth: '2',
    stroke: '#ffa726',
  },
};

От Размер Модуль, мы экспортируем ширину окна устройства, а ширина графика будет 30px меньше, чем полная ширина. Тогда, в Chartstyles мы даем это 15px маржа слева, так что график горизонтально центрирован на экране с хорошим 15px по обе стороны от этого. Мы также добавляем некоторый радиус вокруг своей границы.

Большая часть стайлинга сделана через ChartConfig опоры вместо реагирования на родной стиль. Мы настраиваем график, чтобы использовать градиент на заднем плане, начиная с PrivareColor акцент. Остальные свойства предназначены для различных форм и цветов содержания, показанного внутри диаграммы. Вы можете узнать больше способов настроить свой график из Официальная документация библиотеки Отказ

Вернуться к компоненту, обратите внимание, что мы не будем напрямую экспортировать Диаграмма Компонент, как мы сделали с двумя другими компонентами. Вместо этого мы обертываем его в компоненте более высокого порядка (HOC) и экспортируя эту версию обертки:

const enhanceWithWeights = withObservables([], () => ({
  weights: observeWeights(),
}));

export default enhanceWithWeights(Chart);

Именно здесь проживает мощность армелонда. с сервисами HOC дает нам способ подключения реактивный компонент непосредственно к данным в нашей базе данных в режиме реального времени.

Это где мы применяем наблюдательные весы () Функция помощника и упаковка наши Диаграмма Компонент с HOC означает, что компонент автоматически получит опоры с именем Вес Отказ Этот опорой будет содержать все записи веса из базы данных, и каждый раз добавляются новые данные или существующие данные обновляются или удаляются, компонент будет переназначен с последними данными.

Взять его для спина

Со всем этим на месте мы можем наконец открыть наше приложение на устройстве или эмуляторе и проверять его. Вот видео из меня, играя вокруг с ним:

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

Со щитом или на щите

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

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

Селектор с периода времени

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

Импорт/экспортные данные

Одна очень распространенная проблема с автономными приложениями является синхронизация данных. Пользователи могут потерять свои телефоны, сломать их, сбросить их и т. Д. Есть много других сценариев, где данные, хранящиеся в устройстве, будут потеряны навсегда. Чтобы избежать такого беспорядка, оффлайн приложения необходимо предоставить способ экспортировать данные в портативные форматы, такие как CSV или PDF-файлы.

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

Уведомления напоминания

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

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