转载请注明出处,未经同意,不可修改文章内容。
🔥🔥🔥"前端一万小时"两大明星专栏------"从零基础到轻松就业"、"前端面试刷题",已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。
1 immutable.js 的使用
打开 header 目录下 store 中的 reducer.js
文件:
javascript
import {CHANGE_CLASS_NAME, RESUME_CLASS_NAME} from "./actionTypes";
const defaultState = {
refresh: false
}
export default (state=defaultState, action) => {
if(action.type === CHANGE_CLASS_NAME) {
return {
refresh: true
}
}
if(action.type === RESUME_CLASS_NAME) {
return {
refresh: false
}
}
return state;
}
根据之前的 React 基础语法讲解,reducer 在接到"原始 state"后,一定不能对"原始 state"进行任何修改 !reducer 要想返回一个新的"数据"出去,必须要对"原始 state"进行克隆后,才能进行相应地逻辑操作,否者会出现莫名的 bug。
但在实际项目中,由于开发者们的起点不一,我们不能保证每一个开发者都把这一要点牢牢记住并遵从。
幸好的是,Facebook 团队历时 3 年为我们开发出了一个第三方模块------immutable.js,用来确保我们不去修改"原始 state",并提高页面性能。
immutable.js 可以帮我们生成一个"immutable 对象",即"不可变对象"。
所以,只要我们把 "原始 state"变为"immutable 对象","原始 state"就可以不被任何人改变了,reducer 也就不会出莫名的 bug。
1️⃣安装 immutable.js:
2️⃣打开 header 目录下 store 中的 reducer.js
文件,将"原始 state"变为"immutable 对象":
javascript
import {CHANGE_CLASS_NAME, RESUME_CLASS_NAME} from "./actionTypes";
/*
❗️❗️❗️2️⃣-①:从 immutable 中引入 fromJS 方法,这个"方法"可以
帮我们把一个"JS 对象"转化为一个"immutable 对象";
*/
import {fromJS} from "immutable";
/*
2️⃣-②:先把原来"JS 对象"的写法注释掉~/
const defaultState = {
refresh: false
}
*/
// 2️⃣-③:用 fromJS 将"JS 对象"转变为"immutable 对象";
const defaultState = fromJS({
refresh: false
})
export default (state=defaultState, action) => {
if(action.type === CHANGE_CLASS_NAME) {
return {
refresh: true
}
}
if(action.type === RESUME_CLASS_NAME) {
return {
refresh: false
}
}
return state;
}
打开 header 目录下的 index.js
文件:
jsx
import React, {Component} from "react";
import {
HeaderWrapper,
Logo,
Navbar,
ItemList,
LinkList,
SearchArea,
SearchInput,
SearchPanel,
PanelTitle,
PanelChange,
PanelLabels,
LabelLink,
Extra,
ExtraLink
} from "./style";
import { connect } from "react-redux";
import {actionCreators} from "./store";
class Header extends Component {
render() {
return (
<HeaderWrapper>
<Logo>
<img src="https://qdywxs.github.io/jianshu-images/logo.png" alt="logo" />
</Logo>
<Navbar className="clearfix">
<ItemList className="active">
<LinkList href="/">
首页
</LinkList>
</ItemList>
<ItemList>
<LinkList href="/">
下载APP
</LinkList>
</ItemList>
</Navbar>
<SearchArea>
<SearchInput />
<span className="iconfont icon-search"></span>
<SearchPanel>
<PanelTitle>
热门搜索
<PanelChange
onMouseDown={this.props.handleMouseDown}
onMouseUp={this.props.handleMouseUp}
>
<span className={this.props.refresh ? "iconfont refresh" : "iconfont"}></span>
换一批
</PanelChange>
</PanelTitle>
<PanelLabels className="clearfix">
<LabelLink href="/">
区块链
</LabelLink>
<LabelLink href="/">
故事
</LabelLink>
<LabelLink href="/">
小程序
</LabelLink>
<LabelLink href="/">
前端一万小时
</LabelLink>
</PanelLabels>
</SearchPanel>
</SearchArea>
<Extra>
<span className="iconfont icon-textsize" ></span>
<ExtraLink className="login" href="/">
登录
</ExtraLink>
<ExtraLink className="register" href="/">
注册
</ExtraLink>
<ExtraLink className="writing" href="/">
<span className="iconfont icon-pen"></span>
写文章
</ExtraLink>
</Extra>
</HeaderWrapper>
)
}
}
const mapStateToProps = (state) => {
return {
/*
❗️❗️❗️2️⃣-④:由于这里的 state.header 指的就是上一步中
reducer 返回的"数据",但这个"数据"已经变成了"immutable 对象"了,
故直接用 state.header. "改变"数据的语法是不可以的!
❗️需要用 .get() 的 immutable 特定方法来获取对应的属性!
refresh: state.header.refresh
*/
refresh: state.header.get("refresh")
}
}
const mapDispatchToProps = (dispatch) => {
return {
handleMouseDown() {
const action = actionCreators.changeClassNameAction();
dispatch(action)
},
handleMouseUp() {
const action = actionCreators.resumeClassNameAction();
dispatch(action)
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);
❌经过以上两步,虽然数据获取的流程跑通了,但"数据改变"的流程还未通!
打开 header 目录下 store 中的 reducer.js
文件:
javascript
import {CHANGE_CLASS_NAME, RESUME_CLASS_NAME} from "./actionTypes";
import {fromJS} from "immutable";
const defaultState = fromJS({ /*❗️*/
refresh: false
})
export default (state=defaultState, action) => {
if(action.type === CHANGE_CLASS_NAME) {
/*
❗️2️⃣-⑤:当用户 mousedown 按钮时,会派发一个 action 给到 reducer,
reducer 给 store 返回一个新的数据。由于上一步中,我们已经让 state 变为了
immutable 对象,这里就不能再像原来那样返回"普通对象"了!
❗️❗️❗️需要利用 immutable 提供的 set() 方法来设置"数据"!
它的背后原理为:immutable 对象的 set 方法会结合"之前 immutable 的值"和"设置的值",
返回一个全新的对象(它并没有去改"原始 state")!
return {
refresh: true
}
*/
return state.set("refresh", true); // 🚀注意 .set() 方法的格式!
}
if(action.type === RESUME_CLASS_NAME) {
/*
同理,把这里的代码注释掉,并进行改写~
return {
refresh: false
}
*/
return state.set("refresh", false);
}
return state;
}
返回页面查看效果:
2 redux-immutable 的使用
打开 header 目录下的 index.js
文件:
jsx
import React, {Component} from "react";
import {
HeaderWrapper,
Logo,
Navbar,
ItemList,
LinkList,
SearchArea,
SearchInput,
SearchPanel,
PanelTitle,
PanelChange,
PanelLabels,
LabelLink,
Extra,
ExtraLink
} from "./style";
import { connect } from "react-redux";
import {actionCreators} from "./store";
class Header extends Component {
render() {
return (
<HeaderWrapper>
<Logo>
<img src="https://qdywxs.github.io/jianshu-images/logo.png" alt="logo" />
</Logo>
<Navbar className="clearfix">
<ItemList className="active">
<LinkList href="/">
首页
</LinkList>
</ItemList>
<ItemList>
<LinkList href="/">
下载APP
</LinkList>
</ItemList>
</Navbar>
<SearchArea>
<SearchInput />
<span className="iconfont icon-search"></span>
<SearchPanel>
<PanelTitle>
热门搜索
<PanelChange
onMouseDown={this.props.handleMouseDown}
onMouseUp={this.props.handleMouseUp}
>
<span className={this.props.refresh ? "iconfont refresh" : "iconfont"}></span>
换一批
</PanelChange>
</PanelTitle>
<PanelLabels className="clearfix">
<LabelLink href="/">
区块链
</LabelLink>
<LabelLink href="/">
故事
</LabelLink>
<LabelLink href="/">
小程序
</LabelLink>
<LabelLink href="/">
前端一万小时
</LabelLink>
</PanelLabels>
</SearchPanel>
</SearchArea>
<Extra>
<span className="iconfont icon-textsize" ></span>
<ExtraLink className="login" href="/">
登录
</ExtraLink>
<ExtraLink className="register" href="/">
注册
</ExtraLink>
<ExtraLink className="writing" href="/">
<span className="iconfont icon-pen"></span>
写文章
</ExtraLink>
</Extra>
</HeaderWrapper>
)
}
}
const mapStateToProps = (state) => {
return {
/*
❌这行代码中,state 是 src 目录下 store 中 reducer.js 里的"JS 对象",
而 state.header 又是 header 目录下 store 中 reducer.js 的"immutable 对象"。
这样"JS 对象"和"immutable 对象"揉在一起获取"数据"的方式很不利于后期维护!
❗️故,我们既然用了 immutable,那么我们最好就把所有"数据"统一为"immutable 对象"。
*/
refresh: state.header.get("refresh")
}
}
const mapDispatchToProps = (dispatch) => {
return {
handleMouseDown() {
const action = actionCreators.changeClassNameAction();
dispatch(action)
},
handleMouseUp() {
const action = actionCreators.resumeClassNameAction();
dispatch(action)
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);
1️⃣安装 redux-immutable:
2️⃣打开 src 目录下 store 中 reducer.js
文件:
javascript
/*
2️⃣-①:之前,我们的 combineReducers 来自 redux。但有了 redux-immutable 后,
redux-immutable 也为我们提供了一个 combineReducers。
用它生成的"数据"就为"immutable 对象"
import {combineReducers} from "redux";
*/
import {combineReducers} from "redux-immutable";
import {reducer as headerReducer} from "../common/header/store";
const reducer = combineReducers({ // 2️⃣-②:❗️生成的 reducer 是一个"immutable 对象"!
header: headerReducer
})
export default reducer;
返回 header 目录下的 index.js
文件:
jsx
import React, {Component} from "react";
import {
HeaderWrapper,
Logo,
Navbar,
ItemList,
LinkList,
SearchArea,
SearchInput,
SearchPanel,
PanelTitle,
PanelChange,
PanelLabels,
LabelLink,
Extra,
ExtraLink
} from "./style";
import { connect } from "react-redux";
import {actionCreators} from "./store";
class Header extends Component {
render() {
return (
<HeaderWrapper>
<Logo>
<img src="https://qdywxs.github.io/jianshu-images/logo.png" alt="logo" />
</Logo>
<Navbar className="clearfix">
<ItemList className="active">
<LinkList href="/">
首页
</LinkList>
</ItemList>
<ItemList>
<LinkList href="/">
下载APP
</LinkList>
</ItemList>
</Navbar>
<SearchArea>
<SearchInput />
<span className="iconfont icon-search"></span>
<SearchPanel>
<PanelTitle>
热门搜索
<PanelChange
onMouseDown={this.props.handleMouseDown}
onMouseUp={this.props.handleMouseUp}
>
<span className={this.props.refresh ? "iconfont refresh" : "iconfont"}></span>
换一批
</PanelChange>
</PanelTitle>
<PanelLabels className="clearfix">
<LabelLink href="/">
区块链
</LabelLink>
<LabelLink href="/">
故事
</LabelLink>
<LabelLink href="/">
小程序
</LabelLink>
<LabelLink href="/">
前端一万小时
</LabelLink>
</PanelLabels>
</SearchPanel>
</SearchArea>
<Extra>
<span className="iconfont icon-textsize" ></span>
<ExtraLink className="login" href="/">
登录
</ExtraLink>
<ExtraLink className="register" href="/">
注册
</ExtraLink>
<ExtraLink className="writing" href="/">
<span className="iconfont icon-pen"></span>
写文章
</ExtraLink>
</Extra>
</HeaderWrapper>
)
}
}
const mapStateToProps = (state) => {
return {
/*
❌这行代码中,state 是 src 目录下 store 中 reducer.js 里的"JS 对象",
而 state.header 又是 header 目录下 store 中 reducer.js 的"immutable 对象"。
这样"JS 对象"和"immutable 对象"揉在一起获取"数据"的方式很不利于后期维护!
❗️故,我们既然用了 immutable,那么我们最好就把所有"数据"统一为"immutable 对象"。
*/
/*
3️⃣既然上一步已经让 state 成为"immutable 对象",那么这里就可以用其提供的
get 方法获取"数据"。由于这里有两层 get,故可以用 immutable 提供的 getIn([]) 方法简写~
refresh: state.header.get("refresh")
*/
refresh: state.getIn(["header", "refresh"]) /*
❗️它其实是
refresh: state.get("header").get("refresh")
的简写!
*/
}
}
const mapDispatchToProps = (dispatch) => {
return {
handleMouseDown() {
const action = actionCreators.changeClassNameAction();
dispatch(action)
},
handleMouseUp() {
const action = actionCreators.resumeClassNameAction();
dispatch(action)
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);
返回页面查看效果:
祝好,qdywxs ♥ you!