Разработка приложения React Native — начиная с реформы официальной демоверсии (1)

React Native

Полный код демо-версии, используемой в этой статье, находится здесь. react-native-complete-demo.

Когда я впервые получил уведомление от компании о разработке React Native APP, я был очень взволнован, потому что предыдущий технологический стек был в основном Vue и Angular, Я написал только несколько демонстраций для React, и я всегда хотел использовать его на практике. проектов, но шансов не было. Однако время разработки, предоставленное компанией, было очень коротким, и от требований к дизайну до представления первой версии на рассмотрение прошел всего один месяц. С учетом предыдущего опыта использования Vue (даже если вы не очень с ним знакомы, вы можете скачать демо-версию официального сайта и модифицировать его для выхода в интернет, а функции и производительность можно итеративно оптимизировать в будущем) и более 90% бизнес-API были откорректированы совместно со студентами, и я подумал, что месяца будет более чем достаточно.

Хотя последнее приложение онлайн (iOS,андроид), но в процессе разработки было много подводных камней.

Во-первых, было сложно найти готовую демонстрацию приложения React Native. Существующие демонстрации либо слишком просты, например, демонстрации, представленные на официальном сайте React Native.AwesomeProject, эта демонстрация предоставляет только самые простые функции и не включает маршрутизацию (компоненты навигации), управление состоянием и т. д. Хотя в руководствах по React Native упоминается, как выбирать компоненты и сторонние библиотеки для сложных приложений, они не дают полных примеров. С другой стороны, существует множествоReact Native APPХотя с открытым исходным кодом, они являются полноценными приложениями для определенных случаев.Структура каталогов некоторых приложений сама по себе неудобна, и нет полной документации.

Во-вторых, кривая обучения React сама по себе относительно крутая, особенно когда дело доходит до управления состоянием, трудно найти код, который можно копировать-вставить напрямую, кроме того, к самому нативному приложению предъявляется множество требований, отличных от веб-приложений. .

По вышеуказанным причинам я решил написать статью с подробным описанием процесса разработки приложения React Native.

Контента много, он разбит на две части, основное содержание этой части:

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

подготовка

1.1 Инструменты разработки

Если вы хотите разработать приложение для iOS и опубликовать его в APP Store, вы должны использовать Xcode и иметь учетную запись разработчика Apple. Если вы разрабатываете приложения для Android, хорошо иметь компьютер, а лучше всего иметь лестницу.

1.2 Проверка кода и автоматическая коррекция

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

Конечной целью является сохранение кода после операции и автоматическое форматирование кода в соответствии с конфигурацией eslint.

2 Загрузка официальной демоверсии и введение

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

2.1 Конфигурация среды

Загрузите официальную демоверсию: AwesomeProject и запустите ее.

Требуемая конфигурация средыофициальная документацияЭто очень ясно и не будет повторяться здесь. Следует отметить, что React Native предоставляет два метода запуска Demo: один из нихExpoЗапустите в клиенте, другой — скомпилируйте в собственный код (Android скомпилирован в Java, iOS скомпилирован в Objective-C), а затем запустите в симуляторе или на реальной машине. Рекомендуется использовать второй напрямую.Если вы хотите опубликовать приложение, вы не можете обойти его.

Если вы раньше не разрабатывали нативное ПРИЛОЖЕНИЕ, вам также необходимо ознакомиться с инструментами разработки нативного ПРИЛОЖЕНИЯ: Использование AndroidAndroid Studio, iOS используетXcode. Как они работают с React Nativeофициальная документацияЗаявлено, что ям в этой части не много, а у гугла вообще есть решение при возникновении проблем.

Следует отметить, что для многих обновлений зависимостей Android Studio требуется доступ к службам Google, поэтому принесите свою собственную лестницу.

существуетstep_by_step/other/react/react_native/Подробно описаны проблемы и решения, с которыми я столкнулся в процессе использования React Native впервые.Поскольку это для целей записи, то немного многословно.Если вам интересно, то можете прочитать.

2.2 Введение в официальный демо-каталог

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

AwesomeProject 目录结构

