引入React设计模式:Flux,Redux和Context API

作者 : IT 大叔 本文共8128个字,预计阅读时间需要21分钟 发布时间: 2020-08-25

引入React设计模式:Flux,Redux和Context API插图

作为开发人员,我们转向设计原则来帮助我们解决问题。这些作为一种模板,可帮助快速创建应用程序的结构,因此我们可以将MVP付诸实践。Facebook创建React的原因之一不仅在于更快地迭代问题,而且还在于构造代码以使新工程师能够快速入职。

我们在React中使用设计模式,通过应用已被证明可以解决常见问题的解决方案来节省时间。无需重新设计轮子,以后再重构,因为您已经在使用一种可行的设计。

在本文中,我们将讨论您可以选择用于构建React应用程序的常见架构。

今天,我们将介绍:

将您的React技能提升到一个新的水平。

了解如何利用设计模式,并更抽象地思考如何在React中创建应用程序。

反应模式

助焊剂体系结构

一种较常见的设计模式称为MVC设计模式,它代表模型,视图,控制器。此模式将您的代码组织到三个框中:

  • 原始数据,这将是您的应用程序的模型
  • 接收原始数据并将其转换为将控制应用程序状态的功能的逻辑
  • 您的客户端将与之交互并查看应用程序的用户界面

随着应用程序的扩展,MVC数据流可能会成为更大的问题,因为MVC应用程序具有可以在多个方向上移动的数据,从而创建双向数据流。代码很难维护。如果我们想快速迭代问题,那么这种编写代码的方式将行不通。

Facebook通过创建Flux架构解决了这个问题。Flux架构是一种设计模式,该模式仅允许数据在一个方向上流动,而与React配合只能在组件状态改变时更新网页。

助焊剂体系结构的一部分

引入React设计模式:Flux,Redux和Context API插图(2)

1.行动

动作触发了将要发生的事件序列,最终将最终导致UI在React中重新呈现。动作具有类型属性和新数据:

//action types
 
export const ADD_USER = "ADD_USER";
export const UPDATE_USER = "UPDATE_USER";
 
//action creators
 
export const addUser = (payload) => {
   return ({
       type: ADD_USER,
       payload
   })
}
 
export const updateUser = (payload) => {
   return ({
       type: UPDATE_USER, payload
   })
}

type属性描述操作,有效负载是传递的新数据。该有效负载可以是任何类型(对象,字符串等),具体取决于它将用于的动作创建者。在这种情况下,它们可能都是对象,因为我们可能要处理用户ID和用户名或电子邮件地址。

这些动作创建者在调用时是调度程序的责任。

2.调度员

在这种情况下,调度程序实质上是流量控制器。这是用于更新商店的回调函数目录。就像警察调度员会告诉警车去哪里紧急情况一样,通量调度员也会告诉我们应该采取的行动。

var Dispatcher = function () {
  return {
    _stores: [],
    register: function (store) {  
      this._stores.push({ store: store });
    },
    // checks for updates in each store
    dispatch: function (action) {
      if (this._stores.length > 0) {
        this._stores.forEach(function (entry) {
          entry.store.update(action);
        });
      }
    }
  }
};

3.储存

商店处理我们的应用程序状态。在Flux中,我们可以有多个商店,如果需要的话,每个组件一个。状态是持有key:value对的对象,这些对有助于呈现特定组件和/或其子代。

import React, { Component } from 'react';
 
class SampleContainerComponent extends Component {
   constructor(props) {
       super(props);
       this.state = {
           loading: true,
           user: {
               name: "Jane Doe",
               age: 42,
               numKids: 0
           },
           movie: {
               title: "E.T.: The Extra-Terrestrial",
               director: "Steven Spielberg",
               music: "John Williams"
           }
       }
   }
   render() {
       return (
           <>
           <Movie movie={this.state.movie} />
           <User user={this.state.user} />
           </>
       );
   }
}
 
export default SampleContainerComponent;

这些组件将通过传递道具使用它们共有的状态。通过传递用于更新有状态类组件中状态的逻辑,然后在执行逻辑后呈现该组件将在屏幕上显示的实际道具,这继续促进了单向数据流。

4.查看

在状态更新之前,应用程序的视图不会更改。这样可以防止自动重新渲染静态或不需要更改的组件。仅状态已更改的组件将被更新。

全面实施Flux架构

让我们看一下Flux架构的完整实现。在这里,如果添加对AMD,CommonJS和全局用法的支持,则在压缩JavaScript之后,我们将得到66行代码,1.7KB纯文本或795个字节。

var Dispatcher = function () {
  return {
    _stores: [],
    register: function (store) {
      // expecting an `update` method for each store
      if (!store || !store.update) {
        throw new Error(
          'You should provide a store that has an `update` method'
        );
      } else {
        var consumers = [];
        var change = function () {
          consumers.forEach(function (consumer) {
            consumer(store);
          });
        };
        var subscribe = function (consumer, noInit) {
          consumers.push(consumer);
          !noInit ? consumer(store) : null;
        };

        this._stores.push({ store: store, change: change });
        return subscribe;
      }
      return false;
    },
    dispatch: function (action) {
      // check all stores for update
      if (this._stores.length > 0) {
        this._stores.forEach(function (entry) {
          entry.store.update(action, entry.change);
        });
      }
    }
  }
};

