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

React相关

React 是一个采用声明式,高效并且灵活的用来构建用户界面的框架。javascript

JSX

本质上来说,JSX 只是为React.createElement(component, props, ...children)方法提供的语法糖。好比下面的代码:前端

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

编译为:java

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

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

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

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

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

每当 React 元素发生变化时,ReactDOM首先会比较元素内容前后的不一样,而后操做浏览器DOM更新改变了的部分。github

组件 & Props

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

//使用 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')
);

咱们来回顾一下在这个例子中发生了什么:浏览器

  1. 咱们对<Welcome name="Sara" />元素调用了ReactDOM.render()方法。
  2. React 将{name: 'Sara'}做为props传入并调用 Welcome 组件。
  3. Welcome 组件将<h1>Hello, Sara</h1>元素做为结果返回。
  4. 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 个步骤:

  1. 调用 store.dispatch(action)。
  2. Redux store 调用传入的 reducer 函数。
  3. 根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。
  4. Redux store 保存了根 reducer 返回的完整 state 树。

Router相关

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

容器组件 和 展现组件

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

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

组件分离

系列目录

  1. 前端大统一时代即未来临?
  2. React项目实战:环境搭建
  3. React项目实战:react-redux-router基本原理
  4. React项目实战:登陆页面(编辑中)
相关文章
相关标签/搜索