简书Header组件开发(使用immutable.js库、redux-immutable库)

总结

  • immutable.js库/redux-immutable库 都可生成不可改变的immutable对象,但使用场景不同
    • **immutable.js库的fromJS()**:接受组件的state对象,返回immutable对象类型的state。
    • **redux-immutable库的combineReducers()**:接受各个组件的reducer,返回immutable对象类型的 总state。
  • 想要获取immutable对象的属性则需要使用**get()**。
  • immutable对象的set()不会改变原本的immutable对象,它返回的是新的immutable对象。
  • 注意:fromJS会自动 将对象中的数组 变成 immutable类型的数组,所以使用set()修改immutable类型数组时要求修改的数据也是immutable类型的,否则数据类型就乱了。所以我们要使用fromJS使set()的参数2也成为immutable类型

拆分actionCreators与constants

  • actionCreators.js里都是函数,每个函数都返回对应的action
  • constants.js即我们之前使用过的actionTypes.js,用于将action的type从字符串定义为常量的文件
  • 在common-header-store文件夹下新建actionCreators.js和constants.js,他们都要通过index.js进行输出store文件夹下的所有文件都通过index.js输出,这样 外部文件 引用时统一引用到store文件夹即可

拆分constants.js

1.common-header-store 新建constants.js 将action的type从字符串定义为常量

1
2
3
//加一个`header/`表示是header下的,对后续维护有好处
export const SEARCH_FOCUS = "header/SEARCH_FOCUS";
export const SEARCH_BLUR = "header/SEARCH_BLUR";

2.在common-header-store-index.js中引入、输出constants.js,统一对外接口路径

1
2
3
4
import reducer from "./reducer";
import * as constants from "./constants";

export { reducer, constants };

3.header-index.js中,引入constants并修改原本的action的type字符串=>常量):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { constants } from "./store";
//中间未修改部分省略
const mapDispatchProps = (dispatch) => {
return {
handleInputFocus() {
const action = {
type: constants.SEARCH_FOCUS
};
dispatch(action);
},
handleInputBlur() {
const action = {
type: constants.SEARCH_BLUR
};
dispatch(action);
}
}
}

注意:两个常量都是从constants中获取的,constants输出时使用了*,所以调用常量时都要使用constants前缀

4.common-header-store-reducer.js中,引入constants并修改action.type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import * as constants from "./constants";

const defaultState = {
focused: false
};

export default (state = defaultState, action) => {
if (action.type === constants.SEARCH_FOCUS) {
return {
focused: true
}
}
if (action.type === constants.SEARCH_BLUR) {
return {
focused: false
}
}
return state;
}

拆分actionCreators.js

1.common-header-store新建actionCreators.js,里面的每个函数都返回对应的action

1
2
3
4
5
6
7
8
9
import { constants } from "../store";

export const searchFocus = () => ({
type: constants.SEARCH_FOCUS
});

export const searchBlur = () => ({
type: constants.SEARCH_BLUR
});

2.在common-header-store-index.js中统一对外接口

1
2
3
4
5
import reducer from "./reducer";
import * as constants from "./constants";
import * as actionCreators from "./actioncreators";

export { reducer, constants, actionCreators };

3.在common-header-store-reducer.js中引入并使用actionCreators中的函数来返回对应action

1
2
3
4
5
6
7
8
9
10
11
12
import { constants, actionCreators } from "./store";
//中间未修改部分省略
const mapDispatchProps = (dispatch) => {
return {
handleInputFocus() {
dispatch(actionCreators.searchFocus());
},
handleInputBlur() {
dispatch(actionCreators.searchBlur());
}
}
}

(**注意:调用的是actionCreators中的函数,所以记得()**)


immutable.js库 生成不可改变的对象

