return ( `Given ${actionDescription}, reducer "${key}" returned undefined. ` + `To ignore an action, you must explicitly return the previous state. ` + `If you want this reducer to hold no value, you can return null instead of undefined.` ) }
functiongetUnexpectedStateShapeWarningMessage( inputState, reducers, action, unexpectedKeyCache ) { const reducerKeys = Object.keys(reducers) const argumentName = action && action.type === ActionTypes.INIT ? 'preloadedState argument passed to createStore' : 'previous state received by the reducer'
if (reducerKeys.length === 0) { return ( 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.' ) }
if (!isPlainObject(inputState)) { return ( `The ${argumentName} has unexpected type of "` + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + `". Expected argument to be an object with the following ` + `keys: "${reducerKeys.join('", "')}"` ) }
if (action && action.type === ActionTypes.REPLACE) return
if (unexpectedKeys.length > 0) { return ( `Unexpected ${unexpectedKeys.length > 1 ? 'keys' : 'key'} ` + `"${unexpectedKeys.join('", "')}" found in ${argumentName}. ` + `Expected to find one of the known reducer keys instead: ` + `"${reducerKeys.join('", "')}". Unexpected keys will be ignored.` ) } }
if (typeof initialState === 'undefined') { thrownewError( `Reducer "${key}" returned undefined during initialization. ` + `If the state passed to the reducer is undefined, you must ` + `explicitly return the initial state. The initial state may ` + `not be undefined. If you don't want to set a value for this reducer, ` + `you can use null instead of undefined.` ) }
if ( typeofreducer(undefined, { type: ActionTypes.PROBE_UNKNOWN_ACTION() }) === 'undefined' ) { thrownewError( `Reducer "${key}" returned undefined when probed with a random type. ` + `Don't try to handle ${ActionTypes.INIT} or other actions in "redux/*" ` + `namespace. They are considered private. Instead, you must return the ` + `current state for any unknown actions, unless it is undefined, ` + `in which case you must return the initial state, regardless of the ` + `action type. The initial state may not be undefined, but can be null.` ) } }) }
// This is used to make sure we don't warn about the same // keys multiple times. let unexpectedKeyCache if (process.env.NODE_ENV !== 'production') { unexpectedKeyCache = {} }
if (typeof reducer !== 'function') { thrownewError('Expected the reducer to be a function.') } /* Step2:定义内部变量 1. 变量1:currentReducer = reducer | 当前的reducer 2. 变量2:currentState = preloadedState | 当前的state:可被getState()获取 3. 变量3:currentListeners = [] | 监听列表 4. 变量4:nextListeners = currentListeners | 监听列表 5. 变量5:isDispatching = false | 是否正在被dispatch(调度) */ let currentReducer = reducer let currentState = preloadedState let currentListeners = [] let nextListeners = currentListeners let isDispatching = false /* ensureCanMutateNextListeners函数: 生成currentListeners的浅拷贝,可以把nextListeners作为临时调度列表 这可以防止消费者调用的任何错误在调度过程中订阅/取消订阅 */ functionensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() } }
/* getState函数 返回当前状态(currentState) */ functiongetState() { /* 获取state的时候必须保证这个reducer已经结束工作了,store已经接收到新的state了,才能调用getState */ if (isDispatching) { thrownewError( 'You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.' ) }
return currentState }
/* subscribe函数:作用是订阅监听 任何时候dispatch一个action都会调用这个函数【一触即发!】 调用action后state object tree的部分可能已经改变了 所以可以再去调用getState()读取回调内的当前状态树 参数说明: - listener:监听到变化后执行的函数,比如subscribe(function() {console.log(1)}) 变化后打印1 返回值说明: - unsubscribe {Fuction}: 返回一个具有取消订阅功能的函数 */ functionsubscribe(listener) { /* listener必须是一个函数 举个例子,listener是一个render函数,调用subscribe就会重新渲染某部分的页面(取决于你的render函数需要render什么) */ if (typeof listener !== 'function') { thrownewError('Expected the listener to be a function.') } /* 同理:获取state的时候必须保证这个reducer已经结束工作了,store已经接收到新的state了,才能调用getState 这也就是说明,顺序是 dispatch action -> state改变 -> 被subscribe(listener) 监听到 -> 获取新的状态 -> listener函数调用 举例: 计时器:dispatch action [目的在于使得value+1] -> value状态改变 -> 被subscribe(render) 监听到 -> 获取新的state -> 重新渲染 */ if (isDispatching) { thrownewError( 'You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' + 'See https://redux.js.org/api-reference/store#subscribelistener for more details.' ) } // Sub-Step1: 设置isSubscribed 为 true let isSubscribed = true // Sub-Step2: (1) 浅复制currentListeners[当前的监听列表],(2) 把监听函数push到监听列表中 ensureCanMutateNextListeners() nextListeners.push(listener)
/* unsubscribe函数:具有取消订阅功能 */ returnfunctionunsubscribe() { // 只有isSubscribed为true的才能被取消订阅 if (!isSubscribed) { return } /* 同理:正在被执行的不能取消订阅 */ if (isDispatching) { thrownewError( 'You may not unsubscribe from a store listener while the reducer is executing. ' + 'See https://redux.js.org/api-reference/store#subscribelistener for more details.' ) } // sub-step3: 修改isSubscribed 为 false isSubscribed = false // sub-step4: 浅复制监听列表 ensureCanMutateNextListeners() // sub-step5: 监听完毕,从列表中删除它 const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) currentListeners = null } } /* dispatch函数:[调度函数] 划重点!回顾:这是改变状态的唯一方法!!!!! 【核心概念2:state只读】 dispatch被调用后,reducer将会被调用,store通过转发dispatch(action) 中包含的previousState和action给redeucer,reducer返回newState给store,React component可以通过getState获取newState 注意:基本实现仅仅支持普通对象的操作,如果的状态是一个Promise Obserable thunk等等,你需要借助与中间件(middleware) 【后面介绍】 参数说明: - action 是一个object,格式为 {type:xxx, data:xxx} 返回值说明: - {Object} 为了方便,返回action对象,但是里面的data是经过更改了 */ functiondispatch(action) { /* isPlainObject函数不贴代码了~看源码的意思,isPlainObject就是用来判断action是不是一个对象 */ if (!isPlainObject(action)) { thrownewError( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } /* 只有定义了action.type才能进行后续操作,所以type不能是undefined */ if (typeof action.type === 'undefined') { thrownewError( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) } /* 正在被dispatch的action不能传入到reducer中处理 */ if (isDispatching) { thrownewError('Reducers may not dispatch actions.') } /* sub-step1: - 切换isDispatching为true - currentState为currentReducer(currentState, action)处理后返回的state reducer函数举例: function currentReducer(state={count:0}, action) => { if (action.type === 'INCREMENT') { return {...state, count: state.count+1} } } 执行完毕后,也就是currentState返回后, 切换isDispatching为false */ try { isDispatching = true currentState = currentReducer(currentState, action) } finally { isDispatching = false } /* sub-step2: 触发listener函数 */ const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action } /* replaceReducer函数:替换store当前使用的reducer来计算 state 不是特别重要,就是替换当前的reducer */ functionreplaceReducer(nextReducer) { if (typeof nextReducer !== 'function') { thrownewError('Expected the nextReducer to be a function.') }
currentReducer = nextReducer
dispatch({ type: ActionTypes.REPLACE }) } /* observable函数: 不重要~暂时不说了 */ functionobservable() { const outerSubscribe = subscribe return { subscribe(observer) { if (typeof observer !== 'object' || observer === null) { thrownewTypeError('Expected the observer to be an object.') }
functionobserveState() { if (observer.next) { observer.next(getState()) } }
functiongetState() { /* 获取state的时候必须保证这个reducer已经结束工作了,store已经接收到新的state了,才能调用getState */ if (isDispatching) { thrownewError( 'You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.' ) }
functionsubscribe(listener) { /* listener必须是一个函数 举个例子,listener是一个render函数,调用subscribe就会重新渲染某部分的页面(取决于你的render函数需要render什么) */ if (typeof listener !== 'function') { thrownewError('Expected the listener to be a function.') } if (isDispatching) { thrownewError( 'You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' + 'See https://redux.js.org/api-reference/store#subscribelistener for more details.' ) } // Sub-Step1: 设置isSubscribed 为 true let isSubscribed = true // Sub-Step2: (1) 浅复制currentListeners[当前的监听列表],(2) 把监听函数push到监听列表中 ensureCanMutateNextListeners() nextListeners.push(listener)
/* unsubscribe函数:具有取消订阅功能 */ returnfunctionunsubscribe() { // 只有isSubscribed为true的才能被取消订阅 if (!isSubscribed) { return } /* 同理:正在被执行的不能取消订阅 */ if (isDispatching) { thrownewError( 'You may not unsubscribe from a store listener while the reducer is executing. ' + 'See https://redux.js.org/api-reference/store#subscribelistener for more details.' ) } // sub-step3: 修改isSubscribed 为 false isSubscribed = false // sub-step4: 浅复制监听列表 ensureCanMutateNextListeners() // sub-step5: 监听完毕,从列表中删除它 const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) currentListeners = null } }
Posted onIn数据处理Symbols count in article: 982Reading time ≈1 mins.
需求1
封装一个函数,用于生成颜色(16进制或者rgba)
传入boolean为true时随机生成颜色的十六进制值,传入false时生成rgba值
需求2
封装一个函数,能够随机生成16进制颜色值,要求使用内部rag值的转换
十六进制颜色特点
0-9 A-F组成(字母不区分大小写)
rgb颜色特点
rgb包含三个参数,分别代表红色、绿色、蓝色
三个参数取值为0-255或者是0%-100%
实现思路
利用Math.random()生成随机数进行取值
实现1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
functiongetRandomColor(bool) { // 生成十六进制 if (bool) { let str = ''; for (let i = 0; i < 6; i++) { // Math.random() 取值为0-1 toString(16)转为16进制 let c = Math.floor(Math.random()*16.toString(16)); str += c; }; return`#${str}` } else { // 生成rgba值 let r = Math.floor(Math.random()*256); let g = Math.floor(Math.random()*256); let b = Math.floor(Math.random()*256); return`rgb(${r}, ${g}, ${b})`; } }
实现2
1 2 3 4 5 6 7 8 9 10 11 12 13 14
functiongetColor16() { let arr = []; for (let i = 0; i < 3; i++) { // 生成r/g/b arr[i] = Math.floor(Math.random()*256); // 16进制转换 arr[i] = arr[i] < 16 ? `0${arr[i].toString(16)}` : arr[i].toString(16); } return'#' + arr.join(''); }
try { await sequelize.authenticate(); console.log('Connection has been established successfully.'); } catch (error) { console.error('Unable to connect to the database:', error); }
// 测试连接 try { sequelize.authenticate(); console.log('Connection has been established successfully.'); } catch (error) { console.error('Unable to connect to the database:', error); }