Вышеупомянутая структура каталогов описана следующим образом, важными из них являются:

  • android/Собственный код Android (используйте студию Android, чтобы открыть этот каталог, если вы откроете родительский каталог напрямую, будет сообщено об ошибке)
  • ios/Собственный код ios (используйте xcode, чтобы открыть этот каталог, если вы откроете родительский каталог напрямую, будет сообщено об ошибке)
  • index.jsВведите входной файл React Native (часть js) при упаковке приложения (Android и ios совместно используют входной файл после 0.49)
  • App.jsЭто можно понимать как входной файл части кода React Native (часть js), например, здесь импортируется маршрутизация всего проекта.

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

  • _test_/Для тестирования (еще не использовал)
  • app.jsonОписание проекта, в основном для нативной упаковки приложений, включая название проекта и отображаемое имя мобильного рабочего стола.React Native : 0.41 app.json
  • package.jsonФайл конфигурации пакета зависимостей проекта
  • node_modulesКаталог установки пакета зависимостей
  • yarn.lockфайл управления пакетами пряжи
  • Другие файлы конфигурации пока не нужно изменять, и здесь они не будут объясняться.

3 Настроить маршрутизацию

использовать здесьreact navigationМаршрутизация управления, большое и всестороннее введение или объяснение принципа не является целью этой части, вот как ее использовать.

Существует три распространенных API для интерактивной навигации:

  • StackNavigator: Переход между страницами (предыдущая страница будет помещаться в стек возврата после каждого перехода, особенно полезно возвращаться на предыдущую страницу)
  • TabNavigator: переход на верхнюю или нижнюю вкладку, обычно используется внизу
  • DrawerNavigator: боковая навигация

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

3.1 StackNavigator реализует переходы между страницами

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

添加 StackNavigator 后目录结构

  • src/Поместите весь оригинальный реагирующий нативный код
  • config/Файлы конфигурации, такие как конфигурация маршрутизации
  • route.jsфайл конфигурации маршрутизации
  • screens/все файлы страниц
  • ScreenHome/Этот каталог предназначен для конкретных файлов подкачки. Для дальнейшего разделения кода он разделен на три файла:index.jsсодержит логическую часть,style.jsсодержит раздел стилей;view.jsСодержит раздел элемента представления или страницы. Остальная часть структуры копии страницы такая же.

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

Краткое введение в реагирующую навигацию и следующие конкретные модификации:

1) Сначала настройте маршрутизацию: файл маршрутизацииroute.jsВ настоящее время содержание выглядит следующим образом, что такжеStackNavigatorСамый простой способ использования:

/**
 * route.js
 */

// 引入依赖
import React from "react";
import { StackNavigator } from "react-navigation";

// 引入页面组件
import ScreenHome from "../screens/ScreenHome";
import ScreenSome1 from "../screens/ScreenSome1";

// 配置路由
const AppNavigator = StackNavigator({
  ScreenHome: {
    screen: ScreenHome
  },
  ScreenSome1: {
    screen: ScreenSome1
  }
});

export default () => <AppNavigator />;

2) ОбновлениеApp.js, файл маршрутизации стыковки:

/**
 * App.js
 */

export default class RootApp extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    // 渲染页面
    return <Route />;
  }
}

3) Конкретные настройки страницы дляScreenHomeНапример

существуетindex.jsНастройте логику маршрутизации и стили текущей страницы, такие как заголовок и его стили, настраиваемые кнопки в панели навигации и т. д. Пока нам нужно просто установить заголовок:

/**
 * ScreenHome/index.js
 */

export default class ScreenHome extends Component {
  // 自定义当前页面路由配置,后面介绍的TabNavigator也使用这个对象中的属性
  static navigationOptions = {
    // 设置 title
    title: "首页"
  };

  constructor(props) {
    super(props);
    this.navigation = props.navigation;
  }

  render() {
    return view(this);
  }
}

существуетview.jsОпределите определенные страницы перехода для определенных элементов в

/**
 * ScreenHome/index.js
 */

// 引入依赖略

export default self => (
  <View>
    <Text style={{ fontSize: 36 }}>home</Text>
    <Button
      title="goSomePage1"
      // 路由跳转
      onPress={() => self.navigation.navigate("ScreenSome1")}
    />
  </View>
);

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

StackNavigator效果图

3.2 TabNavigator реализует переключение вкладок внизу страницы

первый вscreensновый каталогScreenBottomTabстраница для настройкиTabNavigator. Каждая вкладка соответствует странице, при необходимости создайте новую страницу, и вновь созданная страница должна быть вroute.jsОбновленная структура каталогов выглядит следующим образом:

