[Redux] redux的概述
redux 的概述
随着 javascript 单页应用的不断发展,javascript 需要管理比以往都要多的状态,管理不断变化的 state 非常困难,数据流动不断变的模糊不可预测,代码的开发与维护成为了变得越来越困难.redux 这类状态管理框架变出现了,通过限制更新发生的时间和方式,来使 state 的变化变得可以预测.
redux 是一个很有用的框架,但是并不是非用不可,而是当你自己觉得可能需要 redux 的时候,就会找到他,并且使用他(还有其他同类框架)
- 当你有大量的,随时间变化的数据
- 当你需要一个单一可靠的 state 数据源
- 当你把所有 state 放到顶部,或者父子兄弟之间的数据通信让你焦头烂额的时候
三大原则
- 单一数据源 (整个应用的 state 存放在一个 object tree 中,这个 object tree 只存在与唯一的一个 store 中)
- state 是只读的,唯一能够改变 state 的只有 action
- 只能通过纯函数进行修改
state 基本概念
state 是数据的状态集合,一般为一个对象
let state = {
    singer: [
        {
            name: "刘德华",
            desc: "一位演员"
        }
    ],
    actor: [
        {
            name: "郭富城",
            desc: "一位歌手"
        }
    ]
};
action 基本概念
action 是一个普通的 javacript 对象,用来更新 state 并同时描述发生了什么.可以知道应用到底发生了什么,变化后可以知道为什么改变.
let action = {
    type: "ADD_SINGER",
    payload: {
        name: "黎明",
        desc: "一位很好的歌手"
    }
};
let action2 = {
    type: "ADD_ACTOR",
    payload: {
        name: "周润发",
        desc: "一位很好的演员"
    }
};
action 生成器
(action 是一个对象,action 生成器是一个函数,两个不同的概念)
用于 action 的复用,实际上是返回一个对象的函数
function addSinger_action(payload) {
    return {
        type: "ADD_SINGER",
        payload
    };
}
function addActor_action(payload) {
    return {
        type: "ADD_ACTOR",
        payload
    };
}
reducer 基本概念
reducer 是一个为了把 state 和 action 连接起来而诞生的纯函数,接收 state 和 action,然后返回一个新的 state
function add_singer(state, action) {
    if (action.type === "ADD_SINGER") {
        console.warn("发起了action=ADD_SINGER");
        state = Object.assign({}, state, {
            singer: state.singer.concat([action.payload])
        });
        return state;
    }
    return state;
}
function add_actor(state, action) {
    if (action.type === "ADD_ACTOR") {
        console.warn("发起了action=>ADD_ACTOR");
        state = Object.assign({}, state, {
            actor: state.actor.concat([action.payload])
        });
        return state;
    }
    return state;
}
改变 state
state = add_actor(
    state,
    addActor_action({
        name: "周润发",
        desc: "一位很好的演员"
    })
);
console.log(state);
state = add_singer(
    state,
    addSinger_action({
        name: "黎明",
        desc: "一位很好的歌手"
    })
);
console.log(state);

上面就是 state,action 以及 reducer 连接二者的方式,redux 里面提供了更多的便捷操作
redux 基础
1. redux 中的 action
action 主要是把数据从应用传到 store 的有效载荷,它是 store 的唯一来源,通过 reducer 定义的 state 是初始化,一般写法中多设置为 null,undefined,{},[]等.通过 store.dispatch()将 action 传到 store.为了使用方便,一般会用 action 生成器来生成 action.
redux 只用把 action 生成器的结果传给 dispatch()就可以发起 dispatch
import { createStore } from "../redux/index";
import reducer from './reducer';
const ADD_SINGER = "ADD_SINGER";
const ADD_ACTOR = "ADD_ACTOR";
const store = createStore(reducer);
store.dispatch(
    addSinger_action({
        name: "周华健",
        desc: "一位大帅哥"
    })
);
store.dispatch(
    addActor_action({
        name: "谢安琪",
        desc: "一位小美女"
    })
);
console.log(store.getState());
function addSinger_action(payload) {
    return {
        type: ADD_SINGER,
        payload
    };
}
function addActor_action(payload) {
    return {
        type: ADD_ACTOR,
        payload
    };
}

