React项目实战:react-redux-router基本原理
React相关
React 是一个采用声明式,高效而且灵活的用来构建用户界面的框架。
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 传入。
系列目录
- 前端大统一时代即将来临?
- React项目实战:环境搭建
- React项目实战:react-redux-router基本原理
- React项目实战:登录页面(编辑中)
React项目实战:react-redux-router基本原理的更多相关文章
- 如何在非 React 项目中使用 Redux
本文作者:胡子大哈 原文链接:https://scriptoj.com/topic/178/如何在非-react-项目中使用-redux 转载请注明出处,保留原文链接和作者信息. 目录 1.前言 2. ...
- 如何优雅地在React项目中使用Redux
前言 或许你当前的项目还没有到应用Redux的程度,但提前了解一下也没有坏处,本文不会安利大家使用Redux 概念 首先我们会用到哪些框架和工具呢? React UI框架 Redux 状态管理工具,与 ...
- 优雅的在React项目中使用Redux
概念 首先我们会用到哪些框架和工具呢? React UI框架 Redux 状态管理工具,与React没有任何关系,其他UI框架也可以使用Redux react-redux React插件,作用:方便在 ...
- 七天接手react项目 系列 —— react 脚手架创建项目
其他章节请看: 七天接手react项目 系列 react 脚手架创建项目 前面我们一直通过 script 的方式学习 react 基础知识,而真实项目通常是基于脚手架进行开发. 本篇首先通过 reac ...
- 七天接手react项目 系列 —— react 路由
其他章节请看: 七天接手react项目 系列 react 路由 本篇首先讲解路由原理,接着以一个基础路由示例为起点讲述路由最基础的知识,然后讲解嵌套路由.路由传参,最后讲解路由组件和一般组件的区别,以 ...
- react全家桶从0搭建一个完整的react项目(react-router4、redux、redux-saga)
react全家桶从0到1(最新) 本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目.文中针对react.webpack.babel.react-route.redux.redu ...
- 《Node+MongoDB+React 项目实战开发》已出版
前言 从深圳回长沙已经快4个月了,除了把车开熟练了外,并没有什么值得一提的,长沙这边要么就是连续下一个月雨,要么就是连续一个月高温暴晒,上班更是没啥子意思,长沙这边的公司和深圳落差挺大的,薪资也是断崖 ...
- 在react项目当中使用redux
如果需要在你的react项目当中使用状态管理模式的话,需要引入redux和react-redux两个插件,redux提供基本的功能,react-redux提供将redux注入react的方法. imp ...
- asp.net core react 项目实战(一)
asp.net-core-react asp.net core react 简介 开发依赖环境 .NET Core SDK (reflecting any global.json): Version: ...
随机推荐
- 吴裕雄--天生自然C语言开发:数组
] = {1000.0, 2.0, 3.4, 7.0, 50.0}; ]; #include <stdio.h> int main () { ]; /* n 是一个包含 10 个整数的数组 ...
- 系统学习javaweb补充1----HTML常用语句
HTML 常用语句 一.单行文本框语法格式 <input type="text" name="输入信息的名字" value="输入信息的值&qu ...
- 部署企业本地yum源及源码包安装
YUM命令 yum list //列出每个软件包(包括未安装和已安装) rpm -q repolist //列出所以仓库名称 info //查看软件信息 rpm -qi install //安装 rp ...
- 网页元素检测工具:Spy_for_InternetExplorer下载地址
本工具用于实时查看IE浏览器中打开的网页中元素的信息.支持iframe.frame框架. 下载地址: Spy_for_InternetExplorer.rar
- 网站爬取-案例四:知乎抓取(COOKIE登录抓取个人中心)(第二卷)
接着上卷来分析,作为开发人员我们都知道,登录是一个想指定URL发送POST请求的过程,所以我们需要找到请求的URL,以及字段,先用一个错误账号和密码做一下尝试,如果是正确的话会直接跳转到别的页面,这样 ...
- 蓝桥杯-PREV45-图形排版
这是2017年蓝桥杯C组C++的压轴题,拿到之后没什么想法.但是蓝桥杯有部分分.所以直接敲了个大暴力提交上去过了一半的数据.后来想到了DP,但是没能实现出来,感觉还是有问题的.后来看了解题视频发现是预 ...
- Mr.Yu
在linux下搭建Git服务器 git服务器环境 服务器 CentOS7 + git(version 1.8.3.1)客户端 Windows10 + git(version 2.16.0.window ...
- VM Storage Policies深度解析
- [LC] 91. Decode Ways
A message containing letters from A-Z is being encoded to numbers using the following mapping: 'A' - ...
- [LC] 300. Longest Increasing Subsequence
Given an unsorted array of integers, find the length of longest increasing subsequence. Example: Inp ...