资讯专栏INFORMATION COLUMN

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

MorePainMoreGain / 1919人阅读

摘要:组件将元素作为结果返回。是把数据从项目传到的有效载荷。有以下职责维持应用的提供方法获取提供方法更新通过注册监听器通过返回的函数注销监听器。系列目录前端大统一时代即将来临项目实战环境搭建项目实战基本原理项目实战登录页面编辑中

React相关

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

JSX

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

const element = (
  

Hello, world!

);

编译为:

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 

Hello, {this.props.name}

; } } const element = ; ReactDOM.render( element, document.getElementById("root") );

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

我们对元素调用了ReactDOM.render()方法。

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

Welcome 组件将

Hello, Sara

元素作为结果返回。

ReactDOM 将DOM更新为

Hello, Sara

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 (
      
    );
  }
}

ReactDOM.render(
  ,
  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 传入。

系列目录

前端大统一时代即将来临?

React项目实战:环境搭建

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

React项目实战:登录页面(编辑中)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/54432.html

相关文章

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

    摘要:组件将元素作为结果返回。是把数据从项目传到的有效载荷。有以下职责维持应用的提供方法获取提供方法更新通过注册监听器通过返回的函数注销监听器。系列目录前端大统一时代即将来临项目实战环境搭建项目实战基本原理项目实战登录页面编辑中 React相关 React 是一个采用声明式,高效而且灵活的用来构建用户界面的框架。 JSX 本质上来讲,JSX 只是为React.createElement(co...

    Doyle 评论0 收藏0
  • React项目实战:环境搭建

    摘要:官方文档中文翻译构建用户界面的库。官方文档建议学习时以官方文档为准,中文翻译或者第三方作者的教程可以帮助你理清思路会用到的重要知识点我也会进行简明的解释,如遇到错误或者不理解的内容,欢迎实时指出。 前言 前面提到前端大统一的概念,如果感兴趣,欢迎说说自己的看法,点击前往。Web前端框架层出不穷,不可能面面俱到,这里给个小建议: 如果对Weex App感兴趣,应该选择vue框架; 如果...

    cnio 评论0 收藏0
  • React项目实战:环境搭建

    摘要:官方文档中文翻译构建用户界面的库。官方文档建议学习时以官方文档为准,中文翻译或者第三方作者的教程可以帮助你理清思路会用到的重要知识点我也会进行简明的解释,如遇到错误或者不理解的内容,欢迎实时指出。 前言 前面提到前端大统一的概念,如果感兴趣,欢迎说说自己的看法,点击前往。Web前端框架层出不穷,不可能面面俱到,这里给个小建议: 如果对Weex App感兴趣,应该选择vue框架; 如果...

    GHOST_349178 评论0 收藏0
  • react-redux-router4-webpack2组成的大众点评的demo.

    该demo使用的是webpack2.*来配置的,很多配置项都产生了变化,踩了不少坑.目前还在逐步完善中,webpack是一部一部配置来的。后端数据使用nodejs来开发模拟。GitHub项目地址。 showImg(https://segmentfault.com/img/remote/1460000009665620); 欢迎大家提问题。

    Caizhenhao 评论0 收藏0
  • 基于Dva.js的Blog SPA实践

    摘要:项目地址项目预览登录流负责全局的登录状态管理。总体思想所有的组件都尽量是所有的状态组件一般都是路由组件。所有的分发都交给了路由组件来完成。数据的获取有两种方式。一种是官方推荐的使用在订阅数据源。 项目地址 https://github.com/HeskeyBaoz... 项目预览 showImg(https://segmentfault.com/img/bVIQHX?w=1249&h=...

    vslam 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<