添加tab导航后目录结构

  • ScreenBottomTabНастроить навигацию по нижней вкладке
  • ScreenTab1/2/3Создайте новую страницу с навигацией по нижней вкладке

1) Минимальная конфигурация без значка вкладки

Нужно только настроитьScreenBottomTabвнутриindex.jsФайл в порядке, как показано ниже:

/**
 * ScreenBottomTab/index.js
 */

const ScreenTab = TabNavigator(
  // 配置 tab 路由
  {
    ScreenHome: {
      screen: ScreenHome
    },
    ScreenTab1: {
      screen: ScreenTab1
    },
    ScreenTab2: {
      screen: ScreenTab2
    },
    ScreenTab3: {
      screen: ScreenTab3
    }
  },
  // 其他配置选项
  {
    tabBarPosition: "bottom"
  }
);

export default ScreenTab;

Файл подкачки теперь настраивать не нужно, следует отметить, что текст под вкладкой по умолчанию, а вStackNavigatorТо же, что заголовок навигации заголовка, определенный в .

2) Настройте значок вкладки

В дополнение к настройке значок вкладки также должен отображать разные цвета в зависимости от того, выбран он или нет.Это можно настроить, настроивTabNavigatorизtabBarIconРеализация, конкретный файл, который нужно изменить, - это страница, соответствующая вкладкеindex.jsдокумент.

/**
 * ScreenHome/index.js
 */

static navigationOptions = {
  title: '首页',
  tabBarIcon: ({ focused }) => {
    // 根据是否选中,显示不同图片
    const icon = focused
      ? require('../../assets/images/tab_home_active.png')
      : require('../../assets/images/tab_home.png');
    return <Image source={icon} style={{ height: 22, width: 22 }} />;
  },
};

Окончательный эффект выглядит следующим образом:

底部 tab 导航效果图

3.3 Переключение модального режима на одной странице

Общие требования для ios: страница входа в систему вводится снизу вверх, в то время как другие страницы по умолчанию вводятся слева направо Навигация React предоставляет только способ глобальной настройки страницы и не дает возможности взаимодействовать одна страница, но эту функцию еще можно реализовать, это во второй частиРазработка React Native APP — начиная с преобразования официальной демоверсии (2)введено в.

Четыре пользовательских компонента

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

Здесь представлена ​​только настройка структуры каталогов. Конкретный код см. в коде проекта на Github. Поскольку требования к пользовательским компонентам сильно различаются, существует также множество руководств для конкретного процесса написания. Мы не будем их представлять. здесь, но добавляйте только пользовательские компоненты Toast. Структура каталогов настроена следующим образом:

组件目录

  • components/Здесь размещаются пользовательские компоненты
  • XgToast.jsСпециальный код пользовательского компонента

документconfig/pxToDp.jsдля адаптации размера, вXgToast.jsв использовании,Разработка React Native APP — начиная с преобразования официальной демоверсии (2)подробно описано.

Пять сетевых запросов

Самым большим преимуществом использования React Native является то, что вам не нужно учитывать совместимость нового синтаксиса.В этом случае естественно использовать более разработанный API.Что касается сетевых запросов, этот проект используетfetch API.

После добавления сетевых запросов структура каталогов настраивается следующим образом:

网络请求目录

  • xgHttp.jsнастроить API выборки
  • xgRequest.jsсписок API-запросов

5.1 Настройка API выборки

xgHttp.jsВесь код выглядит следующим образом, в нем есть простые комментарии, которые здесь подробно объясняться не будут, можно обратиться к использованию fetch apiВведение в API выборки

/**
 * xgHttp.js
 */

// 请求服务器host
const host = "http://api.juheapi.com";

export default async function(
  method,
  url,
  { bodyParams = {}, urlParams = {} }
) {
  const headers = new Headers();
  headers.append("Content-Type", "application/json");

  // 将url参数写入URL
  let urlParStr = "";
  const urlParArr = Object.keys(urlParams);
  if (urlParArr.length) {
    Object.keys(urlParams).forEach(element => {
      urlParStr += `${element}=${urlParams[element]}&`;
    });
    urlParStr = `?${urlParStr}`.slice(0, -1);
  }

  const res = await fetch(
    new Request(`${host}${url}${urlParStr}`, {
      method,
      headers,
      // 如果是 get 或者 head 方法,不添加请求头部
      body: method === ("GET" || "HEAD") ? null : JSON.stringify(bodyParams)
    })
  );

  if (res.status < 200 || res.status > 299) {
    console.log(`出错啦:${res.status}`);
  } else {
    return res.json();
  }
}

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

