摘要:因为最近搞懂了redux的异步操作,所以觉得可以用react+redux来做一个小小的项目了,以此来加深一下印象。切记,是小小的项目,所以项目肯定是比较简单的啦,哈哈。

项目效果图如图所示:(因为一张图实现起来太长了 ,所以切成了两半,略丑,罪过!!)

项目的github地址:https://github.com/xianyulaodi/react-redux

之前写过一篇文章是redux的异步操作,本文只是将其应用到了实战当中。

用react+redux的步骤是,首先需要知道大概有哪些状态,上图中,有以下几个状态:

同步状态:排行版和规则页切换的状态

异步状态:热气球星榜和魔术帽星榜等四个tab切换的状态,查看上周的状态

是的,不要搞那么复杂,这个活动页就这几个状态的,不过这样对于入门很有好处,因为比较好理解嘛

talk is cheap,show me the code。

来看我们的 actions

actions/index.js

// 由于目前大多数浏览器原生还不支持它,建议你使用 isomorphic-fetch 库:
// 每次使用 `fetch` 前都这样调用一下
import fetch from 'isomorphic-fetch'
export const RECEIVE_POSTS = 'RECEIVE_POSTS';
export const IS_LASTWEEK = 'IS_LASTWEEK';
export const TAB_CHANGE = 'TAB_CHANGE';
export const GIFT_ID_CHOICE = 'GIFT_ID_CHOICE'; // 本案例的状态有以下几个: // 1、上周和本周的切换
// 2、点击四个tab的切换
// 3、排行版和规则页的切换 /*
上周和本周的 action
其中weekOffset有两个值,本周为0,上周为1
*/
export function weekChoice(weekOffset) {
return {
type: IS_LASTWEEK,
weekOffset
}
} /*
热气球星榜和魔术帽星榜的action,值为giftId giftId的值可为401,402
其中401是热气球,402是魔术帽
*/
export function giftIdChoice(giftId) {
return {
type: GIFT_ID_CHOICE,
giftId
}
} // 排行版和规则页切换
export function tabChange(tabId) { return {
type: TAB_CHANGE,
tabId
} } /*
获取数据成功的action,将所有的数据传回去
返回的状态为 posts
*/ function receivePosts(reddit, json) {
return {
type: RECEIVE_POSTS,
posts:json
}
} /**
请求的函数,传值从这里传
**/
function fetchPosts(weekOffset,giftId) {
return function (dispatch) {
// data.weekOffset=weekOffset; // 0 本周 1上周
// data.giftId=giftId; // 礼物id 401是热气球,402是魔术帽
return fetch(`http://api.ys.m.yy.com/api/internal/gift/rank.json?data={"platform":1,"weekOffset":${weekOffset},"giftId":${giftId},"uid":0}`)
.then(response => response.json())
.then(json =>
dispatch(receivePosts(weekOffset, json))
)
}
} //获取数据
export function fetchPostsIfNeeded(weekOffset,giftId) { return (dispatch, getState) => { return dispatch(fetchPosts(weekOffset,giftId)) }
}

  这里定义了几个action,是根据上面说的同步和异步的状态来定义的,

  定义了选择是上周还是本周的action  weekChoice,并返回一个weekOffset,这个值是要传给请求的一个参数。0为本周,1为上周

  定义了是热气球还是星球帽的action giftIdChoice,并返回giftId,这个也是传给请求的一个参数。401为热气球的,402为星球帽

  定义了排行版和规则页切换的action tabChange,并返回一个tabId, 0为排行版,1为规则页。这个页面的切换是同步的。

其他的比如是fetch的请求的action可以参考我之前写一篇文章,地址为:这里是上一篇文章地址。

action的代码不多,接下来说一说reducer的代码:

reducers/index.js

import { combineReducers } from 'redux'
import {
RECEIVE_POSTS,
IS_LASTWEEK,
GIFT_ID_CHOICE,
TAB_CHANGE
} from '../actions' function isNextWeek(state = 0, action) {
switch (action.type) {
case IS_LASTWEEK:
return action.weekOffset //这里面的值是和action里面的值对应的
default:
return state
}
} function tabIdState(state=0,action){
switch(action.type){
case TAB_CHANGE :
return action.tabId
default:
return state
}
} function giftId(state = 401, action) { switch (action.type) { case GIFT_ID_CHOICE:
return action.giftId
//这里面的值是和action里面的值对应的
default:
return state
}
} /** Object.assign是ES6的一个语法。合并对象,将对象合并为一个,前后相同的话,后者覆盖强者。详情可以看这里
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
例如:
var obj = { a: 1 };
var copy = Object.assign({}, obj,{'b':2});
console.log(copy); // { a: 1,b:2 } var obj = { a: 1 };
var copy = Object.assign({}, obj,{'a':2});
console.log(copy); // { a: 2} **/
function receiveData(state ={}, action) {
switch (action.type) {
case RECEIVE_POSTS:
return Object.assign({}, state, {
items: action.posts //请求得到的数据都存在了这里
})
default:
return state
}
} // 将所有的reducer结合为一个,传给store
const rootReducer = combineReducers({
receiveData,
isNextWeek,
giftId,
tabIdState
}) export default rootReducer

    reducre也比较简单,Action对象仅仅是描述了行为的相关信息,至于如何通过特定的行为来更新state,就需要看看Reducer了。

