zoukankan      html  css  js  c++  java
  • 在 react 项目里如何配合immutable在redux中使用

    一、reducer文件的处理

    先安装 immutable 与 redux-immutable 

    yarn add immutable redux-immutable

    我们可能会在很多地方定义子树,这就需要在大树下将它们合并,在store文件夹的 reducer.js 文件中引入

    import { combineReducers } from 'redux-immutable'
    取代原本的
    import { combineReducers } from 'redux'
    将子树合并为一个大树。
    export default combineReducers({
      homepage,
      address,
    })
    在每一个子树的 reducer.js 文件中引入 fromJS
    import { fromJS } from 'immutable'

    将子树的state 转为 immutable 类型数据

    整个 defaultState 是个Map类型,hotCity 是 List 类型

    const defaultState = fromJS({
      hotCity: [],
      areas: [],
      city: '全国',
    })

    以在城市列表页,以 redux 维护选择的城市这个状态,其所在子树的 reducer.js 文件引入 immutable

    import { fromJS } from 'immutable'
    
    import {
      GET_CITYINFO_DATA,
      CHANGE_CITY_DATA,
    } from './actionTypes'
    
    const defaultState = fromJS({
      hotCity: [],
      areas: [],
      city: '全国',
    })
    
    export default (state=defaultState,action) => {
      if(action.type === GET_CITYINFO_DATA){
        // return {
        //   ...state,
        //   hotCity: [...action.result.hotCity],
        //   areas: [...action.result.areas]
        // }
        let newList = state.setIn(['hotCity'],fromJS(action.result.hotCity))
        return newList.setIn(['areas'],fromJS(action.result.areas))
        //如果要再原来的基础上修改List数据,就要用 updataIn方法如下 插入两个 List
        // let newList = newProjectInfo.updateIn(['projectInfo'],list => list.concat(fromJS(action.result.loadMore),fromJS(action.result.loadMore)))
      }
      if(action.type === CHANGE_CITY_DATA){
        // return {
        //   ...state,
        //   city: action.city
        // }
        return state.setIn(['city'],action.city)
      }
      return state
    }

    其中注释掉的是不使用 immutable 的代码。第二个 import 引入的是 定义的 action.type 值,可以做到避免在一个大树下有相同的 type 值。其命名如下 :

    export const GET_CITYINFO_DATA = 'address/get_cityInfo_data'

    二、在城市列表页引入 store 内的数据

    先引入 connect

    import {connect} from 'react-redux'

    再定义 mapState 与 mapDispatch。

    import {CHANGE_CITY_DATA} from 'pages/address/actionTypes'
    
    const mapState = (state) => {
      return {
        hotCity: state.getIn(['address','hotCity']),
        areas: state.getIn(['address','areas']),
      }
    }
    const mapDispatch = (dispatch) => {
      return {
        loadData () {
          dispatch(loadListAsync(dispatch))
        },
        changeCity (city) {
          dispatch({
            type: CHANGE_CITY_DATA,
            city
          })
        }
      }
    }

    其中 loadData() 方法是异步的请求数据,如果要想异步的请求数据则需要引入 中间件,这里用的是 redux-thunk ,同时需要引入 redux 的 applyMiddleware ,将中间件加上

    import { createStore, applyMiddleware } from 'redux'
    import thunk from 'redux-thunk'
    
    import reducers from './reducers'
    
    const store = createStore(reducers,applyMiddleware(thunk))
    
    export default store
    
    //这是 store 文件夹下的 index.js 文件,暴露 store

    这时就可以在action时异步的请求数据,redux-thunk会检测dispatch的内容,如果是个对象就直接让其正常向后执行,如果是函数,则会在函数执行完后,再次dispatch再正常后流。

    changeCity() 方法 改变了所维护的城市状态

    loadData() 的相关代码如下:

    import {
      GET_CITYINFO_DATA,
    } from './actionTypes'
    
    export const loadCityInfoAsync = (result) => {
      return {
        type: GET_CITYINFO_DATA,
        result
      }
    }
    
    export const loadListAsync = (dispatch) => {
      return () => {
        fetch('/api/position/city')
          .then(response => response.json())
          .then(result => {
            dispatch(loadCityInfoAsync(result))
          })
      }
    }

    三、对数据的渲染

    对于 List 类型的数据,利用 map() 进行渲染

    代码如下:

    import React,{Component} from 'react'
    import {connect} from 'react-redux'
    import BScroll from 'better-scroll'
    
    import {AddressContainer} from './styledComponents'
    import {loadListAsync} from 'pages/address/actionCreator'
    import {CHANGE_CITY_DATA} from 'pages/address/actionTypes'
    
    const mapState = (state) => {
      return {
        hotCity: state.getIn(['address','hotCity']),
        areas: state.getIn(['address','areas']),
      }
    }
    const mapDispatch = (dispatch) => {
      return {
        //请求数据
        loadData () {
          dispatch(loadListAsync(dispatch))
        },
        //改变redux中所保存的城市信息
        changeCity (city) {
          dispatch({
            type: CHANGE_CITY_DATA,
            city
          })
        }
      }
    }
    
    class AddressContent extends Component {
      render(){
        // 将 this.props 内的内容解构出来
        let { hotCity, areas, changeCity, handleClick } = this.props
        //为在一页显示就没有进一步拆分,看不惯还请见谅
        return (
          // 绑定 better-scroll 的滚动根元素
          <AddressContainer className="address-com-page" ref={el => this.scrollEl = el}>
            <div>
              <div>
                <div className="address-tit">定位城市</div>
                <div className="address-hot">
                  <span>定位失败</span>
                </div>
              </div>
              <div>
                <div className="address-tit" ref="hot">热门城市/区域</div>
                <div className="address-hot">
                  {
                    // 对 hotCity 进行渲染,先判断这个数据是否存在,存在再渲染
                    // 数据是一个 List ,里面是个 Map , 里面的 cities 的值 是一个 List 类型,取得后直接进行map()
                    hotCity.get(0) && hotCity.getIn([0,'cities']).map((v,i) => {
                      return (
                        // 绑定点击事件,选取所点击的城市 changeCity()
                        // handleClick() 是路由跳转,跳回首页
                        // cities 的每个子元素都是 Map ,利用 get() 来获取值
                        <span key={ v.get('cityId') }
                        onClick={() => {
                          changeCity(v.get('name'))
                          handleClick()
                        }} >
                        { v.get('name') }</span>
                      )
                    })
                  }
                </div>
              </div>
              <div>
                {
                  // 对按字母顺序排列的城市列表进行渲染
                  areas.map((v,i) => {
                    return (
                      <div key={v.get('prefix')}>
                        {/* 将小写字母转为大写 */}
                        <div className="address-tit">{ v.get('prefix').toUpperCase() }</div>
                        <ul className="address-detail">
                          {
                            // 渲染城市列表,并绑定点击事件
                            v.get('cities').map((v,i) => {
                              return (
                                <li key={v.get('cityId')}
                                  onClick={() => {
                                    changeCity(v.get('name'))
                                    handleClick()
                                }}>{ v.get('name') }</li>
                              )
                            })
                          }                      
                        </ul>
                      </div>
                    )
                  })
                }
              </div>
            </div>
          </AddressContainer>
        )
      }
      componentDidMount(){
        // 调用 mapDispatch 中的loadData() 方法,获取数据
        this.props.loadData()
    
        this.bScroll = new BScroll(this.scrollEl,{
          click: true,
        })
      }
    }
    
    export default connect(mapState,mapDispatch)(AddressContent)

    至此城市列表页就渲染出来了。

    以上就是利用 immutable 处理 redux 的 过程!

    如果有问题,欢迎指出。

  • 相关阅读:
    强烈推荐Seam实战
    关于写给大家看的C语言书(第2版)的读后感
    在Win7系统上安装ccnet 安装笔记
    使用Itext把html转换成pdf文件
    升级项目到Vs2010,编译时出现:MSB6006: “LC.exe”已退出,解决方法
    vs2010 插件不显示的问题处理。
    几个软件研发团队管理的小问题
    关于UML风格(第2版·英汉对照)的读后感
    C#本质论(第2版)的评论
    IDA Pro代码破解揭秘这本书怎么样
  • 原文地址:https://www.cnblogs.com/wertantan/p/10035812.html
Copyright © 2011-2022 走看看