5.2 Написание и использование API запроса

  • файл со списком API

Я помещаю конкретный код запроса APIxgRequest.jsфайл, сgetЗапрос, например,xgRequest.jsкод показывает, как показано ниже:

/**
 * xgRequest.js
 */

import XgHttp from "./xgHttp";

export default {
  todayOnHistory: urlPar => XgHttp("GET", "/japi/toh", { urlParams: urlPar })
};

в"/japi/toh"Для адреса интерфейса здесь я использую агрегированные данныесегодня в историиAPI.

Вызов сводных данныхсегодня в историиЯ использую свой собственный APPKEY, когда я использую API, который вызывается 100 раз в день бесплатно, и после его превышения возвращается ошибка.request exceeds the limit!, если вы хотите выполнить больше тестов, просто замените его на свой APPKEY после регистрации.

  • использовать

Сначала вызовите интерфейс, чтобы получить данные.

Вызов интерфейса находится в файле подкачкиindex.jsосуществляется вScreenTab1/index.jsНапример:

/**
 * ScreenTab1/index.js
 */

const urlPar = {
  // 大佬们,这个是我申请的聚合数据应用的key,每天只有100免费请求次数
  key: '7606e878163d494b376802115f30dd4e',
  v: '1.0',
  month: Number(this.state.inputMonthText),
  day: Number(this.state.inputDayText),
};

// 拿到返回数据后就可以进一步操作了
const todayOnHistoryInfo = await XgRequest.todayOnHistory(urlPar);

Затем отобразите данные.

После получения данных вы можете выполнять дальнейшие операции, которые обычно отображаются на странице.react — это фреймворк, управляемый данными., для динамически изменяющихся отображаемых данных обычно помещаются в React Nativestateв объекте,stateПосле изменения он сработаетrender()Функция повторно отображает измененную часть DOM.

первый вindex.jsЗапишите данные, которые должны быть динамически отображены в первую очередьstate:

/**
 * ScreenTab1/index.js
 */

// 将需要动态更新的数据放入 state
this.state = {
  todayOnHistoryInfo: {}
};

затем вview.jsчитать вstateданные в:

/**
 * ScreenTab1/view.js
 */

{
  /* 查询 */
}
<Button title="查询" onPress={() => self.getTodayOnHistoryInfo()} />;

{
  /* 展示查询数据 */
}
<Text>
  发生了啥事:{self.state.todayOnHistoryInfo.result
    ? self.state.todayOnHistoryInfo.result[0].des
    : "暂无数据"}
</Text>;

вышесказанноеview.jsКод в основном делает две вещи: отправляет команду вызова и отображает возвращенные данные.

Окончательные рендеры выглядят следующим образом:

网络请求效果

Шесть встроенных редукторов

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

После введения redux структура каталогов настраивается следующим образом:

redux目录

  • reduxХранить файлы конфигурации, связанные с избыточностью
  • actions.js redux action
  • reducers.js redux reducer
  • store.js redux store

Если у вас нет понятия о редуксе, вы можете прочитать эту статьюНачало работы с Redux

ReduxЭто на самом деле очень сложно использовать, если вы использовали его раньшеvuex, в процессе использования Redux вы обнаружите, что слишком много вещей, которые нужно настраивать самостоятельно (здесь нет ни хорошего, ни плохого, вы не хотите начинать войну, это просто ваш собственный опыт), чтобы упростить работу с Redux, автор Redux разработалreact-redux, хотя он и не сравним с vuex с точки зрения простоты использования, его все же гораздо проще использовать, чем напрямую использовать Redux.

Прежде чем интегрировать Redux для управления состоянием, давайте подумаем над вопросом: какие трудности возникают в процессе интеграции?

Поскольку Redux имеет только один магазин в приложении, этот магазин должен быть общим для всех компонентов (страницы), поэтому сложность интеграции заключается в том, чтоКак сделать этот уникальный магазин доступным для всех компонентов (страницы) и запускать действия. С этой целью в редукс-реакции введеныconnectфункция иProvideКомпоненты, они должны использоваться вместе для достижения избыточной интеграции.

