React redux之immutable+combineReducers+redux-thunk完成对数据的拆分管理

关于immutable.js:immutable.js是一个第三方模块,可以帮助我们生成一个immutable对象,这个对象不可被变更。若state是一个immutable对象,state就不可以被改变,这样reducer就不会出问题。因此,我们就需要把state变成immutable对象。

immutable安装指令:npm i immutable --save      ·

关于combineReducers:reducer如果存放过多的数据可能会造成代码的不可维护。那么,combineReducers帮我们把一个reducer拆成很多个子reducer,最终再做一个整合。

关于redux-thunk:Redux-thunk是redux的一个中间件,它使得我们可以在action里面写函数。中间件是指action和store之间,是对dispatch的升级。本案例使用redux-thunk发送ajax数据请求,获取数据后存到store中,在页面进行显示。

redux-thunk安装指令:npm i redux-thunk --save

1.1 在以下案例中,在header > store > actionCreators中,因为用了redux-thunk,函数返回函数,这也是thunk的意义。

//header > store > actionCreators
import { search_focus, search_blur, change_list } from "./actionTypes";
import { fromJS } from 'immutable';
import axios from "axios"

export const getFocusAction = () => ({
  type: search_focus
})

export const getBlurAction = () => ({
  type: search_blur
})

//因为reducer中的list在最外层包裹了fromJS,最初list数组就已经被变成了immutable类型的数组
//因此要在这里做统一
const changeListAction = (data) => ({
  type: change_list,
  data: fromJS(data)
})

//因为用了redux-thunk,函数返回函数,这也是thunk的意义
export const getList = () => {
  return (dispatch) => {
    //请求假数据 来自public > api > headerList.json
    axios.get('/api/headerList.json').then((res) => {
      const data = res.data;
      const action = changeListAction(data.data)//将list中的内容传给此函数
      dispatch(action)
    }).catch(() => {
      console.log("error");
    })
  }
}

1.2 把跟header相关的数据和操作放到了header > store > reducer.js中,存放的是header组件相关的默认数据和对数据的操作。

import { search_focus, search_blur, change_list } from "./actionTypes";
import { fromJS } from 'immutable'

const defaultState = fromJS({
  focused: false,
  list: []
});

export default (state = defaultState, action) => {
  switch (action.type) {
    case search_focus:
      return state.set('focused', true);
    case search_blur:
      return state.set('focused', false);
    case change_list:
      return state.set('list', action.data);
    default:
      return state
  }
}

2. 然后,在src > store > reducer.js中拿到header > store > reducer.js中的headerReducer,整合出一个大的reducer这样,我们就把reducer里的内容拆成一小个一小个管理了。因为在src > store > index.js中创建了store,也应该在这里使用thunk。

// src > store > index.js 
import { createStore, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(
  applyMiddleware(thunk)
))

export default store;

// src > store > reducer.js 
import { combineReducers } from 'redux-immutable'
import headerReducer from '../common/header/store/reducer'

const reducer = combineReducers({
  header: headerReducer
})

export default reducer;

3. header组件中因为combineReducers, “state.方法”要改为“state.header.方法”: src > common > header > index.js

import React, { Component } from "react";
import { connect } from 'react-redux';
import { CSSTransition } from "react-transition-group";
import { HeaderWrapper, Logo, Nav, NavItem, NavSearch, Addition, Button, SearchWrapper, SearchInfo, SearchInfoTitle, SearchInfoSwitch, SearchInfoItem, SearchInfoList } from "./style";
import { getFocusAction, getBlurAction, getList } from './store/actionCreators'

class Header extends Component {
  getListArea(show) {
    const { focused, list } = this.props
    if (focused) {
      return (
        <SearchInfo>
          <SearchInfoTitle>
            热门搜索
            <SearchInfoSwitch>换一批</SearchInfoSwitch>
          </SearchInfoTitle>
          <SearchInfoList>
            {
              list.map((item) => {
                return <SearchInfoItem key={item}>{item}</SearchInfoItem>
              })
            }
          </SearchInfoList>
        </SearchInfo>
      )
    } else {
      return null;//什么都不返回
    }
  }
  render() {
    const { focused, handleInputFocus, handleInputBlur, list } = this.props
    return (
      <HeaderWrapper>
        <Logo />
        <Nav>
          <NavItem className="left active">首页</NavItem>
          <NavItem className="left">下载App</NavItem>
          <NavItem className="right">登录</NavItem>
          <NavItem className="right">
            <i className="iconfont">&#xe636;</i>
          </NavItem>
          <SearchWrapper>
            <CSSTransition
              in={focused}
              timeout={200}
              classNames="slide">
              <NavSearch
                className={focused && 'focused'}
                onFocus={() => handleInputFocus(list)}
                onBlur={handleInputBlur}></NavSearch>
            </CSSTransition>
            <i className={focused ? 'i_focused iconfont' : 'iconfont'}>&#xe617;</i>
            {this.getListArea()}
          </SearchWrapper>
        </Nav>
        <Addition>
          <Button className="writing">
            <i className="iconfont">&#xe652;</i>
            写文章</Button>
          <Button className="reg">注册</Button>
        </Addition>
      </HeaderWrapper>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    //focused: state.focused 没用immutable时
    focused: state.getIn(['header', 'focused']),//也可写为 state.get('header').get('focused')
    list: state.getIn(['header', 'list'])
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    handleInputFocus(list) {
      //改变focused数据的值变为true 作用是控制search框的显示和input框的长短
      dispatch(getFocusAction());
      //redux-thunk使得我们可以去action里做异步操作 
      //注意,当list.size等于0,也就是没数据时,才请求search的数据
      (list.size === 0) && dispatch(getList());
    },
    handleInputBlur() {
      dispatch(getBlurAction());
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Header);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值