Redux
mobx 也不错
和vuex去区别
无异步操作,只能dispatch
依赖
npm install redux -S
1.简单上手
1.store.js
import { createStore } from 'redux'
//必须是一个函数(初始化状态)
const countReducer = (state=0,action)=>{
switch(action.type){
case 'add':
return state+=1
break;
case 'minus':
return state-=1
break;
default:
return state;
}
}
const store = createStore(countReducer);
export default store;
2.ReduxTest.js
import React from 'react'
import store from './store'
export default function ReduxTest(){
return (
<div>
<p onClick={()=>store.dispatch({type:'minus'})}>减</p>
<p>{store.getState()}</p>
<p onClick={()=>store.dispatch({type:'add'})}>加</p>
</div>
)
}
3.订阅状态更新 index.js
import store from './store'
ReactDOM.render(<App />, document.getElementById('root'));
store.subscribe(()=>{
ReactDOM.render(<App />, document.getElementById('root'));
})
2.react-redux
1.安装
npm install react-redux -S
2.Provider
不在需要订阅状态,但需要包括顶级组件 APP.js
import { Provider } from 'react-redux'
import store from './store'
function App() {
return (
<div className="App">
<Provider store={ store }>
<header className="App-header">
<h1>hello word</h1>
<Index name='哈哈' />
</header>
</Provider>
</div>
);
}
//实际内部为上下文
3.ReduxTest.js
import React from 'react'
// import store from './store'
import { connect } from 'react-redux'
const mapStateToProps = state => ({num: state})
const mapDispatchToProps = {
add:()=>({type:'add'}),
minus:()=>({type:'minus'})
}
function ReduxTest({num,add,minus}){
return (
<div>
<p onClick={minus}>减</p>
<p>{num}</p>
<p onClick={add}>加</p>
</div>
)
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ReduxTest);
4.ReduxTest.js 装饰器写法
import React from 'react'
// import store from './store'
import { connect } from 'react-redux'
const mapStateToProps = state => ({num: state})
const mapDispatchToProps = {
add:()=>({type:'add'}),
minus:()=>({type:'minus'})
}
@connect(mapStateToProps,mapDispatchToProps)
class ReduxTest extends Component{
render(){
const {minus , num, add } = this.props;
return (
<div>
<p onClick={minus}>减</p>
<p>{num}</p>
<p onClick={add}>加</p>
</div>
)
}
}
export default ReduxTest;
3.redux-thunk(异步操作)
1.安装
npm install redux-thunk -S
npm install redux-logger -S
2.store.js
import { createStore, applyMiddleware } from 'redux'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
//必须是一个函数(初始化状态)
const countReducer = (state=0,action)=>{
switch(action.type){
case 'add':
return state+=1
break;
case 'minus':
return state-=1
break;
default:
return state;
}
}
//注意 applyMiddleware 顺序 先logger 日志记录,再thunk 异步
const store = createStore(countReducer, applyMiddleware(logger,thunk));
export default store;
3.ReduxTest.js
import React from 'react'
// import store from './store'
import { connect } from 'react-redux'
const mapStateToProps = state => ({num: state})
const mapDispatchToProps = {
add:()=>({type:'add'}), //返回的是一个对象
minus:()=>({type:'minus'}),
asyncAdd: () => dispatch =>{ //返回的是一个函数
setTimeout(()=>{
dispatch({type: 'add'})
},1000)
}
}
@connect(mapStateToProps,mapDispatchToProps)
class ReduxTest extends Component{
render(){
const {minus , num, add, asyncAdd } = this.props;
return (
<div>
<p onClick={minus}>减</p>
<p>{num}</p>
<p onClick={add}>加</p>
<p onClick={asyncAdd}>异步</p>
</div>
)
}
}
export default ReduxTest;
4.重构以上代码
1.store/index.js
import { createStore, applyMiddleware } from 'redux'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
import { countReducer } from './countRedux' //导入状态
//注意 applyMiddleware 顺序 先logger 日志记录,再thunk 异步
const store = createStore(countReducer, applyMiddleware(logger,thunk));
export default store;
- store/countRedux.js
//必须是一个函数(初始化状态)
export const countReducer = (state=0,action)=>{
switch(action.type){
case 'add':
return state+=1
break;
case 'minus':
return state-=1
break;
default:
return state;
}
}
//action creator
export const add = () =>({type:'add'}); //返回的是一个对象
export const minus = ()=>({type:'minus'})
export const asyncAdd = () => dispatch =>{ //返回的是一个函数
setTimeout(()=>{
dispatch({type: 'add'})
},1000)
}
}
3.ReduxTest.js
import React from 'react'
// import store from './store'
import { connect } from 'react-redux'
import { add,minus,asyncAdd} from './store/countRedux'
const mapStateToProps = state => ({num: state})
const mapDispatchToProps = {add,minus,asyncAdd}
@connect(mapStateToProps,mapDispatchToProps)
class ReduxTest extends Component{
render(){
const {minus , num, add, asyncAdd } = this.props;
return (
<div>
<p onClick={minus}>减</p>
<p>{num}</p>
<p onClick={add}>加</p>
<p onClick={asyncAdd}>异步</p>
</div>
)
}
}
export default ReduxTest;
5.模块化
1.store/index.js
import { createStore, applyMiddleware, combineReducers } from 'redux'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
import { countReducer } from './countRedux' //导入状态
//注意 applyMiddleware 顺序 先logger 日志记录,再thunk 异步
const store = createStore( combineReducers({
count:countReducer
}), applyMiddleware(logger,thunk));
export default store;
2.ReduxTest.js
import React from 'react'
// import store from './store'
import { connect } from 'react-redux'
import { add,minus,asyncAdd} from './store/countRedux'
const mapStateToProps = state => ({num: state.count})
const mapDispatchToProps = {add,minus,asyncAdd}
@connect(mapStateToProps,mapDispatchToProps)
class ReduxTest extends Component{
render(){
const {minus , num, add, asyncAdd } = this.props;
return (
<div>
<p onClick={minus}>减</p>
<p>{num}</p>
<p onClick={add}>加</p>
<p onClick={asyncAdd}>异步</p>
</div>
)
}
}
6.redux-saga
redux-saga 和redex-thunk 都是异步数据处理
1.安装
npm install redux-saga -S
2.store/saga.js
/**
* call //调用异步函数
* put //执行完异步后 通知更新状态
* takeEvery //全局鉴定 action
*/
import { call, put, takeEvery } from 'redux-saga/effects';
//模拟用户登录
const UserService = {
login(uname){
return new Promise((resolve,reject) => {
setTimeout(() => {
if(uname == 'abc'){
resolve({ id: 1 , name: '小明'})
} else {
reject('用户名或密码错误')
}
},1000)
})
}
}
//带* 为生成器函数
function* login(action){
tyr{
yield put({ type : 'requestLigin'});//提交action
const result = tield call(UserService.login,action.name);
yield put({ type: 'loginSuccess', result })
}catch(message) {
yield put({ type: 'loginFailuer', message })
}
}
function* mySaga(){
yield takeEvery('login', login)
}
export default mySaga;
3.注册 store/index.js
import createSagaMiddleware from 'redux-saga'
import mySaga from './store/saga.js'
//1.创建中间件
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
combineReducers({ user }),
applyMiddleware(logger, sagaMiddleware)
)
//2.中间件运行
sagaMiddleware.run(mySaga);
export default store;
4.user.redux.js
export const user = (
state = {
isLogin: false,
loading: false,
error: ''
},
action
) => {
switch (active.type){
case: 'requestLigin'
return { isLogin: false, loading: true, error: ''}
break;
case: 'loginSuccess'
return { isLogin: true, loading: false, error: ''}
break;
case: 'loginFailuer'
return { isLogin: false, loading: false, error: action.message }
break;
}
}
expore function login(uname){
return { type: 'login', uname}
}
7.生成器函数
function* g(a){
yield a;
yield 'b';
yield 'c';
return 'ending'
}
//第一次传参,要传给构造函数
var gen = g('a')
console.log(gen.next()) //{ value: 'a', done: false }
console.log(gen.next()) //{ value: 'b', done: false }
console.log(gen.next()) //{ value: 'c', done: false }
console.log(gen.next()) //{ value: 'd', done: true }
function next(){
let { value,done } = gen.next()
if(!done){
next()
}
}
next()
2.传至 计算
function r(num){
const r1 = yield compute(num)
yield compute(r1)
}
function compute(num){
return new Promise(resolve => {
setTimeout(()=>{
const ret = num*num
resolve(ret)
},1000)
} )
}
let it = r(2)
// it.next().value.then(num => it.next(num));
function next(data){
let { value,done } = it.next(data);
if(!done){
value.then(num => {
next(num);
})
}
}
next()