сквозь этоconnectиProvideИдея реализации хранилища между компонентами такова:

  1. Магазин Redux может (обратите внимание, что «можно», а не «должен», необходимо настроить, см. пункт 2)connectМетод виден, поэтому в компоненте его можно вызвать вызовомconnectМетод реализует доступ к хранилищу данных;
  2. Реализовать пару магазинов ReduxconnectВидимое предварительное условие состоит в том, чтоНеобходимо убедиться, что этот компонентProvideподкомпонент компонента, так что, передав магазин какProvideРеквизиты компонента могут передаваться всем дочерним компонентам слой за слоем;
  3. но дочерний компонент должен пройтиconnectМетод реализует доступ к хранилищу и не может быть доступен напрямую.

6.1 Знакомство с зависимостями

Во-первых, установить и зависеть от редукции, реагировать-редукс:

yarn add redux react-redux

6.2 Настройка избыточности

Вот конфигурацияactions, reducersиstore.

Говорят, что приложение большое, и лучше всего разделить редукс, но проект пока маленький, и разделения пока нет.

  • настроитьactions
/**
 * actions.js
 */

export function setUserInfo(userInfo) {
  return {
    // action 类型
    type: "SET_USER_INFO",

    // userinfo 是传进来的参数
    userInfo
  };
}
export function clearReduxStore() {
  return {
    type: "CLEAR_REDUX_STORE"
  };
}
  • настроитьreducers
/**
 * reducers.js
 */

import { initialState } from "./store";

function reducer(state = initialState, action) {
  switch (action.type) {
    case "SET_USER_INFO":
      // 合并 userInfo 对象
      action.userInfo = Object.assign({}, state.userInfo, action.userInfo);

      // 更新状态
      return Object.assign({}, state, { userInfo: action.userInfo });
    case "CLEAR_REDUX_STORE":
      // 清空 store 中的 userInfo 信息
      return { userInfo: {} };
    default:
      return state;
  }
}

export default reducer;

УведомлениеSET_USER_INFOКод по этому пути используетObject.assign(). Это потому чтоreducerФункция каждый раз возвращает новыйstateобъект,Это означает, что еслиstateобъект содержит несколько свойствreducerФункция возвращает без слияния предыдущегоstate, может привести кstateСвойство объекта отсутствует.

Это очень распространенная ошибка, потому что обычно мы запускаемactionsнужно пройти только в той части, которая измениласьstateсвойства, а не весьstateОтправьте еще раз.

Учебное пособие по классическому счетчику Redux запускаетсяstateОбычно так пишут при сменеreturn { defaultNum: state.defaultNum - 1 };, потому что в контрпримере есть только одно свойство, а именноdefaultNum, поэтому перед слияниемstateЭто не имеет смысла, но приложение в производственной средеstateЧасто в объекте присутствует более одного атрибута, и описанный выше способ записи будет неправильным.

  • настроитьstore
/**
 * store.js
 */

import { createStore } from "redux";
import reducers from "./reducers";

// 定义初始值
const initialState = {
  userInfo: {
    name: "小光",
    gender: "男"
  }
};

const store = createStore(reducers, initialState);

export default store;

6.3 Используемые компоненты

После настройки redux следующим шагом будет его использование.

  • настроитьindex.js

в конфигурацииindex.jsСреда в основном конфигурацияProvideкак корневой компонент и передатьstoreВ качестве его свойства создайте условия для использования избыточности следующим компонентом.

/**
 * index.js
 */

import React from "react";
import { AppRegistry } from "react-native";
import { Provider } from "react-redux";
import App from "./App";
import store from "./src/redux/store";

const ReduxApp = () => (
  // 配置 Provider 为根组件,同时传入 store 作为其属性
  <Provider store={store}>
    <App />
  </Provider>
);

AppRegistry.registerComponent("AwesomeProject", () => ReduxApp);
  • Настроить компоненты

здесь сScreenTab2Например:

Первый вindex.jsСвязано с редукцией в

/**
 * ScreenTab2/index.js
 */
// redux 依赖
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import * as actionCreators from "../../redux/actions";

changeReduxStore(userInfo) {
  // 设置 redux store,相当于 dispatch,这里触发 actions 中的 'SET_USER_INFO'
  this.props.setUserInfo(userInfo);
}

// 将 store 中的状态映射(map)到当前组件的 props 中,这样才能在该组建中访问 redux state
function mapStateToProps(state) {
  return { userInfo: state.userInfo };
}

// 将 actions 中定义的方法映射到当前组件的 props 中,这样才能在该组建中触发 action
function mapDispatchToProps(dispatch) {
  return bindActionCreators(actionCreators, dispatch);
}

