react+redux教程(八)连接数据库的redux程序
前面所有的教程都是解读官方的示例代码,是时候我们自己写个连接数据库的redux程序了!
例子
这个例子代码,是我自己写的程序,一个非常简单的todo,但是包含了redux插件的用法,中间件的用法,连接数据库的方法等多个知识点。
源代码:
https://github.com/lewis617/react-redux-tutorial/tree/master/redux-wilddog-todos
运行方法:
npm install
npm run build
手动打开index.html
wilddog数据库
作为一名曾经的angular开发者,我非常喜欢用firebase来做自己的数据库,并结合angular实现酷炫的“三向数据绑定”。wilddog是中国的“firebase”,不仅语法兼容,而且国内速度更快。
下面的程序都是基于wilddog和angular的程序,也用了我曾经的最爱requirejs,有兴趣的同学可以看看,顺便赏我点star哈哈!
https://github.com/lewis617/wild-angular-seed
https://github.com/lewis617/daily-task
如今写react程序,仍然可以使用wilddog或者firebase,不仅不用配置数据库服务,也不用写数据库增删改查的api程序了,可以让我们前端工程师专注于写前端程序!
redux的chrome插件
本程序也用到了redux的chrome插件,可以帮助我们自动生成redux的devtool界面,非常好用啊!只需要在你的程序store注册中,加入一行代码:
- export default (initialState) => {
- const store = compose(
- applyMiddleware(
- thunk,
- createLogger()
- ),
- window.devToolsExtension ? window.devToolsExtension() : f => f
- )(createStore)(reducers, initialState);
- return store;
- };
就是这行代码:
- window.devToolsExtension ? window.devToolsExtension() : f => f
安装方法,就是去chrome的市场搜索redux关键字就可以了!
没有服务端渲染和热替换
为什么要把这个单独提起来说呢?这是一个历史遗留问题。我们研究所用的web框架是flask,一个python框架,包括前端也是用flask的jinja模板。没有nodejs也就意味着无法使用服务端渲染和热替换这两个炫酷的功能。
那么不是基于nodejs的前端程序,还能否使用redux和react呢?当然可以,我只通过webpack生成一个js文件,将js文件放进html里面。其他所有的功能都不要。这也是可以的。这也算是结合非node平台的一个实践经验吧!当然你的包管理还得用npm。
从另一个方面来说,基于nodejs的前端时代已经来临,如果你拒绝它,将会失去很多,或者寸步难行!
获取所有的todos
我们在action中进行http请求和服务端交互,即便是在中间件中执行http请求,其实质也是dispatch的封装。那么这个程序的关键就是action的编写。
实例化wilddog,定义action类型:
actions.js
- import Wilddog from 'wilddog/lib/wilddog-node'
- /*
- * action 类型
- */
- export const GET_TODO_ERROR = 'GET_TODO_ERROR';
- export const GET_TODO_OK = 'GET_TODO_OK';
- export const ADD_TODO_ERROR = 'ADD_TODO_ERROR';
- export const ADD_TODO_OK = 'ADD_TODO_OK';
- export const REMOVE_TODO_OK = 'REMOVE_TODO_OK';
- export const REMOVE_TODO_ERROR = 'REMOVE_TODO_ERROR';
- let wilddog=new Wilddog('https://redux-wilddog-todos.wilddogio.com')
从wilddog数据库中获取所有的todos,因为wilddog数据库是树状结构,生成的列表,其实质也是个对象,所以我们需要将其转化为数组:
- export function getTodo() {
- return (dispatch,getState)=>{
- wilddog.child('todos').once('value',(snapshot)=>{
- let obj=snapshot.val();
- let array=[];
- for(let key in obj){
- array.push({key:key,text:obj[key].text})
- }
- dispatch({
- type: GET_TODO_OK,
- payload: array
- })
- },(err)=>{
- dispatch({
- type: GET_TODO_ERROR,
- payload: err
- })
- });
- }
- }
wilddog.child('todos').once('value',function)是获取‘todos’节点数据的方法。获取到数据后,转化为数组。然后dispatch一个GET_TODO_OK,告诉reducer获取数据成功,可以更新state了。数据都装在payload中。如果失败,则dispatch一GET_TODO_ERROR。
就是这么简单,不用写后台程序,在js中直接操作数据库!
那么在哪里执行这个getTodo呢?你可以在组件渲染后dispatch它,也可以在初始化store后,立即执行它。我用的是后面一种:
index.js
- import { getTodo,registerListeners} from './actions'
- let store = createStore();
- store.dispatch(getTodo())
添加新的todo
在action中定义添加todo的方法:
actions.js
- export function addTodo(text) {
- return (dispatch,getState)=>{
- wilddog.child('todos').push({
- text
- },(err)=>{
- if(err){dispatch({type:ADD_TODO_ERROR,payload:err})}
- });
- }
- }
通过wilddog.child('todos').push()方法,直接往数据库中插入数据,第二参数是回调,失败的话,dispatch相应的action。
那么成功后的action在哪执行?我们需要再写一个function,绑定数据变动的回调。其实正常情况下,我们在这个function中就直接写成功后的回调了,主要是因为wilddog数据库的成功回调不在push这个方法中。
actions.js
- export function registerListeners() {
- return (dispatch, getState) => {
- wilddog.child('todos').on('child_removed', snapshot => {
- dispatch({
- type: REMOVE_TODO_OK,
- payload: snapshot.key()
- })
- });
- wilddog.child('todos').on('child_added', snapshot => dispatch({
- type: ADD_TODO_OK,
- payload: Object.assign({},snapshot.val(),{key:snapshot.key()})
- }));
- };
- }
wilddog.child('todos').on('child_added') 这个方法定义了添加todo成功后的回调,我们执行了一个ADD_TODO_OK 的action,并把新的todo对象放在payload中返回给reducer。
你也看到了,我们顺便把移除todo成功的回调也定义了。
我们在哪执行这个绑定函数呢?就在获取所有todos的后面吧!其实放在组件渲染完也可以!
index.js
- store.dispatch(registerListeners())
移除指定todo
在action中添加移除todo的方法:
actions.js
- export function removeTodo(key) {
- return (dispatch,getState)=>{
- wilddog.child(`todos/${key}`).remove((err)=>{
- if(err)dispatch({type:REMOVE_TODO_ERROR,payload:err})
- });
- }
- }
通过wilddog的remove方法移除数据库的指定节点。就是这么简单!然后编写失败后的回调以及action!
数据库在action中完事,state还需要reducer
数据库我们是操作完啦,不过组件的显示是基于state的,我们还要同步更新state,那么reducer就出场了!
reducers.js
- import { combineReducers } from 'redux'
- import { ADD_TODO_OK, REMOVE_TODO_OK ,GET_TODO_OK} from './actions'
- function todos(state=[], action) {
- switch (action.type) {
- case GET_TODO_OK:
- return action.payload
- case ADD_TODO_OK:
- return [
- ...state,
- action.payload
- ]
- case REMOVE_TODO_OK:
- return state.filter((todo)=>todo.key!==action.payload
- )
- default:
- return state
- }
- }
- const todoApp = combineReducers({
- todos
- })
- export default todoApp
很简单,如果你还不会,可以去前面几节教程补课。
来个图吧:
action操作数据库后,要在回调中返回信号,让reducer更新state,因为只有state变了,组件才会变。state变了,组件自动就变了,至少不用苦逼地操作dom了,还是挺开心的!
为什么不提react组件
说了这么多我们的redux容器算是搞定了,为什么不提组件?不是不提,是要让大家知道,组件和redux容器的耦合度很低,我们可以完全将它们隔离开来编写,通过一些固定的套路将它们连接起来。什么套路?
- 绑定state到props
- 绑定action到props(可选)
- 将store注入,并用provider在顶层包住组件
redux是个状态容器,只能通过发起action改变state,这种集中管控的做法让状态管理和预测变的简单。组件只是state的展现形式而已!react只是一个界面库而已!
教程源代码及目录
如果您觉得本博客教程帮到了您,就赏颗星吧!
https://github.com/lewis617/react-redux-tutorial
react+redux教程(八)连接数据库的redux程序的更多相关文章
- react+redux教程(二)redux的单一状态树完全替代了react的状态机?
上篇react+redux教程,我们讲解了官方计数器的代码实现,react+redux教程(一).我们发现我们没有用到react组件本身的state,而是通过props来导入数据和操作的. 我们知道r ...
- react+redux教程(六)redux服务端渲染流程
今天,我们要讲解的是react+redux服务端渲染.个人认为,react击败angular的真正“杀手锏”就是服务端渲染.我们为什么要实现服务端渲染,主要是为了SEO. 例子 例子仍然是官方的计数器 ...
- react+redux教程(五)异步、单一state树结构、componentWillReceiveProps
今天,我们要讲解的是异步.单一state树结构.componentWillReceiveProps这三个知识点. 例子 这个例子是官方的例子,主要是从Reddit中请求新闻列表来显示,可以切换reac ...
- react+redux教程(四)undo、devtools、router
上节课,我们介绍了一些es6的新语法:react+redux教程(三)reduce().filter().map().some().every()....展开属性 今天我们通过解读redux-undo ...
- react+redux教程(七)自定义redux中间件
今天,我们要讲解的是自定义redux中间件这个知识点.本节内容非常抽象,特别是中间件的定义原理,那多层的函数嵌套和串联,需要极强逻辑思维能力才能完全消化吸收.不过我会多罗嗦几句,所以不用担心. 例子 ...
- 【前端,干货】react and redux教程学习实践(二)。
前言 这篇博文接 [前端]react and redux教程学习实践,浅显易懂的实践学习方法. ,上一篇简略的做了一个redux的初级demo,今天深入的学习了一些新的.有用的,可以在生产项目中使用的 ...
- Redux教程1:环境搭建,初写Redux
如果将React比喻成士兵的话,你的程序还需要一位将军,去管理士兵(的状态),而Redux恰好是一位好将军,简单高效: 相比起React的学习曲线,Redux的稍微平坦一些:本系列教程,将以" ...
- Redux教程3:添加倒计时
前面的教程里面,我们搭建了一个简单红绿灯示例,通过在console输出当面的倒计时时间:由于界面上不能显示倒计时,用户体验并不良好,本节我们就添加一个简单的倒计时改善一下. 作为本系列的最后一篇文章, ...
- React 系列教程 1:实现 Animate.css 官网效果
前言 这是 React 系列教程的第一篇,我们将用 React 实现 Animate.css 官网的效果.对于 Animate.css 官网效果是一个非常简单的例子,原代码使用 jQuery 编写,就 ...
随机推荐
- C#高性能TCP服务的多种实现方式
哎~~ 想想大部分园友应该对 "高性能" 字样更感兴趣,为了吸引眼球所以标题中一定要突出,其实我更喜欢的标题是<猴赛雷,C#编写TCP服务的花样姿势!>. 本篇文章的主 ...
- 让姑姑不再划拳 码农也要有原则 : SOLID via C#
“姑娘,别这样.我们是有原则的.” “一个有原则的程序猿是不会写出 “摧毁地球” 这样的程序的,他们会写一个函数叫 “摧毁行星”而把地球当一个参数传进去.” “对,是时候和那些只会滚键盘的麻瓜不同了, ...
- ASP.NET Core中如影随形的”依赖注入”[下]: 历数依赖注入的N种玩法
在对ASP.NET Core管道中关于依赖注入的两个核心对象(ServiceCollection和ServiceProvider)有了足够的认识之后,我们将关注的目光转移到编程层面.在ASP.NET ...
- [C#] 进阶 - LINQ 标准查询操作概述
LINQ 标准查询操作概述 序 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> ...
- html5 canvas常用api总结(二)--绘图API
canvas可以绘制出很多奇妙的样式和美丽的效果,通过几个简单的api就可以在画布上呈现出千变万化的效果,还可以制作网页游戏,接下来就总结一下和绘图有关的API. 绘画的时候canvas相当于画布,而 ...
- C#——传值参数(2)
//我的C#是跟着猛哥(刘铁猛)(算是我的正式老师)<C#语言入门详解>学习的,微信上猛哥也给我讲解了一些不懂得地方,对于我来说简直是一笔巨额财富,难得良师! 这次与大家共同学习C#中的 ...
- java中易错点(二)
java,exe是java虚拟机 javadoc.exe用来制作java文档 jdb.exe是java的调试器 javaprof,exe是剖析工具 解析一: sleep是线程类(Thread)的方法, ...
- HTML5 Page Visibility
什么是 Page Visibility ? Page Visibility 即页面可见性,通过 visibilityState 的值检测页面当前是否可见.当一个网站是可见或点击选中的状态时 Page ...
- 初识git版本控制系统
当下git分布式版本控制系统越来越火,掌握git也是必须的一个技能.因此,对git做了如下学习. Git初级指南 1. 先安装git.(ps:在select cmponents处要勾选Git Bash ...
- Spring MVC初始化参数绑定
初始化参数绑定与类型转换很类似,初始化绑定时,主要是参数类型 ---单日期 在处理器类中配置绑定方法 使用@InitBinder注解 在这里首先注册一个用户编辑器 参数一为目标类型 proper ...