在React Native应用程序中使用Redux示例

在React Native应用程序中使用Redux示例

这是在 React Native App 中使用 Redux 的示例。 我们都知道 Redux 是一个状态管理库,它将帮助您在一个名为的地方管理所有状态 店铺。 在 React Native 中集成 Redux 的帮助非常简单 反应还原。 在这个例子中我们将看到

  1. 在 React Native 应用程序中设置 Redux 库
  2. 在单个页面中管理状态
  3. 调度动作并在减速器中处理它们
  4. 使用 Redux 存储中的不同状态

我们请求所有刚接触 React Native 并想要学习这个概念的读者,请花一些时间来理解 props、state 和 Components。 一旦你对此有了清晰的认识,那么你就可以从 Redux 开始了。 虽然使用 Redux 创建 React Native 应用程序非常简单,但如果不理解基本概念,你会发现它有点复杂。

推荐:使用React Native应用程序在Google Drive上存储检索文件

什么是 Redux?

终极版 是一个状态管理库,可帮助您将应用程序逻辑组织在一个地方,以便您的应用程序可以按您的预期工作。 Redux 使您的应用程序代码非常易于理解,并且您可以管理有关应用程序状态何时、何地、为何以及如何更新的逻辑 + 状态。 它由以下几个关键部分组成:

  • actions
  • reducers
  • store
  • dispatch
  • selector

动作和动作创建者

一个actions行动 是一个普通的 JavaScript 对象,具有类型字段和可选的有效负载。 它也可以被认为是描述已经发生的事情的事件。

export const addToBookmark = (item) => {
  return (dispatch) => {
    dispatch({
      type: 'ADD_BOOKMARK',
      payload: item,
    });
  };
};

动作创作者 只是创建和返回操作对象的函数。

reducers

reducers减速器 也是一个接收当前状态和操作对象的函数,如果需要更新状态并返回新状态。 不允许减速器修改现有状态; 相反,它复制现有状态并更改复制的值。 换句话说,reducer 应该是一个纯函数。 这是一个例子

const initialState = {
  bookmarkItems: (),
};

const reducers = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_BOOKMARK':
      return Object.assign({}, state, {
        counter: state.counter + 1,
        bookmarkItems: (...state.bookmarkItems, action.payload),
        postData: filter_records(state.postData, (
          ...state.bookmarkItems,
          action.payload,
        )),
        sort: 'NA',
      });
    .....
    .....
    .....
  }
};

store

store 是一个存储 Redux 应用程序当前状态的对象。 您可以通过将减速器传递给来创建存储的初始状态 createStore 功能。

import {createStore} from 'redux';
import rootReducer from './src/utils/reducers';
const store = createStore(rootReducer);

调度和选择器

dispatch() 是 Redux 存储方法,用于通过传递操作对象来更新状态。

dispatch(addToBookmark(item))

选择器用于从存储中读取数据。

这是一个流程,可以帮助您更好地理解它。

React_native_redux_flow

React Native Redux 示例描述

在此示例中,我们将创建一个简单的书签应用程序,它将有 2 个屏幕,一个用于列出添加的书签,另一个用于列出帖子。 我们不会将书签永久存储在应用程序中,因为这只是为了理解 Redux 的概念。

每当用户登陆书签屏幕时,他/她都会看到添加的所有书签(第一次什么都没有)。 每当用户想要添加书签时,他/她可以单击书签屏幕中的添加按钮,并且可以看到帖子列表以在书签中添加任何帖子。 一旦用户点击任何帖子,该帖子就会从帖子列表中消失并添加到书签中,用户可以在标题中看到添加的书签总数。 当用户按下后退按钮时,他/她将看到更新的书签列表,该列表可以根据帖子 ID 升序/降序排序。

对于帖子列表,我们有 发布数据 在商店中注明我们有书签 书签项目。 每当用户登陆帖子屏幕时,我们都会调度 获取帖子列表 函数作为一个动作,它将是一个异步函数,我们使用了react-thunk中间件。 一旦我们得到获取的响应,我们将调度一个带有有效负载的操作,该操作将更新我们的 发布数据 状态这将帮助我们渲染帖子列表。

单击任何帖子后,我们将发送 添加到书签 带有有效负载的操作将添加单击的记录 书签项目 并将该记录从 发布数据。 如上所述,用户还可以对书签列表进行排序,这可以使用 排序书签列表 行动。

我希望您明白我们要做什么,所以让我们开始使用 Redux 创建 React Native 应用程序。

制作 React Native 应用程序

React Native 入门将帮助您更多地了解如何制作 React Native 项目。 我们将使用 React Native 命令行界面来制作我们的 React Native 应用程序。

如果您之前安装了全局的react-native-cli软件包,请将其删除,因为它可能会导致意外问题:

npm uninstall -g react-native-cli @react-native-community/cli

运行以下命令创建一个新的 React Native 项目

npx react-native init ProjectName

如果你想使用特定的 React Native 版本启动一个新项目,你可以使用 –version 参数:

npx react-native init ProjectName --version X.XX.X

注意如果上述命令失败,您可能使用的是旧版本 react-native 或者 react-native-cli 在您的电脑上全局安装。 尝试卸载 cli 并使用 npx 运行 cli。

这将在项目目录中创建一个带有名为 App.js 的索引文件的项目结构。

安装依赖项

要安装任何依赖项,请打开终端并使用以下命令跳转到项目中

cd ProjectName

要在 React Native 中使用 Redux,我们需要安装 还原 这是一个独立的库,可以与任何 UI 层或框架一起使用,我们还需要安装 反应还原 这是 React 的官方 Redux UI 绑定库。

对于这个例子,我们调用一个 API,它是一个异步操作,为此我们需要添加 redux-thunk 支持同样的。

npm install redux react-redux redux-thunk --save

我们在此示例中使用 React Navigation,因此我们还需要安装导航的依赖项

npm install @react-navigation/native --save

其他导航支持库

npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view --save

对于堆栈导航器

npm install @react-navigation/stack --save

此命令会将所有依赖项复制到您的 node_module 目录中。 –save 是可选的,它只是更新 package.json 文件中的依赖项。

项目目录/文件结构

要开始此示例,您需要创建以下目录/文件结构。 项目将有一个 源代码 包含我们所有代码的目录,src 目录将还有两个目录 成分实用程序。 所有这些目录将包含以下文件作为完整示例。

react_native_redux_exmaple_struct

你可以看到

  1. 应用程序.js 包含主导航
  2. src/BookmarkScreen.js,包含所有书签的登陆页面
  3. src/PostList.js, 包含用户可以添加到书签的帖子列表
  4. src/components/HeaderCountLabel.jsPostList 标题中的计数器标签显示添加的书签数量
  5. src/components/HeaderSortLabel.js对添加的书签进行排序
  6. src/utils/actions.js,具有所有动作函数定义
  7. src/utils/reducers.js,拥有基于动作的所有状态管理

在 React Native 中使用 Redux 的代码

应用程序.js

// Use of Redux in React Native App | React Native Redux
// https://aboutreact.com/react-native-redux/
import 'react-native-gesture-handler';

import * as React from 'react';
import thunk from 'redux-thunk';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';

import rootReducer from './src/utils/reducers';
import HeaderSortLabel from './src/components/HeaderSortLabel';
import HeaderCountLabel from './src/components/HeaderCountLabel';

const store = createStore(rootReducer, applyMiddleware(thunk));

import BookmarkScreen from './src/BookmarkScreen';
import PostList from './src/PostList';

const Stack = createStackNavigator();