module.exports = {
  create: function () {
    var dispatcher = Dispatcher();

    return {
      createAction: function (type) {
        if (!type) {
          throw new Error('Please, provide action\'s type.');
        } else {
          return function (payload) {
            // actions are passed to dispatcher
            return dispatcher.dispatch({
              type: type,
              payload: payload
            });
          }
        }
      },
      createSubscriber: function (store) {
        return dispatcher.register(store);
      }
    }
  }
};

关于Flux Architecture以及它如何与React一起工作,有很多很棒的东西。但是,如果我们的应用程序变大,或者我们的子组件需要将道具传递到四个或五个以上的级别(称为“道具钻探”的概念),则新手更容易出现错误并且难以理解,可能会加快代码的速度。

还有两种可以用来帮助改进Flux体系结构的模式。接下来,我们将讨论Redux。

Redux架构

Redux是一个充当状态容器的库,有助于管理您的应用程序数据流。它类似于Flux架构,并且有很多共同点。Redux架构采用了我们已经了解的Flux架构,并对其进行了扩展,因此对于更宏大,更复杂的应用程序而言,它效率更高。

Redux提供的两个最大改进是,一个商店可供所有 React组件访问和订阅,而商店内部的一个reducer可以确定对应用程序状态的更改。

继续学习

学习React设计模式,而无需阅读视频或文档。最后,您将可以放心地创建高度复杂的应用程序。Educative的基于文本的课程易于浏览,并具有实时编码环境。

反应模式

Redux体系结构的一部分

Redux的大部分架构与Flux架构非常相似。我们将遍历体系结构中彼此不同的部分:

引入React设计模式:Flux,Redux和Context API插图(4)

一店保持状态

当我们考虑Flux体系结构及其工作原理时,我们知道它具有单向数据流。我们倾向于从亲子关系的角度来考虑React应用程序。例如,如果我们有一个子组件说需要与堂兄对话,该怎么办?

如果使用Flux Architecture,则状态将提升到两个组件的最接近的共同祖先。当最接近的共同祖先回到五代时,这变得有些复杂。这可能会导致称为“道具钻探”的问题,并使代码的可读性降低。这就是Redux的用武之地。

Redux用封装了我们的React组件,Provider从而为我们提供了一个Store包含应用程序大部分状态的。Components连接到此商店,并订阅mapStateToProps他们需要在特定组件中使用的状态。

CreateStore

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { taskReducer } from './reducers/taskReducer';
 
import './index.css';
import App from './App';
 
const store = createStore(taskReducer);
 
 
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));

Connect to Component via MapStateToProps

const mapStateToProps = state => {
   return {
       tasks: state.tasks
   }
}
 
export default connect(mapStateToProps, { addNewTask, toggleTask })(Tasks);

数据流本质上是相同的,单向的,但是状态管理是在全局级别上进行的,而不是在容器级别上进行的,容器级别依赖于将状态作为道具传递给容器的子级。

确定状态如何变化的减速器

减速器作为参数传递给我们的商店。减速器本身接受动作和应用程序的当前状态。减速器内部的逻辑看起来可以,但是只要您复制当前状态然后进行更改即可。此外,只能使用传入的参数来计算新状态。

不能使用随机值,不能使用异步逻辑或其他会导致流中断的方法。减速器的主要工作是帮助Redux跟踪状态随着时间的变化。

//Example Reducer for a ToDo List Application:
import { ADD_TASK, TOGGLE_COMPLETE } from '../actions';
 
const initialState = {
   tasks: [
       {task: 'Wash the car', complete: false},
       {task: "Laundry", complete: false}
   ]
}
 
export const taskReducer = (state = initialState, action) => {
   switch(action.type) {
       case ADD_TASK:
           return {
               ...state, tasks: [
                   ...state.tasks, { task: action.payload, complete: false}
               ]
           }
 
       case TOGGLE_COMPLETE:
          return {
              ...state, tasks: state.tasks.map((item, index) => {
              if(action.payload === index) {
                  return {
                      ...item, complete: !item.complete
                  }
              } else {
                  return item;
              }
          })
       }
       default:
           return state;
   }
}

关于Redux的最终想法

Redux的优点在于,我们拥有掌握状态的一个真理来源。有一个reducer(一个或多个reducer)从调度程序/事件处理程序接收一个动作,然后采取该动作告诉商店如何处理它。

当商店更新时,我们将在UI中看到更新的组件的重新呈现。我们可以使用Redux DevTools查看状态如何随时间变化。

如果需要,Redux是一个很棒的工具。请特别注意数据库的结构,如何使用它以及应用程序流程将如何进行。在不一定需要使用Redux的情况下,有很多次使用它。仅在需要时才真正使用它。

我们将要讨论的最后一个设计模式是许多人可能认为可以替代Redux:Context API。

带有React Hooks的上下文API

