Reducer
必须为纯函数
- 什么是纯函数? 所谓纯函数基本可以用一句话来替代,那就是”
一个函数,相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。
“,下面展示一下纯函数与非纯函数的区别
非纯函数
var obj1 = { name:'lam', }
function changeObj(obj){ obj.name = '肥林' }
changeObj(obj1)
console.log(obj1);
|
纯函数
var obj1 = { name:'lam', }
function changeObj(obj){ var newObj = {...obj} newObj.name = '肥林' }
changeObj(obj1)
console.log(obj1);
|
因为对象是指向内存中的地址,而reducer
又是修改对象的,因此我们必须使用纯函数
来设置reducer
,redux
源代码中将oldState
和newState
(reducer
返回的结果)做比较,如果reducer
为非纯函数,两者指向同一个地址,导致react
认为state
无变化,从而不更新页面。这样做是牺牲一点计算性能(生成新对象)来保证页面刷新,在页面更新时使用react
的diff
算法来计算需要更新的组件。之所以这样设计,是为了避免在reducer
中进行大量的深比较。
Reducer
合并(combineReducers
)
官方文档
我们在编写代码的时,有时候会遇到一个全局的store
中会有多个不同的action
所处理的属性之间没有联系,此时我们就可以将Reducer
函数拆分成多个小的Reducer
,不同的函数负责处理不同属性,最终把它们合并成一个大的 Reducer
即可。如下面的案例
案例需求
import React, { Component } from 'react'
import { HashRouter as Router, Route, Redirect, Switch, NavLink } from 'react-router-dom' import store from '../../store/index.js'
import About from './about.js' import Info from './info.js' import Footer from './footer.js' import NotFound from './404.js'
export default class home extends Component { componentDidMount(){
store.subscribe(()=>{ console.log('home组件监听中....'); this.setState({ isShow:store.getState().isShowBottomReducer.isShow }) }) } state = { isShow:store.getState().isShowBottomReducer.isShow } render() { console.log('是否展示底部区域',store.getState().isShowBottomReducer.isShow); return ( <div> <h1>首页</h1> <p>(去到信息页关闭底部,去到关于页开启底部)</p> <div style={{ width: '100%', height: '400px', backgroundColor: 'yellowgreen' }}> <Router> <ul> <li><NavLink to={'/home/info'}>info</NavLink></li> <li><NavLink to={'/home/about'}>about</NavLink></li> </ul> {/* 使用Switch来解决每次页面刷新,重定向功能执行的bug(模糊匹配) */} <Switch> <Route path="/home/about" component={About} /> <Route path="/home/info" component={Info} />
<Redirect from="/" to="/home/info" exact /> {/* 匹配不到的页面则展示404 */} <Route component={NotFound} /> </Switch> </Router> </div> {/* 通过判断全局store中的isShow来执行是否展示Footer组件 */} {this.state.isShow && <Footer />} </div> ) } }
|
info.js
(个人信息页)
import React ,{useEffect}from 'react' import store from '../../store/index.js'
export default function Info() { useEffect(()=>{ console.log('进入info组件');
store.dispatch({ type:'changeBottom', isShow:true }) return ()=>{ console.log('退出info组件'); store.dispatch({ type:'changeBottom', isShow:false }) } },[])
return ( <div>个人信息页</div> ) }
|
about.js
(关于页面)
import React ,{useEffect,useState}from 'react' import store from '../../store/index.js'
export default function About() { console.log(store.getState().pageNameReducer.pageName); const [title,setTitle] = useState(store.getState().pageNameReducer.pageName) useEffect(()=>{ console.log('进入About组件'); store.dispatch({ type:'showTitle', payload:'关于页', }) return ()=>{ console.log('退出About组件'); } },[])
return ( <div>{title}</div> ) }
|
小型Reducer
(最后在全局的store
中合并成大的)
const isShowBottomReducer = (prevState={ isShow:true },action)=>{ let newState = {...prevState} switch(action.type){ case "changeBottom": newState.isShow = action.isShow return newState default: return prevState } }
export default isShowBottomReducer
const pageNameReducer = (prevState={ pageName:'unTitle' },action)=>{ let newState = {...prevState} switch(action.type){ case "showTitle": newState.pageName = action.payload return newState default: return prevState } }
export default pageNameReducer
|
store.js
(全局store
)
import {combineReducers, createStore} from 'redux'
import pageNameReducer from './reducer/pageNameReducer' import isShowBottomReducer from './reducer/isShowBottomReducer'
const reducer = combineReducers({ pageNameReducer, isShowBottomReducer })
const store = createStore(reducer)
export default store
|
结果展示: