一.Redux 解析
1).统一数据管理
将所需的数据提取到state中统一进行管理。当渲染后我们希望更改状态,封装更改状态的方法(dispatch)
2).实现dispatch
不要直接更改状态而是使用dispatch方法进行状态的更改,派发一个带有type的属性来进行状态的更改,但是依然无法阻止用户更改状态.
3).createStore的实现
将状态放到了createStore函数中,目的是隔离作用域,并且再内部返回深度克隆的对象,这样用户无法再通过外界更改状态。但是状态应该由我们自身来控制,应该是外界传入的,所以要将状态拿出createStore。并且判断的逻辑也应该由我们自己来编写
4).reducer的实现
我们已将需要自己处理的逻辑提取出来,但是我们每次dispatch时都需要自己触发视图的更新,我们希望采用发布订阅来实现。
5).订阅函数
我们redux中常用的方法已经封装完成我们将封装好的逻辑抽离成redux.js
二.Redux深入
2.1 redux文件拆分
store
│ action-types.js
│ index.js
│
├─actions
│ counter.js
│
└─reducer
counter.js
action-types用来存放需要的常量
counter中存放reducer的逻辑
store中的index文件用来创建store
action文件夹中的counter,用来生成对应组件的action对象
2.2 实现多个counter
在redux中只能拥有一个store所以我们需要将多个状态进行合并,状态是通过reducer返回的,所以我们可以将多个reducer进行合并达到合并状态的目的。
│ index.js
│ redux.js
│
├─components
│ counter1.js
│ counter2.js
│
└─store
│ action-types.js
│ index.js
│
├─actions
│ counter1.js
│ counter2.js
│
└─reducer
counter1.js
counter2.js
index.js
action-types新增counter2处理的常量
对应的counter2中的action也进行更改
三. React-Redux
1.为什么需要高阶组件
从本地存储中获取数据放到输入框内的逻辑应该就是公用逻辑。这时我们就要使用高阶组件,也就是将组件在原有的基础上进行包装。
2.实现高阶组件
我们将公共的逻辑拿到外层组件,处理好后以属性的方式传递给原本的组件,为此高阶组件就是一个 React 组件包裹着另外一个 React 组件
3.context的用法
react是单向数据流,我们想传递数据需要一层层向下传递,数据传递变得非常麻烦,我们可以用context实现数据的交互
1) 父 childContextTypes getChildContext函数
2) 子 contextTypes
import React from 'react';
import ReactDOM from 'react-dom';
import Counter from "./components/Counter";
import store from './store/index';
import {Provider} from 'react-redux';
ReactDOM.render(
<Provider store={store}>
<Counter/>
</Provider>,window.root);
class Counter extends React.Component {
render(){
return <div>
数量:{this.props.number}
<button onClick={()=>{this.props.add(1)}}>+</button>
<button onClick={()=>{this.props.minus(1)}}>-</button>
</div>
}
}
export default connect(state=>({...state}),dispatch=>({
add:(amount)=>{dispatch(actions.add(amount))},
minus:(amount)=>{dispatch(actions.minus(amount))}
}))(Counter)
四.MiddleWare的使用
1.logger中间件
在控制台查看更改前后的状态
2.实现redux-thunk中间件
实现派发异步动作,actionCreator可以返回函数,可以把dispatch的权限交给此函数
3.实现redux-promise中间件
返回一个实例 ,支持异步请求 看resolve reject情况
五. Redux 源码仿写
<div id="title"></div>
<div id="content"></div>
const CHANGE_TITLE_TEXT = "CHANGE_TITLE_TEXT";
const CHANGE_CONTENT_COLOR = "CHANGE_CONTENT_COLOR";
function createStore(reducer) {
let state;
let listeners = [];
let getState = () => JSON.parse(JSON.stringify(state));
function dispatch(action) {
state = reducer(state, action);
listeners.forEach(item => {
if (typeof item === "function") {
item();
}
})
}
dispatch({});
function subscribe(fn) {
listeners.push(fn);
return () => {
listeners = listeners.filter(item => item !== fn);
}
}
return {
getState,
dispatch,
subscribe
}
}
let initState = {
title: { color: "red", text: "xxWOxx" },
content: { color: "yellow", text: "qqNIqq" }
};
function reducer(state = initState, action) {
switch (action.type) {
case CHANGE_TITLE_TEXT:
return { ...state, title: { ...state.title, text: action.text } };
case CHANGE_CONTENT_COLOR:
return { ...state, content: { ...state.content, color: action.color } }
}
return state;
}
let store = createStore(reducer);
function renderTitle() {
let title = document.getElementById("title");
title.innerHTML = store.getState().title.text;
title.style.color = store.getState().title.color;
}
function renderContent() {
let content = document.getElementById("content");
content.innerHTML = store.getState().content.text;
content.style.color = store.getState().content.color;
}
function renderApp() {
renderTitle();
renderContent();
}
renderApp();
setTimeout(function () {
store.dispatch({ type: CHANGE_TITLE_TEXT, text: "好好学习" });
store.dispatch({ type: CHANGE_CONTENT_COLOR, color: "blue" })
}, 2000)