摘要:因为最近搞懂了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. DataGridView 绑定List集合后实现自定义排序

    这里只贴主要代码,dataList是已添加数据的全局变量,绑定数据源 datagridview1.DataSource = dataList,以下是核心代码. 实现点击列表头实现自定义排序 priva ...

  2. ubuntu-16.4TLS安装QQ

    01下载Winqq 下载地址:http://www.ubuntukylin.com/application/show.php?lang=cn&id=27902解压zip unzip wine- ...

  3. 74 partprobe-磁盘管理

    partprobe命令用于重读分区表,当出现删除文件后,出现仍然占用空间.可以partprobe在不重启的情况下重读分区. 语法 partprobe (选项) (参数) 选项 -d:不更新内核: -s ...

  4. Linq的TakeWhile误用

    where(func<>)返回符合条件的元素 与此相对的skipwhile跳过符合条件的,返回剩下的元素 容易误用的takewhile,与where 不一样,只有当所有元素满足条件时,才返 ...

  5. MySQL删除/更新数据时报1175错误

    今天删除MySQL数据库中的一条记录的时候,一直不能删除,提示错误信息如下: Error Code: 1175. You are using safe update mode and you trie ...

  6. 【POJ 3294】Life Forms 不小于k个字符串中的最长子串

    一下午和一晚上都在刚这道题,各种错误都集齐了so sad 我的时间啊!!! 后缀数组就先做到这里吧,是在伤不起啊QAQ 出现了各种奇怪的错误,看了标算,然后乱改自己的代码,莫名其妙的改A了,后来发现用 ...

  7. DOS常用命令收集(长期更新)

    命令列表 命令 说明 ASSOC 显示或修改文件扩展名关联. ATTRIB 显示或更改文件属性. BREAK 设置或清除扩展式 CTRL+C 检查. BCDEDIT 设置启动数据库中的属性以控制启动加 ...

  8. python面试题目

    问题一:以下的代码的输出将是什么? 说出你的答案并解释. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Parent(object):     x = 1   clas ...

  9. java.sql.SQLException: 无效的列索引

    java.sql.SQLException: 无效的列索引 "无效的列索引"其实是个低级的错误,原因无非几个: 1.sql串的?号数目和提供的变量数目不一致: 例如:jdbcTem ...

  10. the useful for loop

    cp four_letter four_letter_bk for i in `ls /media/10TB/Stats/Assembly_marker` do cd /media/10TB/Stat ...