使用immutable.js管理store中的数据

  • reducer中拿到的store的state是不应该被改变的,为防止不小心改变,我们可以将state变成immutable对象
  • 生成immutable对象:使用 immutable库 的fromJS()
  • 获取immutable对象的属性:使用 immutable对象 的get()(注意参数是字符串
  • 修改并返回新的immutable对象:使用 immutable对象 的set()

安装immutable库

可参考immutable.js官方文档

1
yarn add immutable

immutable库的fromJS()生成immutable对象

  • immutable库的fromJS可用于生成immutable对象
  • 引入import {fromJS} from "immutable";
  • 使用const immutable = fromJS({对象属性:属性值});(fromJS()接受一个对象,并返回immutable对象)

header-reducer.js中,使用immutable库的fromJS生成immutable对象,替代原本的state默认值

1
2
3
4
5
import { fromJS } from "immutable";

const defaultState = fromJS({
focused: false
});

immutable对象的get()获取对象属性

  • 想要获取immutable对象的属性值不能通过对象名.属性名的方式,需要使用对象名.get("属性名")
  • 注意:get()接受的参数为字符串

header-index.js中,原本的state已经变成immutable对象,所以需要使用get()来获取属性

1
2
3
4
5
const mapStateToProps = (state) => {
return {
focused: state.header.get("focused")
}
}

注意:state是JS对象,state.header是immutable对象,所以获取属性的方法才不同。

immutable对象的set()返回新对象

  • immutable对象的set()接受两个参数,返回新对象
    • 参数1:(字符串)想要修改的对象的属性
    • 参数2:想要修改的属性值
  • 语法:immutable对象.set("属性名",属性值)
  • 注意:immutable对象 是不可改变的,set()不会改变 immutable对象,他会结合 之前的immutable对象的值 和 通过参数修改的值,返回全新的对象

header-reducer.js中,需要返回新的state,即新的immutable对象:

1
2
3
4
5
6
7
8
9
10
11
export default (state = defaultState, action) => {
if (action.type === constants.SEARCH_FOCUS) {
// set()不会改变 immutable对象
// 他会结合 之前的immutable对象的值 和 通过参数修改的值,返回全新的对象
return state.set("focused", true);
}
if (action.type === constants.SEARCH_BLUR) {
return state.set("focused", false);
}
return state;
}

补充:getIn()代替连续get()

  • 想要获取immutable对象的属性的属性时可使用getIn()
  • 详细用法可参考immutable.js官方文档
  • getIn()接受一个数组作为参数数组元素为字符串类型
    • immutable对象.getIn(["参数1","参数2"])表示获取immutable对象的参数1下的属性2。
1
2
3
immutable对象.get("属性名a").get("属性名b")
//等同于
immutable对象.getIn(["属性名a","属性名b"])

补充:merge()代替连续set()

  • 详细用法可参考官方文档
  • 需要连续修改数据后返回immutable对象时,可使用merge()合成多次修改。
1
2
3
4
5
6
immutable对象.set("属性名a",属性值a).set("属性名b",属性值b)
//等同于
merge({
属性名a:属性值a,
属性名b:属性值b
})

补充:ToJS()将immutable对象=>JS对象

  • 注意:对象包括数组
  • 语法:const JS对象 = immutable对象.toJS();
  • 作为state,我们不希望他改变,但是state中的数组我们是可以允许改变的,将state生成为immutable对象时顺便生成的immutable数组就可使用ToJS()将其转换为JS数组,以方便修改

在reducer中,我们将state生成为immutable对象后,其中的数组也会成为immutable数组
immutable数组

那后续的数组修改就会变得很麻烦,所以想要修改数组前可使用ToJS()将immutable数组转回JS数组

1
const newList = list.toJS();

redux-immutable库 生成不可改变的对象

  • 上面我们知道了,通过 immutable库的fromJS() 可在组件的reducer中生成immutable对象类型的state。
  • 使用redux-immutable库的combineReducers()合成各个组件的reducer得到的就是immutable对象
  • 想要获取immutable对象的属性的属性时可使用getIn()

使用redux-immutable统一数据格式

  • header下的reducer中的state是immutable对象。
  • 项目最外层的state还是JS对象,这个state是在src-store-reducer.js中创建的。

在header-index.js中,state是JS对象,state.header是immutable对象

1
2
3
4
5
const mapStateToProps = (state) => {
return {
focused: state.header.get("focused")
}
}
  • 原本项目最外层的state是使用redux的combineReducers()合成各个组件的reducer得到的。
    • immutable库的fromJS()接受的参数是对象,不具有结合reducer们的能力,最外层state是由许多reducer合成而来,不能使用fromJS()。
  • 而使用redux-immutable库的combineReducers()合成各个组件的reducer得到的就是immutable对象

安装redux-immutable库

1
yarn add redux-immutable

redux-immutable库的combineReducers()生成immutable对象

  • state是由reducer进行 定义/修改 返回给store的。
  • 原本我们使用redux提供的combineReducers()生成的reducer返回的state是JS对象
  • 现在改成使用redux-immutable库提供的combineReducers()生成immutable对象类型的state返回给store

src-store-reducer.js
只需改成使用redux-immutable库提供的combineReducers()即可
只需改成使用redux-immutable库提供的combineReducers()即可使生成的reducer(即state)为immutable对象

使用immutable对象的get()

**header-index.js中,**由于最外层state也成为了immutable对象,所以获取state的header时要使用get():

1
2
3
4
5
const mapStateToProps = (state) => {
return {
focused: state.get("header").get("focused")
}
}

immutable对象的getIn()获取属性的属性

上面header-index.js的代码可改为:

1
2
3
4
5
const mapStateToProps = (state) => {
return {
focused: state.getIn(["header", "focused"])
}
}

,