从上面的代码可以得知,reducer有一下几点特性,

  1、它是一个纯函数。

  2、它接收两个参数,一个是旧的状态previousState和一个Action对象。

  3、它返回一个新的状态NewState。 你可以返回任何的东西,对象、数组、字符串等等等等

  比如我的代码中,当接收到 IS_LASTWEEK状态描述,我们就返回一个新的 weekOffset  ,当接收到 RECEIVE_POSTS的状态描述,我们就返回一个对象,将数据返回到items对象里面。等等等等。反正通过reducer,当你接收到某个状态描述时,可以返回任何东西,而且state需要的话可以给一些默认值。

  其实这些拆分开来的reducer的函数名,才是供View使用的状态值。比如我reducer里的那些纯函数,其实到达VIEW这里是这样的,通过store,这样所有的状态都集中到了这里了。

通过 combineReducers,将多个reducer纯函数结合为一个。

接下来,container/app.js

import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import {fetchPostsIfNeeded,weekChoice,giftIdChoice,tabChange} from '../actions'
import * as TodoActions from '../actions' class App extends Component {
constructor(props) {
super(props)
this.weekChoiceFn = this.weekChoiceFn.bind(this)
this.giftIdChoiceFn = this.giftIdChoiceFn.bind(this)
this.tabFn = this.tabFn.bind(this)
} //初始化渲染后触发
componentDidMount() {
const { dispatch,isLastWeek,giftId} = this.props
dispatch(fetchPostsIfNeeded(isLastWeek,giftId))
} //每次接受新的props触发
componentWillReceiveProps(nextProps) { if ((nextProps.isLastWeek !== this.props.isLastWeek) || (nextProps.giftId !== this.props.giftId) ) {
const { dispatch, isLastWeek ,giftId} = nextProps
dispatch(fetchPostsIfNeeded(isLastWeek,giftId))
} } // 上周还是本周
weekChoiceFn(isLastweek) { this.props.dispatch(weekChoice(isLastweek)); } // 送出热气球星榜还是魔术帽星榜
giftIdChoiceFn(giftId) {
this.props.dispatch(giftIdChoice(giftId)); } tabFn (tabId) { this.props.dispatch(tabChange(3)); } render() {
const { receiveData } = this.props //this.props里面包含着所有的状态
return (
<div>
<a href="#" onClick={this.weekChoiceFn.bind(this,1)}>上周</a>
<br />
<a href="#" onClick={this.weekChoiceFn.bind(this,0)}>本周</a>
<br />
<a href="#" onClick={this.giftIdChoiceFn.bind(this,401)}>热气球星榜</a><br />
<a href="#" onClick={this.giftIdChoiceFn.bind(this,402)}>魔术帽星榜</a><br />
<a href="#" onClick={this.tabFn}>
tabId
</a>
<br />
这里是请求到的数据 <br />{JSON.stringify(receiveData)}<br />
</div>
)
}
} function mapStateToProps(state) {
// 这里很重要,这里需要用到的状态都要返回,不然无法实现
const { receiveData ,isLastWeek,giftId,tabIdState} = state
return {
receiveData,
isLastWeek,
giftId,
tabIdState
}
} // function mapDispatchToProps(dispatch) {
// return {
// actions: bindActionCreators(TodoActions, dispatch)
// }
// }
export default connect(
mapStateToProps
// mapDispatchToProps
)(App)

  其实注意点在这里比较多,首先,所有的状态是需要返回的。这个地方很重要。因为通过 mapStateToProps 这样顶级组件才可以拿到所有的状态。

function mapStateToProps(state) {
// 这里很重要,这里需要用到的状态都要返回,不然无法实现
const { receiveData ,isLastWeek,giftId,tabIdState} = state
return {
receiveData,
isLastWeek,
giftId,
tabIdState
}
}

  其次,要拿到状态值,可以通过this.pros这里拿,比如 const { receiveData } = this.props  ,我们就通过this.props拿到了 receiveData的状态值。

那么如何知道状态值需不需要更新你,可以通过以下方法:

 //每次接受新的props触发
componentWillReceiveProps(nextProps) { if ((nextProps.isLastWeek !== this.props.isLastWeek) || (nextProps.giftId !== this.props.giftId) ) {
const { dispatch, isLastWeek ,giftId} = nextProps
dispatch(fetchPostsIfNeeded(isLastWeek,giftId))
} }

   这里,每次接受到新的props时就会触发这个函数,里面有一个参数,nextProps,就是最近的状态值,我们可以和我们旧的状态值做对比,从而做相应的处理。比如,我们只要isLastWeek或者giftId的参数不等,我们就重新发一次请求。

  这个componentWillReceiveProps函数使比较重要的。不然你接收到新的参数也重新发送请求。所以要注意这一点。

  其他部分的东西跟我之前的redux异步操作笔记的内容有点像,这里就不再进行介绍了。界面的渲染也不做了,偷一下懒,只做了几个按钮,有需要的可以参考一下就行。本文跟之前写的文章有点小类似,就不发布到首页了。