const AppNavigator = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator
        initialRouteName="BookmarkScreen"
        screenOptions={{
          headerStyle: {
            backgroundColor: '#f4511e',
          },
          headerTintColor: '#fff',
          headerTitleStyle: {
            fontWeight: 'bold',
          },
        }}>
        <Stack.Screen
          name="BookmarkScreen"
          component={BookmarkScreen}
          options={{
            title: 'Bookmarks',
            headerRight: () => <HeaderSortLabel />,
          }}
        />
        <Stack.Screen
          name="PostList"
          component={PostList}
          options={{
            title: 'Posts',
            headerRight: () => <HeaderCountLabel />,
          }}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

const App = () => {
  return (
    <Provider store={store}>
      <AppNavigator />
    </Provider>
  );
};

export default App;

src/BookmarkScreen.js

// Use of Redux in React Native App | React Native Redux
// https://aboutreact.com/react-native-redux/
import React from 'react';
import {
  FlatList,
  View,
  Text,
  SafeAreaView,
  StyleSheet,
  Image,
  TouchableOpacity,
} from 'react-native';
import {connect} from 'react-redux';
import {removeFromBookmark} from './utils/actions';

const BookmarkScreen = (props) => {
  const getItem = (item) => {
    props.removeFromBookmark(item);
  };

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.container}>
        <Text style={styles.titleStyle}>
          React Native + Redux Example
        </Text>
        <Text style={{textAlign: 'center'}}>
          Total Bookmarks: {props.counter}
        </Text>
        <FlatList
          data={props.bookmarkItems}
          ItemSeparatorComponent={
            () => <View style={styles.divider} />
          }
          renderItem={({item}) => {
            return (
              <TouchableOpacity onPress={() => getItem(item)}>
                <View style={styles.innerContainer}>
                  <Text>
                    Id: {item.id}
                    {'\n'}
                    Title: {item.title}
                    {'\n'}
                    Body : {item.body}
                  </Text>
                  <Text style={styles.itemRed}>
                    Remove from Bookmark
                  </Text>
                </View>
              </TouchableOpacity>
            );
          }}
          keyExtractor={(_item, index) => index.toString()}
        />
        <TouchableOpacity
          activeOpacity={0.7}
          onPress={() => props.navigation.navigate('PostList')}
          style={styles.touchableOpacityStyle}>
          <Image
            source={{
              uri:
                'https://raw.githubusercontent.com/AboutReact/sampleresource/master/plus_icon.png',
            }}
            style={styles.floatingButtonStyle}
          />
        </TouchableOpacity>
      </View>
      <Text
        style={{
          fontSize: 16,
          textAlign: 'center',
          color: 'grey',
        }}>
        www.aboutreact.com
      </Text>
    </SafeAreaView>
  );
};

const mapStateToProps = (state) => {
  const {counter, bookmarkItems} = state;
  return {
    counter: counter,
    bookmarkItems: bookmarkItems,
  };
};

const mapDispatchToProps = (dispatch) => ({
  removeFromBookmark: (item) => dispatch(removeFromBookmark(item)),
});

export default connect(mapStateToProps, mapDispatchToProps)(BookmarkScreen);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
    padding: 10,
  },
  titleStyle: {
    fontSize: 22,
    fontWeight: 'bold',
    textAlign: 'center',
    padding: 10,
  },
  textStyle: {
    fontSize: 16,
    textAlign: 'center',
    padding: 10,
  },
  touchableOpacityStyle: {
    position: 'absolute',
    width: 50,
    height: 50,
    alignItems: 'center',
    justifyContent: 'center',
    right: 30,
    bottom: 30,
  },
  floatingButtonStyle: {
    resizeMode: 'contain',
    width: 50,
    height: 50,
  },
  innerContainer: {
    padding: 10,
  },
  itemRed: {
    color: 'red',
  },
  divider: {
    height: 0.5,
    width: '100%',
    backgroundColor: '#C8C8C8',
  },
});

src/PostList.js

