React项目实战:react-redux-router基本原理

更新日期: 2017-11-27阅读: 3.7k标签: redux作者: cinglong

JSX

本质上来讲,JSX 只是为react.createElement(component, props, ...children)方法提供的语法糖。比如下面的代码

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

编译为:

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

React.createElement()这个方法首先会进行一些避免bug的检查,之后会返回一个类似下面例子的对象:

const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world'
  }
};

这样的对象被称为React元素,它代表所有你在屏幕上看到的东西。
我们用 React 开发应用时一般只会定义一个根节点。要将 React 元素渲染到根dom节点中,我们通过把它们都传递给ReactDOM.render()的方法来将其渲染到页面上:

ReactDOM.render(
  element,
  document.getElementById('root')
);

每当 React 元素发生变化时,ReactDOM首先会比较元素内容先后的不同,然后操作浏览器DOM更新改变了的部分。

组件 & Props

当 React 遇到的元素是用户自定义的组件,它会将 JSX 属性作为单个对象传递给该组件,这个对象称之为props。无论是使用函数或是类来声明一个组件,它决不能修改它自己的 props 。
例如,这段代码会在页面上渲染出Hello,Sara:

//使用 ES6 class 来定义一个组件,组件名称必须以大写字母开头。
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

我们来回顾一下在这个例子中发生了什么:

    我们对<Welcome name="Sara" />元素调用了ReactDOM.render()方法。

    React 将{name: 'Sara'}作为props传入并调用 Welcome 组件。

    Welcome 组件将<h1>Hello, Sara</h1>元素作为结果返回。

    ReactDOM 将DOM更新为<h1>Hello, Sara</h1>。

State & 生命周期

组件的通过props获取属性,且其不能修改;当我们需要修改当前组件的状态时,要用到state来设置局部状态,需要通过this.setState()来更新组件局部状态:

class Toggle extends React.Component {
  constructor(props) {
    super(props);    //初始化this,并赋值this.props
    this.state = {isToggleOn: true};    //初始化this.state
    this.handleClick = this.handleClick.bind(this);    //为this.handleClick绑定this对象
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));    //用this.setState()更新this.state
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

每一个组件都有几个你可以重写以让代码在处理环节的特定时期运行的“生命周期方法”。方法中带有前缀will的在特定环节之前被调用,而带有前缀did的方法则会在特定环节之后被调用。

装配:这些方法会在组件实例被创建和插入DOM中时被调用:

- constructor(`props`)
- componentWillMount()
- render()
- componentDidMount()

更新:属性或状态的改变会触发一次更新。当一个组件在被重渲时,这些方法将会被调用:

- componentWillReceiveProps(`nextProps`)
- shouldComponentUpdate(`nextProps`, `nextState`)
- componentWillUpdate(`nextProps`, `nextState`)
- render()
- componentDidUpdate(`prevProps`, `prevState`)

卸载:当一个组件被从DOM中移除时,该方法被调用:

- componentWillUnmount()

当项目视图交互复杂且频繁的时候,依旧采用 state 进行状态更改会显得异常繁琐和不可预测。
这时我们就需要借助 Redux 框架,将状态数据全部转交给 Redux 处理,React 专一负责视图显示,这样会让项目逻辑变得简单而清晰。


Redux相关

三大原则:

整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个store中。

惟一改变 state 的方法就是触发action,action 是一个用于描述事件的普通对象。

为了描述 action 如何改变 state tree ,你需要编写reducers。

Action

Action 是把数据从项目传到 store 的有效载荷。它是 store 数据的唯一来源。通常你会通过store.dispatch()将 action 传到 store。

Action 本质上是 JavaScript 普通对象,添加新 todo 任务的 action 是这样的:

{
  type: 'ADD_TODO',
  text: 'Build my first Redux app'
}

Action 创建函数就是生成 action 的方法。在 Redux 中的 action 创建函数只是简单的返回一个 action:

function addTodo(text) {
  return {
    type: 'ADD_TODO',
    text: text
  }
}

这样做将使 action 创建函数更容易被移植和测试。只需把 action 创建函数的结果传给 dispatch() 方法即可发起一次 dispatch 过程。

dispatch(addTodo(text));

//或者创建一个 被绑定的 action 创建函数 来自动 dispatch:
const boundAddTodo = (text) => dispatch(addTodo(text));
boundAddTodo(text);

store 里能直接通过 store.dispatch() 调用 dispatch() 方法,但是多数情况下你会使用 react-redux 提供的connect()帮助器来调用。

Reducer

Action 只是描述了有事情发生了这一事实,而reducer要做的事情正是指明应用如何更新 state 。reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。

(previousState, action) => newState

保持 reducer 纯净非常重要。永远不要在 reducer 里做这些操作:

修改传入参数;

执行有副作用的操作,如 api 请求和路由跳转;

调用非纯函数,如 Date.now() 或 Math.random()。

我们将以指定 state 的初始状态作为开始。Redux 首次执行时,state 为 undefined,此时我们可借机设置并返回应用的初始 state:

const initialState = {};    //初始化state

function todoApp(state = initialState, action) {
  switch (action.type) {
    case 'ADD_TODO':
      return Object.assign({}, state, {
        text: action.text
      })
    default:
      return state    //在 default 情况下返回旧的 state
  }
}