后记:

  关于react生态的学习就暂时告一段了,因为现在所处的部门是公司的活动组,基本都是一直在搞活动,从未停止过。所以都不是很大型的项目,不过这些活动用来试水还挺好的,不好的地方就是缺乏一个大项目使用react生态的那种经验。

  接下来的学习重心可能会从react的生态链中转移开,关注一下其他的东西。八月份到九月份的学习计划是再提升一下自己的javascript水平,看两本书《精通javascript》和《css权威指南》,回归一下基础。然后十月份之后重新学习一下node.js, node.js是一个很迷茫的东西,因为如果没有项目导向,学完就很容易忘记,所以之前学过的基本都忘光了。

前端水很深啊,共勉之!!!

【原】react+redux实战的更多相关文章

  1. TypeScript + React + Redux 实战简单天气APP全套完整项目

    下载链接:https://www.yinxiangit.com/171.html 目录: 从面向过程的js到面向对象的js,让web前端更加高大尚.让你的前端步步日上,紧跟技术发展的前沿.让你构建更加 ...

  2. React+Redux开发实战项目【美团App】,没你想的那么难

    README.md 前言 开始学习React的时候,在网上找了一些文章,读了官网的一些文档,后来觉得React上手还是蛮简单的, 然后就在网上找了一个React实战的练手项目,个人学完之后觉得这个项目 ...

  3. React Redux Sever Rendering实战

    # React Redux Sever Rendering(Isomorphic JavaScript) ![React Redux Sever Rendering(Isomorphic)入门](ht ...

  4. webpack+react+redux+es6开发模式---续

    一.前言 之前介绍了webpack+react+redux+es6开发模式 ,这个项目对于一个独立的功能节点来说是没有问题的.假如伴随着源源不断的需求,前段项目会涌现出更多的功能节点,需要独立部署运行 ...

  5. react + redux 完整的项目,同时写一下个人感悟

    先附上项目源码地址和原文章地址:https://github.com/bailicangd... 做React需要会什么? react的功能其实很单一,主要负责渲染的功能,现有的框架,比如angula ...

  6. Immutable.js 以及在 react+redux 项目中的实践

    来自一位美团大牛的分享,相信可以帮助到你. 原文链接:https://juejin.im/post/5948985ea0bb9f006bed7472?utm_source=tuicool&ut ...

  7. react + redux 实现幻灯片

    写在前面: 这一篇是我 使用scss + react + webpack + es6实现幻灯片 的进阶篇,效果请点我,将会使用上redux的基础用法,因为一开始没有理解好redux的用法,单纯看文档, ...

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

    React相关 React 是一个采用声明式,高效而且灵活的用来构建用户界面的框架. JSX 本质上来讲,JSX 只是为React.createElement(component, props, .. ...

  9. webpack+react+redux+es6开发模式

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

随机推荐

  1. iOS开发小技巧--实现将图片保存到本地相册

    一.报错的代码 错误 -- out of bounds 超出界限的意思 *** Terminating app due to uncaught exception 'NSInvalidArgument ...

  2. IE6和IE7中<a>标签宽高设置无效的问题

    昨天写了一个引导界面, 发现界面中的IE67存在一个问题, 在某些情况下,  A锚链接如果设置了宽高,而且position:absolute的情况下, A标签的宽高无效, 至于总体的效果, 因为这个A ...

  3. hdu2089 数位dp

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  4. win7下安装redies

    https://github.com/MSOpenTech/redis 打开以后,可以直接使用浏览器下载,或者git克隆.注意:下载release版 解压后,目录下有以下这些文件: redis-ben ...

  5. 关于Yii2中CSS,JS文件的引入心得

    js和css的引入 use yii\helpers\Html; 1.全局引入,所有的view生效 /assets/AppAsset.php public $css = [ 'css/site.css' ...

  6. Thinking in java学习笔记之垃圾回收器如何工作

    垃圾回收器使得java在堆上分配空间的速度可以和其他语言从堆栈上分配空间的速度媲美.

  7. [日常训练]school

    Description 众所周知,家离学校很远.于是,每天算准了时间出发,以保证能在上课铃响前 秒到达学校. 不幸的是,市最近正在修路.这就导致有些路可能无法通行,因而可能导致迟到. 不打算改变他的出 ...

  8. 【BZOJ-3337】ORZJRY I 块状链表

    3337: ORZJRY I Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 190  Solved: 50[Submit][Status][Discu ...

  9. 【BZOJ-3238】差异 后缀数组 + 单调栈

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1561  Solved: 734[Submit][Status] ...

  10. jquery插件-表单提交插件-jQuery.Form

    1.介绍 JQuery Form插件是一款强大的Ajax表单提交插件,可以简单方便的实现让我们的表单 由传统的提交方式转换成Ajax无刷新提交! 他提供了两个核心的方法ajaxForm以及ajaxSu ...