// Use of Redux in React Native App | React Native Redux
// https://aboutreact.com/react-native-redux/
import React, {useState} from 'react';
import {
  View,
  Text,
  SafeAreaView,
  StyleSheet,
  FlatList,
  TouchableOpacity,
} from 'react-native';
import {connect} from 'react-redux';
import {getPostsList, addToBookmark} from './utils/actions';

const PostList = (props) => {
  useState(() => {
    props.getPostsList();
  }, ());

  return (
    <SafeAreaView style={styles.container}>
      <View style={{flex: 1}}>
        <FlatList
          data={props.postData}
          ItemSeparatorComponent={
            () => <View style={styles.divider} />
          }
          renderItem={({item}) => {
            return (
              <TouchableOpacity
                onPress={() => {
                  props.addToBookmark(item);
                }}>
                <View style={styles.innerContainer}>
                  <Text>
                    Id: {item.id}
                    {'\n'}
                    Title: {item.title}
                    {'\n'}
                    Body : {item.body}
                  </Text>
                  <Text style={styles.itemRed}>
                    Click to Add in Bookmark
                  </Text>
                </View>
              </TouchableOpacity>
            );
          }}
          keyExtractor={(_item, index) => index.toString()}
        />
      </View>
    </SafeAreaView>
  );
};

const mapStateToProps = (state) => {
  const {postData} = state;
  return {
    postData: postData,
  };
};

const mapDispatchToProps = (dispatch) => ({
  getPostsList: () => dispatch(getPostsList()),
  addToBookmark: (item) => dispatch(addToBookmark(item)),
});

export default connect(mapStateToProps, mapDispatchToProps)(PostList);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
    padding: 10,
  },
  innerContainer: {
    padding: 10,
  },
  itemRed: {
    color: 'red',
  },
  divider: {
    height: 0.5,
    width: '100%',
    backgroundColor: '#C8C8C8',
  },
});

src/components/HeaderCountLabel.js

// Use of Redux in React Native App | React Native Redux
// https://aboutreact.com/react-native-redux/
import React from 'react';
import {Text} from 'react-native';
import {connect} from 'react-redux';

const HeaderCountLabel = (props) => {
  return (
    <Text style={{color: 'white', fontWeight: 'bold', padding: 10}}>
      Bookmarked: {props.counter}
    </Text>
  );
};

const mapStateToProps = (state) => {
  const {counter} = state;
  return {
    counter: counter,
  };
};

export default connect(mapStateToProps)(HeaderCountLabel);

src/components/HeaderSortLabel.js

// Use of Redux in React Native App | React Native Redux
// https://aboutreact.com/react-native-redux/
import React from 'react';
import {Text} from 'react-native';
import {connect} from 'react-redux';
import {sortBookMarkList} from '../utils/actions';

const HeaderSortLabel = (props) => {
  return (
    <Text
      style={{color: 'white', fontWeight: 'bold', padding: 10}}
      onPress={() => props.sortBookMarkList()}>
      Sort: {props.sort}
    </Text>
  );
};

const mapStateToProps = (state) => {
  const {sort} = state;
  return {
    sort: sort,
  };
};

const mapDispatchToProps = (dispatch) => ({
  sortBookMarkList: () => dispatch(sortBookMarkList()),
});

export default connect(mapStateToProps, mapDispatchToProps)(HeaderSortLabel);

src/utils/actions.js

// Use of Redux in React Native App | React Native Redux
// https://aboutreact.com/react-native-redux/
export const addToBookmark = (item) => {
  return (dispatch) => {
    dispatch({
      type: 'ADD_BOOKMARK',
      payload: item,
    });
  };
};

export const removeFromBookmark = (item) => {
  return (dispatch) => {
    dispatch({
      type: 'REMOVE_BOOKMARK',
      payload: item,
    });
  };
};

export const sortBookMarkList = () => {
  return (dispatch) => {
    dispatch({
      type: 'SORT_BOOKMARK_LIST',
    });
  };
};