现在有一个可供我们使用的工具,它结合了redux的最佳功能和flux的最佳功能。它称为Context API,它使状态管理变得比以往更加容易。

在上下文中,我们有几个应用程序范围的存储,用于提供全局级别的状态。它使用上下文提供程序完成此操作。在此上下文提供程序中,有一些钩子可以帮助您从根本上创建一个上下文对象,可以从应用程序中的所有组件进行访问。

主题上下文的最终用法将最终在明亮和黑暗主题之间切换:

import React, { useState, createContext } from 'react';
 
//my resources
import LightCode from '../assets/screenshotlight.png';
import DarkCode from '../assets/screenshotdark.png';
 
 
//create context to hold themes
export const ThemeContext = createContext();
 
export const ThemeContextProvider = ({ children }) => {
   const [isLight, setIsLight] = useState(true);
 
   //define light and dark themes...
   const dark = {
       backgroundPicture: `url('${DarkCode}')`,
       oppositeTheme: "light",
       buttonbg: "#47a5bf",
       buttoncolor: "#ffe54f",
       background: '#121212',
       cardColor: 'darkslategrey',
       primary: '#bb86fc',
       primaryVariant: '#3700b3',
       secondary: '#03dac6',
       surface: '#121212',
       error: '#cf6679',
       onPrimary: '#000000',
       onSecondary: '#000000',
       onBackground: '#fafafa',
       onSurface: '#fafafa',
       onError: '#000000',
 
   };
 
   const light = {
       backgroundPicture: `url('${LightCode}')`,
       oppositeTheme: "dark",
       buttonbg: "#1e39a6",
       buttoncolor: "yellow",
       background: '#F1EFE7',
       cardColor: 'whitesmoke',
       primary: '#6200ee',
       primaryVariant: '#3700b3',
       secondary: '#03dac6',
       secondaryVariant: '#018786',
       surface: "#ffffff",
       error: "#b00020",
       onPrimary: "#ffffff",
       onSecondary: "#000000",
       onBackground: "#000000",
       onSurface: "#000000",
       onError: "#ffffff",
   };
  
   const toggle = () => {
       return isLight ? setIsLight(false) : setIsLight(true);
   }
 
   const theme = isLight ? light : dark;
     return <ThemeContext.Provider value={{theme, toggle}}>{children}</ThemeContext.Provider>;
};

传递给值的是<ThemeContext.Provider>使用useContext钩子将其拉入组件时如何访问上下文。要在您的组件中利用,语法是这样的:

const { theme, toggle } = useContext(ThemeProvider);

上下文对象的解构与您传递到中的value属性的值匹配<ThemeContext.Provider>。这样,您可以使用这些属性,而不必说context.toggle或context.theme。

确保将其导出ThemeProvider并包装在整个组件中,index.js以便在切换主题时可以在任何地方更改主题。

//installed packages
import "dotenv/config";
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
 
//my contexts
import { ThemeContextProvider } from './context/ThemeContext';
 
//my components
import App from './App';
import ScrollToTop from './ScrollToTop';
 
ReactDOM.render(
 <Router>
     <ThemeContextProvider>
     	<App />
     </ThemeContextProvider>
 </Router>,
 document.getElementById('root')
);

您仍然需要声明有关样式的React组件规则。为此,我将推荐您最喜欢的CSS-in-JS程序包,以便在对组件的颜色和背景色进行样式设置时可以访问主题。

关于Context API的最终想法

Context API是获得Redux某些优势的好工具,而无需具备Redux所需的所有样板。自从React Hooks变得流行以来,这使其成为一种设计应用程序的流行方法。

我们将状态提升给上下文提供者,后者将状态作为道具传递给我们的组件树,以便我们在需要时可以将最好的Redux和最好的Flux结合起来使用。

接下来要学什么?

在本文中,我们研究了在React中构建应用程序的三种方式:Flux,Redux和Context。根据您的个人需求,这三种都是可行的选择。对于不需要太多传递道具的小型应用程序,Flux非常有用。

对于需要跟踪多个状态的大型应用程序,Redux很棒。Context API是先前世界中最好的一种。它具有全局上下文对象,该对象对于作为道具传递给提供程序的所有组件都是可用的。

接下来您将要学习掌握React模式:

  • React中的高阶组件
  • 用React进行依赖注入
  • 样式化React组件
  • 集成第三方库
  • 和更多
免责声明:
1. 本站资源转自互联网,源码资源分享仅供交流学习,下载后切勿用于商业用途,否则开发者追究责任与本站无关!
2. 本站使用「署名 4.0 国际」创作协议,可自由转载、引用,但需署名原版权作者且注明文章出处
3. 未登录无法下载,登录使用金币下载所有资源。
IT小站 » 引入React设计模式:Flux,Redux和Context API

常见问题FAQ

没有金币/金币不足 怎么办?
本站已开通每日签到送金币,每日签到赠送五枚金币,金币可累积。
所有资源普通会员都能下载吗?
本站所有资源普通会员都可以下载,需要消耗金币下载的白金会员资源,通过每日签到,即可获取免费金币,金币可累积使用。

发表评论