import invariant from './utils/invariant';
/**
* Utilities to perform atomic operation with navigate state and routes.
*
* 对导航状态和路由执行原子操作的工具方法
*
* 导航状态可以理解成这样一个对象 :
* 1. 拥有一个属性 路由栈 routes, 是一个即是数组又是栈的数据结构,用于跟踪记录用户对屏幕的访问,栈中的每个元素,也就是栈的一帧,
* 表示一个路由(可以是一个普通屏幕组件,也可以是一个嵌套的路由器);对路由栈的操作可以是压栈出栈,也可以不是压栈出栈而只是更新
* index 指向另外一个存在于路由栈中的路由;
* 2. 拥有一个属性 当前路由索引 index, 表示当前活跃路由,指向路由栈中的某一个路由,也就是当前路由器作为活跃屏幕渲染的子路由;
* 3. 当前路由索引 index 并不总是指向路由栈的栈顶:
* 3.1 如果仅仅使用 PUSH/POP 操作,当前路由索引 index 总是指向路由栈栈顶;
* 3.2 如果不仅仅使用 PUSH/POP 操作,还是用 jumpXXX/forward 之类的操作, 当前路由索引 index 就不一定指向路由栈栈顶;
*
* 一个路由器定义的时候被提供了各种配置信息:路由配置,导航配置,而在路由器实例化的时候,其导航状态对象会被创建,该导航状态的
* 初始值一般是这样的 :
* 1. index 为 0;
* 2. routes 为1个元素的数组,这个元素指向该路由器的初始路由(可以是普通屏幕组件,也可以是嵌套的路由器);
*
* ```javascript
* const state1 = {key: 'screen 1'};
* const state2 = NavigationStateUtils.push(state1, {key: 'screen 2'});
* ```
*/
const StateUtils = {
/**
* 获取状态对象的路由栈中 key 属性等于参数 key 的路由
* Gets a route by key. If the route isn't found, returns `null`.
* @param state
* @param key
* @return {*|null} 如果没有找到,返回null
*/
get(state, key) {
return state.routes.find(route => route.key === key) || null;
},
/**
*
* 获取状态对象的路由栈中 key 属性等于参数 key 的路由的索引(栈底路由的索引为0)
* Returns the first index at which a given route's key can be found in the
* routes of the navigation state, or -1 if it is not present.
*
* @param state
* @param key
* @return {*} 如果没找到,返回 -1
*/
indexOf(state, key) {
return state.routes.map(route => route.key).indexOf(key);
},
/**
*
* 检查是否有 key 属性等于参数 key 的路由存在于当前路由栈中
*
* Returns `true` at which a given route's key can be found in the
* routes of the navigation state.
*
* @param state
* @param key
* @return {boolean} `true` 表示存在,`false` 表示不存在
*/
has(state, key) {
return !!state.routes.some(route => route.key === key);
},
/**
* 新的路由压入到路由栈的栈顶,然后 导航状态对象的属性 index 被更新指向路由栈顶路由
*
* 注意 : 听起来PUSH是一个修改操作,但实际上,该方法是基于原导航状态对象和新的待压入路由,
* 构造了一个新的导航状态对象(index + 新的路由栈)
*
* @return 动作完成后新建的导航状态对象
*
* Pushes a new route into the navigation state.
* Note that this moves the index to the positon to where the last route in the
* stack is at.
*/
push(state, route) {
invariant(
StateUtils.indexOf(state, route.key) === -1,
'should not push route with duplicated key %s',
route.key
);
const routes = state.routes.slice();
routes.push(route);
return {
...state,
index: routes.length - 1,
routes,
};
},
/**
*
* 从当前导航状态对象的路由栈顶部弹出一个路由,然后 导航状态对象的属性 index 被更新指向路由栈顶路由
*
* 注意 : 听起来POP是一个修改操作,但实际上,该方法是基于原导航状态对象,构造了一个新的导航状态对象(index + 新的路由栈)
*
* @return 动作完成后新建的导航状态对象
* Pops out a route from the navigation state.
* Note that this moves the index to the positon to where the last route in the
* stack is at.
*/
pop(state) {
if (state.index <= 0) {
// [Note]: Over-popping does not throw error. Instead, it will be no-op.
return state;
}
const routes = state.routes.slice(0, -1);
return {
...state,
index: routes.length - 1,
routes,
};
},
/**
*
* 没有路由出栈也没有压栈操作,只是当前路由索引index更新到参数index指定的某个路由,
*
*
* @return 动作完成后新建的导航状态对象(如果目标路由和当前路由是同一个路由,则直接返回原路由状态对象)
*
* Sets the focused route of the navigation state by index.
*/
jumpToIndex(state, index) {
if (index === state.index) {
return state;
}
invariant(!!state.routes[index], 'invalid index %s to jump to', index);
return {
...state,
index,
};
},
/**
*
* 没有路由出栈也没有压栈操作,只是当前路由索引index更新到参数key指定的某个路由,
*
* @return 动作完成后新建的导航状态对象(如果目标路由和当前路由是同一个路由,则直接返回原路由状态对象)
*
* Sets the focused route of the navigation state by key.
*/
jumpTo(state, key) {
const index = StateUtils.indexOf(state, key);
return StateUtils.jumpToIndex(state, index);
},
/**
* 返回操作,修改当前路由index指向导航栈中当前路由下面的那个路由,
*
* @return 动作完成后新建的导航状态对象(如果当前路由路由栈中只有一个路由,那么什么都不做,返回原导航状态对象)
*
* Sets the focused route to the previous route.
*/
back(state) {
const index = state.index - 1;
const route = state.routes[index];
return route ? StateUtils.jumpToIndex(state, index) : state;
},
/**
* 前进操作,修改当前路由index指向路由栈中当前路由上面的那个路由,
*
* @return 动作完成后新建的导航状态对象(如果当前路由已经是栈顶路由,那么什么都不做,返回原导航状态对象)
*
* Sets the focused route to the next route.
*/
forward(state) {
const index = state.index + 1;
const route = state.routes[index];
return route ? StateUtils.jumpToIndex(state, index) : state;
},
/**
* 将导航状态 state 的路由栈中 key 指定的路由替换成 route 指定的路由信息,
* 并将导航状态 state 的当前路由索引 index 指向该路由
*
* @return 动作完成后新建的导航状态对象(如果待替换路由和参数路由其实是一个对象,那么什么都不做,返回原导航状态对象)
*
* Replace a route by a key.
* Note that this moves the index to the positon to where the new route in the
* stack is at.
*/
replaceAt(state, key, route) {
const index = StateUtils.indexOf(state, key);
return StateUtils.replaceAtIndex(state, index, route);
},
/**
*
* 将导航状态 state 的路由栈中 index 指定的路由替换成 route 指定的路由信息,
* 并将导航状态 state 的当前路由索引 index 指向该路由
*
* @return 动作完成后新建的导航状态对象(如果待替换路由和参数路由其实是一个对象,那么什么都不做,返回原导航状态对象)
*
* Replace a route by a index.
* Note that this moves the index to the positon to where the new route in the
* stack is at.
*/
replaceAtIndex(state, index, route) {
invariant(
!!state.routes[index],
'invalid index %s for replacing route %s',
index,
route.key
);
if (state.routes[index] === route) {
return state;
}
const routes = state.routes.slice();
routes[index] = route;
return {
...state,
index,
routes,
};
},
/**
* 将导航状态对象 state 复位为参数 routes 和 index 指定的信息,
* 其实可以理解为使用 routes 和 index 重新构建一个新的导航状态对象
*
* @return 动作完成后新建的导航状态对象(如果原状态对象和目标状态对象相等,那么什么都不做,返回原导航状态对象)
* Resets all routes.
* Note that this moves the index to the positon to where the last route in the
* stack is at if the param `index` isn't provided.
*/
reset(state, routes, index) {
invariant(
routes.length && Array.isArray(routes),
'invalid routes to replace'
);
const nextIndex = index === undefined ? routes.length - 1 : index;
// 如果原来状态对象和将要设置的属性(index,路由栈)相等,则之间返回原状态对象
if (state.routes.length === routes.length && state.index === nextIndex) {
// 原状态对象的index和目标状态对象的index相等
const compare = (route, ii) => routes[ii] === route;
if (state.routes.every(compare)) {
// 原状态对象的路由栈和目标状态对象的路由栈相等:
// 1. 栈中路由数量相等;
// 2. 每一帧按顺序比较也相等;
return state;
}
}
invariant(!!routes[nextIndex], 'invalid index %s to reset', nextIndex);
return {
...state,
index: nextIndex,
routes,
};
},
};
export default StateUtils;
React Navigation源代码阅读 :StateUtils.js
猜你喜欢
转载自blog.csdn.net/andy_zhang2007/article/details/80313413
今日推荐
周排行