export const getPostsList = () => {
  return (dispatch) => {
    fetch('https://jsonplaceholder.typicode.com/posts', {
      method: 'GET',
    })
      .then((response) => response.json())
      .then((responseJson) => {
        dispatch({
          type: 'POST_LIST_DATA',
          payload: responseJson,
        });
      })
      .catch((error) => {
        console.error(error);
      });
  };
};

src/utils/reducers.js

// Use of Redux in React Native App | React Native Redux
// https://aboutreact.com/react-native-redux/
const initialState = {
  counter: 0,
  bookmarkItems: (),
  sort: 'NA',
  postData: (),
};

const reducers = (state = initialState, action) => {
  switch (action.type) {
    case 'REMOVE_BOOKMARK':
      let newBookmarkItems =
        state.bookmarkItems.filter((bookmarkPost) => {
        return action.payload.id != bookmarkPost.id;
      });
      return Object.assign({}, state, {
        counter: state.counter - 1,
        bookmarkItems: newBookmarkItems,
      });
    case 'ADD_BOOKMARK':
      return Object.assign({}, state, {
        counter: state.counter + 1,
        bookmarkItems: (...state.bookmarkItems, action.payload),
        postData: filter_records(state.postData, (
          ...state.bookmarkItems,
          action.payload,
        )),
        sort: 'NA',
      });
    case 'SORT_BOOKMARK_LIST':
      let sortedBookMarks = state.bookmarkItems;
      let sortOrder="NA";
      if (state.sort == 'NA') {
        sortedBookMarks.sort(sort_by('id', true, parseInt));
        sortOrder="ASC";
      } else if (state.sort == 'ASC') {
        sortedBookMarks.sort(sort_by('id', false, parseInt));
        sortOrder="DESC";
      } else if (state.sort == 'DESC') {
        sortedBookMarks.sort(sort_by('id', true, parseInt));
        sortOrder="ASC";
      }
      return Object.assign({}, state, {
        sort: sortOrder,
        bookmarkItems: (...sortedBookMarks),
      });
    case 'POST_LIST_DATA':
      return Object.assign({}, state, {
        postData: filter_records(
          action.payload,
          state.bookmarkItems
        ),
      });
    default:
      return state;
  }
};

const filter_records = (mainArray, childArray) => {
  return mainArray.filter((mainElement) => {
    if (childArray.length > 0) {
      let isReturnable = true;
      childArray.forEach((childElement) => {
        if (Number(mainElement.id) === Number(childElement.id)) {
          isReturnable = false;
        }
      });
      return isReturnable;
    } else return mainElement;
  });
};

const sort_by = (field, reverse, primer) => {
  const key = primer
    ? function (x) {
        return primer(x(field));
      }
    : function (x) {
        return x(field);
      };
  reverse = !reverse ? 1 : -1;
  return function (a, b) {
    return
      (a = key(a)), (b = key(b)), reverse * ((a > b) - (b > a));
  };
};

export default reducers;

运行 React Native 应用程序

再次打开终端并使用跳转到您的项目。

cd ProjectName

1. 启动 Metro Bundler

首先,您需要启动 Metro,React Native 附带的 JavaScript 捆绑器。 要启动 Metro 捆绑程序,请运行以下命令

npx react-native start

一旦您启动 Metro Bundler,它将永远在您的终端上运行,直到您将其关闭。 让 Metro Bundler 在自己的终端中运行。 打开一个新终端并运行该应用程序。

2.启动React Native应用程序

在 Android 虚拟设备或真实调试设备上运行项目

npx react-native run-android

或在 iOS 模拟器上运行(仅限 macOS)

npx react-native run-ios

输出截图

这就是在 React Native 应用程序中使用 Redux 的方法。 Redux 是一个很有价值的工具,但只有以正确的方式使用它才有用。 Redux 可能有用的一些情况包括由许多人正在处理的代码或包含大量应用程序状态的应用程序。

推荐:4个不同的命令来关闭重新启动Ubuntu Linux


发表评论