每个 reducer 只负责管理全局 state 中它负责的一部分。每个 reducer 的 state 参数都不同,分别对应它管理的那部分 state 数据。

combineReducers()所做的只是生成一个函数,这个函数来调用你的一系列 reducer,每个 reducer 根据它们的 key 来筛选出 state 中的一部分数据并处理,然后这个生成的函数再将所有 reducer 的结果合并成一个大的对象。

import { combineReducers } from 'redux';

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp;

注意上面的写法和下面完全等价:

export default function todoApp(state = {}, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}

combineReducers 接收一个对象,可以把所有顶级的 reducer 放到一个独立的文件中,通过 export 暴露出每个 reducer 函数,然后使用 import * as reducers 得到一个以它们名字作为 key 的 object:

import { combineReducers } from 'redux'
import * as reducers from './reducers'

const todoApp = combineReducers(reducers)

Store

action 来描述“发生了什么,reducers 根据 action 更新 state,Store就是把它们联系到一起的对象。Store 有以下职责:

维持应用的 state;

提供getState()方法获取 state;

提供dispatch(action)方法更新state;

通过subscribe(listener)注册监听器;

通过subscribe(listener)返回的函数注销监听器。

我们使用 combineReducers() 将多个 reducer 合并成为一个。现在我们将其导入,并传递 createStore()。

import { createStore } from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp)

createStore() 的第二个参数是可选的, 用于设置 state 初始状态。这对开发同构应用时非常有用,服务器端 redux 应用的 state 结构可以与客户端保持一致, 那么客户端可以将从网络接收到的服务端 state 直接用于本地数据初始化。

let store = createStore(todoApp, window.STATE_FROM_SERVER);


数据流

Redux 应用中数据的生命周期遵循下面 4 个步骤:

    调用 store.dispatch(action)。

    Redux store 调用传入的 reducer 函数。

    根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。

    Redux store 保存了根 reducer 返回的完整 state 树。

Router相关

直接使用整合后的react-router-redux,后面抽时间再详细讲一下,具体使用的话模仿官方案例吧,官方文档

容器组件 和 展示组件

Redux 的 React 绑定库包含了 容器组件和展示组件相分离 的开发思想。

明智的做法是只在最顶层组件(如路由操作)里使用 Redux。其余内部组件仅仅是展示性的,所有数据都通过 props 传入。

原文来源:https://segmentfault.com/a/1190000012170435


链接: https://fly63.com/article/detial/169

react关于 Redux与flux的比较学习

flux四大元素:Dispatcher:根据注册派发动作(action),Store: 存储数据,处理数据,Action:用于驱动Dispatcher,View: 用户界面视图。flux的目的:纠正MVC框架的无法禁绝view与model通信的缺点。Redux基本原则:继承Flux基本原则:单向数据流

如何优雅地在React项目中使用Redux

Redux:状态管理工具,与React没有任何关系,其他UI框架也可以使用Redux,react-redux:React插件,作用:方便在React项目中使用Redux,react-thunk:中间件,作用:支持异步action

从 源码 谈谈 redux compose

compose,英文意思 组成,构成。它的作用也是通过一系列的骚操作,实现任意的、多种的、不同的功能模块的组合,用来加强组件。很容易实现功能的组合拼装、代码复用;可以根据需要组合不同的功能;

Redux与它的中间件:redux-thunk,redux-actions,redux-promise,redux-sage

这里要讲的就是一个Redux在React中的应用问题,讲一讲Redux,react-redux,redux-thunk,redux-actions,redux-promise,redux-sage这些包的作用和他们解决的问题。

redux中间件的原理_深入理解 Redux 中间件

最近几天对 redux 的中间件进行了一番梳理,又看了 redux-saga 的文档,和 redux-thunk 和 redux-promise 的源码,结合前段时间看的redux的源码的一些思考,感觉对 redux 中间件的有了更加深刻的认识,因此总结一下

react-redux 的使用

类似于 Vue,React 中组件之间的状态管理 第三方包为:react-redux。react-redux 其实是 Redux的官方React绑定库,它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据。

如何使用useReducer Hook?

看到“reducer”这个词,容易让人联想到Redux,但是在本文中,不必先理解Redux才能阅读这篇文章。咱们将一起讨论“reducer”实际上是什么,以及如何利用useReducer来管理组件中的复杂状态,以及这个新钩子对Redux意味着什么?

带着问题看React-Redux源码

我在读React-Redux源码的过程中,很自然的要去网上找一些参考文章,但发现这些文章基本都没有讲的很透彻,很多时候就是平铺直叙把API挨个讲一下,而且只讲某一行代码是做什么的,却没有结合应用场景和用法解释清楚为什么这么做。

React Hooks 是不能替代 Redux 的

我的许多同事最近通过各种方式问同一类问题:“如果我们开始用 hook 后,那还有必要用 Redux 吗?”“React hook 不是让 Redux 过时了吗?那只用 Hooks 就可以做 Redux 所有能做的事了吧?”

redux和react-redux

redux是react的状态管理工具,却不仅仅只是为了react而生的,所以在使用中会存在痛点。而react-redux是专门为了react定制,目的是为了解决redux的痛点,起到了补充的作用。flux无非就是一个常见的event dispatcher

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!