刚开始用redux 感觉它有点笨笨的;

因为重复代码非常多啊;

以官方例子说吧:(并不是说官网例子不好,对刚起步用它的人来说,封装太多反而难以理解)

1.对于store中的一个值的改变需要写两个方法也是有点啰嗦;

2.算上action中的type 和 和reducer中的switch,加起来每写一个action都要写3,4次相同或者类似的名字也是很烦的;

3.每次更新状态都要 dispatch(action(xxx))或者手动封装...

然后自己动手撸了一点小方法,改善了一下

这个实践最后在组件中的使用如下:

假设有一个store模块结构如下:

 {  songSheet: {name: "推荐歌单", list: [], active: false, isFetching: false,...},  ...placeConf:{personal: {name: "私人FM", show: false,...},...}
}复制代码

然后再reducer的分支处理函数中如下设置:

setPlaceConfPersonalVis(state, action){return copy(state,{placeConf:{personal:{show: state.data}}
})}复制代码

然后mapDispatchToProps方法中这么写 :

const mapDispatchToProps = dispatch => {const $actions = makeActions(dispatch);$action.setPlaceConfPersonalVis(true);  return {...actions ,// ...  其他方法}
}复制代码

是的,简化后使用就是这么简单。

然后如下是各文件代码:

reducers/index.js // 合并 各reducer模块

import { combineReducers } from 'redux';
import cmusichome from './cmusichome';
export default combineReducers({cmusichome,// 这里可以放其他模块的 reducer
});复制代码

reducers/cmusichome.js // 被 reducers/index.js引用 // 核心之一, 将reducer的分支方法拆分出去;

// 这个是分支处理函数
import cmusichomeFn from "./cmusichomeFn.js";
// 这里是reducer // 生成并更新store 的入口函数
const cmusichome = (state, action) => {// 初始化时, 没有state 所以可以在这里设置 初始值state || (state= {songSheet: {name: "推荐歌单", list: [], active: false, isFetching: false,},songList: {name: "最新音乐", list: [], active: false, isFetching: false,},djprogramList: {name: "主播电台", list: [], active: false, isFetching: false,},playList:{name: "歌曲列表", list: [], show: false, isFetching: false,},recmendList:{show: false, list:[]},placeConf:{personal: {name: "私人FM", show: false},recmend: {name: "每日推荐", show: false},songList: {name: "歌单", show: false},rankingList: {name: "排行榜", show: false},}});const curFn = cmusichomeFn[action.type];// 根据action 查找分支函数return curFn && curFn(state, action) || state;// 没找到处理函数 则返回上一次的 state
};
export default cmusichome;复制代码

reducers/cmusichomeFn.js,// 节选,可以自己添加一些处理分支 被cmusichome.js引用

import tools from "../components/tools.js";
const {copy} = tools;
export default {// 歌单updateSongSheet(state, action) {return copy(state, {songSheet: {list: action.data,}});},toggleSongSheetState(state, action){return copy(state, {songSheet: {active: !state.songSheet.active,}});},fetchSongSheet(state,action){return copy(state, {songSheet: {isFetching: action.data,}});},
};复制代码

actions/index.js // 被views/Discover.js容器组件引用 // 核心之一,根据reducerFn的键名,创建同名action方法;

// 所有在 reducer 中使用的分支函数;
import cmusichomeFns from "../reducers/cmusichomeFn";
// ...这里可以继续引入其他模块的分值函数// 根据reducer 分支函数名, 创建对应的 action 函数
// 这些action函数会接受一个值, 然后生成 返回{type: action名, data: 参数值}的方法;
function  makeReducerFnsIntoActions(reducerFns){const actions = {};Object.keys(reducerFns).forEach(item => actions[item] = data => ({type: item, data}));return actions;
};
// 组合所有actions 作为 makeActions 内部需要转化的actions
const actions = {...makeReducerFnsIntoActions(cmusichomeFns),// ...这里可以继续添加 分支函数
};
// 导出将 dispatch(action(val)) 转化为 xxx.action(val) 模式的函数;
// 可以在外界用 ...xxx 解构成 action(val); 接受 dispatch 作为参数;
// 然后在 mapDispatchToProps 方法中 return { ...makeActions(dispatch), ... }
// 就可以在 子组件中使用xxx.action(val) 真是极方便的;
export default function makeActions(dispatch){function _(str,val){dispatch(actions[str](val));};const actionFn = {};Object.keys(actions).forEach(item=> actionFn[item] = val => _(item,val));return actionFn;
}复制代码

App.js // 含react-router / react-redux

import React from 'react';
import logo from '../images/logo.svg';
import './App.css';
import {HashRouter,Route} from 'react-router-dom';
import Discover from './Discover.js';
const App = () => (<HashRouter basename="/"><div className="App"><img src={logo} className="App-logo" alt="logo" /><audio src="" id="audio"></audio><Route path="/discover" component={Discover}/></div></HashRouter>
);
export default App;复制代码

views/Discover.js // 容器组件 // 被App.js 引用

import makeActions from '../actions';
import $http from "./../http/http.js";
import React, from 'react';
import { connect } from 'react-redux';
import Home from "./Home/Home.js";
const mapStateToProps = state => ({...state.cmusichome});
const mapDispatchToProps = dispatch => {const $actions = makeActions(dispatch);$http.personalized()(res => {$actions.updateSongSheet(res.result.map(item => ({name: item.name, img: item.picUrl, id: item.id,})))});return{...$actions,// 貌似到子组件 const {$action} = props;会好一些getPlayList: function (id) {$actions.fetchPlayList(true);$http.playlistDetail({id})(res=>{$actions.updatePlayList(res.playlist.tracks);$actions.togglePlayList(true);$actions.fetchPlayList(true);});},playASong(id){$http.songUrl({id})(res=>{const audio = document.querySelector("#audio");audio.src = res.data[0].url;audio.play();})},}};
export default connect(mapStateToProps, mapDispatchToProps)(Home);复制代码

copy.js // 被 reducers/cmusichomeFn.js 引用 // 核心之一 // 深拷贝数组外的属性 // 对于数组的操作是: 通过数组map返回新数组替换之前的数组,并不会直接引用传入的数组或者原store中的值(为什么这么做我也不知道);

import type from "./type.js";
function _copy() {if(arguments.length) {const list = Array.prototype.map.call(arguments, item => item);const curObj = list.shift();Object.keys(curObj).forEach(item=>{const val = curObj[item];if(val !== undefined)this[item] = (type.isObject(val) && copy(this[item]||{},val)) ||(type.isArray(val) && val.map(item => item)) ||val;});return _copy.apply(this, list);} else return this;
}
function copy(){return _copy.apply({},arguments);}
export default copy;复制代码

type.js // 被 copy.js 引用

const getType = item => (Object.prototype.toString.call(item).slice(8, -1));getType.isNumber = item => getType(item) === 'Number';
getType.isString = item => getType(item) === 'String';
getType.isArray = item => getType(item) === 'Array';
getType.isObject = item => getType(item) === 'Object';
getType.isBoolean = item => getType(item) === 'Boolean';
getType.isNull = item => getType(item) === 'Null';
getType.isUndefined = item => getType(item) === 'Undefined';
getType.isFunction = item => getType(item) === 'Function';
getType.isDate = item => getType(item) === 'Date';
export default getType;复制代码

demo 请移架 https://github.com/DeyaoCai/cmusic

转载于:https://juejin.im/post/5be3124951882516d1553181

Redux 一个还好的redux 实践吧相关推荐

  1. Redux的全家桶与最佳实践

    2019独角兽企业重金招聘Python工程师标准>>> image.png Redux 的第一次代码提交是在 2015 年 5 月底(也就是一年多前的样子),那个时候 React 的 ...

  2. 还在用 Redux,要不要试试 GraphQL 和 Apollo?

    还在用 Redux,要不要试试 GraphQL & Apollo? 前段时间刷 Twitter 的时候看到大 V 纷纷提到 Apollo,预测它将在 2018 年崛起.正巧碰上有使用 Grap ...

  3. Redux入门之实现一个迷你版的Redux

    Redux是一种数据架构模式,它可以用来管理应用的状态. 之前一直在做Angular的项目,没有使用到过Redux,对于Redux的使用场景和原理都不是很清楚,看资料时作者自己实现了一个Redux,在 ...

  4. 一个完整小巧的Redux全家桶项目

    OneArticle: 使用React-Native开发,使用Redux,React-Redux,Redux-Persist,Redux-Saga. 为什么取这个名字呢,我也不想啊,App为OneAr ...

  5. 初学redux笔记,及一个最简单的redux实例

    categories: 笔记 tags: react redux 前端框架 把初学redux的一些笔记写了下来 分享一个入学redux很合适的demo, 用redux实现计数器 这是从阮一峰老师git ...

  6. Redux入门0x101: 简介及`redux`简单实现

    0x000 概述 这一章开始讲redux,其实是承接前面的react,但其实作为一个框架来说,redux和react并没有太多的关系,本身是独立存在的.在我看来它们的关系不会比共用re开头更深了,所以 ...

  7. [Redux/Mobx] 什么是redux?说说你对redux的理解?有哪些运用场景?

    [Redux/Mobx] 什么是redux?说说你对redux的理解?有哪些运用场景? Redux是一个数据管理的库,它除了将数据存储在单一数据源中之外,还确定了变更数据.读取数据的方式,以此来明确了 ...

  8. Redux学习(一)——Redux的使用过程

    一.为什么需要redux JavaScript开发的应用程序,已经变得越来越复杂了: JavaScript需要管理的状态越来越多,越来越复杂: 这些状态包括服务器返回的数据.缓存数据.用户操作产生的数 ...

  9. Redux相关知识(什么是redux、redux的工作原理、redux的核心概念、redux的基本使用)(十一)

    系列文章目录 第一章:React基础知识(React基本使用.JSX语法.React模块化与组件化)(一) 第二章:React基础知识(组件实例三大核心属性state.props.refs)(二) 第 ...

最新文章

  1. SQLite中的SELECT子句
  2. css 浮动在最上层_CSS的“层”峦“叠”翠
  3. lua 调用文件中的函数调用_深入Lua:调用相关的指令
  4. Java基础05 break和continue比较区别
  5. 蓝桥杯2018年第九届C/C++省赛B组第二题-明码
  6. java项目高新_java高新技术
  7. Spring Cloud Hystrix - 服务容错
  8. 计算机flash教案,flash教学计划
  9. java docx4j 使用教程_docx4j深入学习整理
  10. 网站优化后如何降低阿里云国际版服务器成本
  11. win10系统安装+激活+去水印
  12. 热血江湖网通一服务器不稳定,《热血江湖》网通新服 千呼万唤始出来
  13. 陶哲轩1(数学牛孩的成长研究
  14. SpringBoot项目遇到AopAutoConfiguration matched: - @ConditionalOnProperty (spring.aop.auto=true)错误
  15. 【机器学习】琴生不等式(Jensen's inequality)
  16. 题目:输入一个8bit数,输出其中1的个数。如果只能使用1bit全加 器,最少需要几个?
  17. 如何在AD19的PCB库编辑界面修改尺寸单位
  18. 华为公司 代码编码规范
  19. 灰度图腐蚀膨胀原理介绍的很清晰。
  20. Camera sensor 基本知识

热门文章

  1. 二叉平衡树算法c语言,算法9-9~9-12:平衡二叉树的基本操作 (C语言代码)
  2. php di,PHP-DI中文文档(基于有道翻译,基本是直接拿过来使用,并没有润色)
  3. idea 运行jmeter源码_学会BeanShell,才敢说自己懂Jmeter
  4. 计算机应用基础2010一级,2010年一级结构基础辅导:(计算机应用基础)备考讲义(10)...
  5. python函数的使用场景_Python——异常(内置异常以及应用场景)
  6. linux中anconda python集成环境配置
  7. 图像降噪算法——DnCNN / FFDNet / CBDNet / RIDNet / PMRID / SID
  8. 【GAN优化】一览IPM框架下的各种GAN
  9. 全球及中国手持式吸尘器行业供应需求及未来投资潜力预测报告2022-2027年
  10. 全球及中国婚礼鲜花行业运营模式分析及投资战略评估报告2022-2027年版