我们也可以创建一个函数用于返回 dispatch 触发器
bound_add_singer_action({
    name: "周华健",
    desc: "一位大帅哥"
});
bound_add_actor_action({
    name: "谢安琪",
    desc: "位小美女"
});
function bound_add_singer_action(payload) {
    return store.dispatch(addSinger_action(payload));
}
function bound_add_actor_action(payload) {
    return store.dispatch(addActor_action(payload));
}
console.log(store.getState());
action 主要包含 action 对象,action_creater()生成器,bound_action_creater()绑定函数
//我是action
{type:"我是type",payload:"我是数据"}
//我是action生成器,我是来返回action对象
function action_creater(){
    return {type:"我是type",payload:"我是数据"}
}
//我是bound_action_creater绑定函数,我是获取action生成器的返回值去触发dispatch()
function bound_action_creater(){
    store.dispatch(action_creater());
}
2. redux 中 reducer
(oldState,action)=> newState 这种就是一个最简单的 reducer.
禁止事项
- 修改传入的参数
- 执行有副作用的操作,如 api 请求,变量修改,路由跳转
- 调用非纯函数,如 Date.now()或 Math.random()
const singerState = {
    singer: [
        {
            name: "刘德华",
            desc: "一位演员"
        }
    ]
}; //state初始状态
const actorState = {
    actor: [
        {
            name: "郭富城",
            desc: "一位歌手"
        }
    ]
}; //state初始状态
const reducer = function(state = {}, action) {
    return {
        singerState: singer_reducer(state.singerState, action),
        actorState: actor_reducer(state.actorState, action)
    };
};
// console.log(reducer);
export default reducer;
function singer_reducer(state = singerState, action) {
    if (action.type === "ADD_SINGER") {
        console.warn("发起了action=ADD_SINGER");
        state = Object.assign({}, state, {
            singer: state.singer.concat([action.payload])
        }); //Object.assgin会修改第一个参数的值,所以将state放到二号位
        return state;
    }
    return state; //遇到未知的 action 时,一定要返回旧的 state
}
function actor_reducer(state = actorState, action) {
    if (action.type === "ADD_ACTOR") {
        console.warn("发起了action=>ADD_ACTOR");
        state = Object.assign({}, state, {
            actor: state.actor.concat([action.payload])
        });
        return state;
    }
    if (action.type === "MINUS_ACTOR") {
        console.warn("发起了action=>MINUS_ACTOR");
        let actor = [].concat(state.actor);
        state = Object.assign({}, state, {
          actor: actor.splice(action.index, 1)
        });
        return state;
    }
    return state;
}
redux 当然提供了的便捷方法 combineReducers().combineReducers()只是生成一个函数 combination,这个函数将调用所有的 reducer,每个 reducer 根据 key 值筛选出 state 的一部分数据进行处理.这个函数再将所有的 reducer 结果合成一个大对象.
import { combineReducers } from "../redux/index";
// 返回一个combination函数
const reducer = combineReducers({
    singer_reducer,
    actor_reducer
});
// console.log(reducer);
此时在 store 中,数据的 key 值会变为 singer_reducer 和 actor_reducer,我们可以通过设置不同 key 来更改在 store 中存放的 key
{
    singerState:singer_reducer,
    actorState:actor_reducer
}
//或者将函数名更改
3. redux 中 store
- store 维护应用的 state
- 提供 getState()方法获取 state
- 提供 dispatch()方法触发 action,更新 state (action->reducer->newState)
- subscribe()注册监听器
- subscribe()返回一个函数用来注销监听器
  
const store = createStore(reducer);
const unsubscribe = store.subscribe(listener);
bound_add_singer_action({
    name: "周华健",
    desc: "一位大帅哥"
});
bound_add_actor_action({
    name: "谢安琪",
    desc: "位小美女"
});
bound_minus_actor_action(1);
unsubscribe();
bound_add_singer_action({
    name: "周杰伦",
    desc: "歌手一枚"
});
bound_add_actor_action({
    name: "周星驰",
    desc: "笑了"
});
function listener() {
    console.log(store.getState());
}
function bound_add_singer_action(payload) {
    return store.dispatch(addSinger_action(payload));
}
function bound_add_actor_action(payload) {
    return store.dispatch(addActor_action(payload));
}
function bound_minus_actor_action(index) {
    return store.dispatch(minusActor_action(index));
}

当我们 shore.dispatch()之后返回的值就是一个用来注销该监听器的 unsubscribe 函数,redux 中源码:
  function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function.')
    }
    let isSubscribed = true
    ensureCanMutateNextListeners()
    <!-- 将listener推入到执行队列中去 -->
    nextListeners.push(listener)
    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }
      isSubscribed = false
      ensureCanMutateNextListeners()
      <!-- 找到监听的listener,并将函数从队列中删除 -->
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号