// 将 store 和 当前组件连接(connect)起来
export default connect(mapStateToProps, mapDispatchToProps)(ScreenTab2);

Затем необходимо контролировать конкретные измененные данные в представлении.

/**
 * ScreenTab2/view.js
 */

<Button title="改变名字" onPress={() => self.changeReduxStore({ name: 'vince' })} />
<Button title="改变性别" onPress={() => self.changeReduxStore({ gender: '女' })} />
<Button title="还原" onPress={() => self.changeReduxStore({ name: '小光', gender: '男' })} />

Окончательный рендеринг выглядит следующим образом:

集成redux后效果

6.4 Постоянное хранилище

К мобильным приложениям обычно предъявляются следующие требования:Если пользователь активно не завершит работу, даже если процесс приложения будет завершен, информация для входа в систему все равно будет сохранена после повторного открытия приложения..

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

  • импортировать зависимости
yarn add redux-persist
  • Изменить конфигурацию редукса

1) Изменитьstore.js.

Помимо введенияredux-persistКроме того, вот использование реакции роднойAsyncStorageКонтейнер для постоянного хранения. Кроме того, инициализируйтеstateпереехал вreducers.jsсередина.

/**
 * store.js
 * 更改为持久化存储
 */

import { createStore } from "redux";

// 引入 AsyncStorage 作为存储容器
import { AsyncStorage } from "react-native";

// 引入 redux-persist
import { persistStore, persistCombineReducers } from "redux-persist";

import reducers from "./reducers";

// 持久化存储配置
const config = {
  key: "root",
  storage: AsyncStorage
};

const persistReducers = persistCombineReducers(config, {
  reducers
});

const configureStore = () => {
  const store = createStore(persistReducers);
  const persistor = persistStore(store);

  return { persistor, store };
};

export default configureStore;

2) Изменитьreducers.js

просто инициализируйstateВъезжать. А зачем инициализироватьstateотstore.jsвъезжатьreducers.jsЭто действительно беспомощно: иначеstore.jsсоздан вstoreЕсли вы сообщите об ошибке, вы заполните яму позже и временно поставите ее наreducers.jsсередина.

/**
 * reducers.js
 * 更改为持久化存储
 */

// 初始化 state 放在这里
const initialState = {
  userInfo: {
    name: "小光",
    gender: "男"
  }
};

function reducers(state = initialState, action) {
  // ... 代码未修改
}

export default reducers;
  • Изменить файлы с помощью редукса

1) Изменить корневой каталогindex.js:

/**
 * index.js
 * 更改为持久化存储
 */
import { PersistGate } from "redux-persist/es/integration/react";
import configureStore from "./src/redux/store";

const { persistor, store } = configureStore();

const ReduxApp = () => (
  // 配置 Provider 为根组件,同时传入 store 作为其属性
  <Provider store={store}>
    {/* redux 持久化存储 */}
    <PersistGate persistor={persistor}>
      <App />
    </PersistGate>
  </Provider>
);

2) Из-за процесса модификации в постоянное хранилище инициализированныйstateсуществуютreducers.js, поэтому в сопоставлении компонентов страницыstateКогда вы дойдете до текущей страницы, вам нужно изменить адрес импорта соответствующего атрибута, по-прежнему используйтеScreenTab2Например:

/**
 * ScreenTab2/index.js
 * 更改为持久化存储
 */

// 修改前
function mapStateToProps(state) {
  // 引用 state.userInfo
  return { userInfo: state.userInfo };
}

// 修改后
function mapStateToProps(state) {
  // 引用 state.reducers.userInfo
  return { userInfo: state.reducers.userInfo };
}

После вышеуказанной модификации может быть реализовано постоянное хранилище избыточности: имя инициализации小光, изменить наvinceПосле перезагрузки страницы имя по-прежнемуvince(а не исходное состояние小光). Схема эффекта выглядит следующим образом:

redux持久化存储

Семь Резюме

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

  • Исходя из использования реактивной навигации,iOS реализует анимацию входа одной страницы снизу вверх (модально)
  • адаптивный размер
  • Установите начальную страницу, измените значок на рабочем столе, отображаемое имя приложения, идентификатор приложения
  • Релиз пакета

использованная литература

Введение в API выборки
Начало работы с Redux
Понимание метода подключения в React-redux