Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is createStore in Redux Source Code parsing Series

2025-04-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "what is createStore in the Redux source code parsing series". Interested friends may wish to have a look. The method introduced in this paper is simple, fast and practical. Next let the editor to take you to learn "Redux source code parsing series of what is createStore"!

INIT

This method is reserved by redux to initialize the state of reducer

Export const ActionTypes = {INIT:'@ @ redux/INIT'}

The function of createStore is to create a store to manage the state of app. The only way to change the state is to dispatch an action and finally return an object.

Return {dispatch, subscribe, getState, replaceReducer, [$observable]: observable}

However, replaceReducer and [$observable]: are not commonly used, so only the first three interfaces are parsed here.

CreateStore

In an app, there can be only one store. If you want to specify that different state corresponds to different action, you can use combineReducers to merge different reducer.

Parameters:

Reducer (function): by passing in the current State, as well as action, the next state is calculated and returned.

PreloadedState (any): initial state

Enhancer (function): enhance the function of store so that it has third-party functions. For example, the only enhancer in middleware.Redux is applyMiddleware ()

Export default function createStore (reducer, preloadedState, enhancer) {/ / the first paragraph says that when the second parameter does not pass preloadedState, but directly passes function You will directly think of this function as enhancer if (typeof preloadedState = = 'function' & & typeof enhancer = =' undefined') {enhancer = preloadedState preloadedState = undefined} / / when the third parameter is passed, but not function will report an error if (typeof enhancer! = = 'undefined') {if (typeof enhancer! = =' function') {throw new Error ('Expected the enhancer to be a function.')} / / this is the key. In the previous article on applyMiddleware, I introduced the significance of doing this. / / it actually does the thing of createStore in applyMiddleware and transfers the pot. Return enhancer (createStore) (reducer, preloadedState)} if (typeof reducer! = = 'function') {throw new Error (' Expected the reducer to be a function.')} let currentReducer = reducer let currentState = preloadedState let currentListeners = [] let nextListeners = currentListeners let isDispatching = false}

Above is the first part, and after verifying that the parameters are correct, you can finally do something serious. CreateStore will eventually return an Object.

{dispatch, subscribe, getState}

Let's take a look at what's going on inside:

GetState

The function of getState is to return the current state status. There is nothing to say.

Function getState () {return currentState}

Subscribe

What it does: add the listening function listener, which is called every time you dispatch action.

Parameter: listener (function): the function that is called every time dispatch action

Return: returns a function that removes listener

/ / the function is to make a shallow copy of the nextListeners,nextListeners if it is found pointing to the same stack. In this way, changing nextListeners will not change to currentListeners function ensureCanMutateNextListeners () {if (nextListeners = nextListeners) {nextListeners = currentListeners.slice ()}} function subscribe (listener) {if (typeof listener! = = 'function') {throw new Error (' Expected listener to be a function.')} let isSubscribed = true ensureCanMutateNextListeners () / / directly put the listening function into nextListeners nextListeners.push (listener) return function unsubscribe () {/ / if it has been removed, return if (! isSubscribed) {return} isSubscribed = false ensureCanMutateNextListeners () / / if it has not been removed First find the location and remove const index = nextListeners.indexOf (listener) nextListeners.splice (index, 1)}} via splice

When you use it, you can:

Const unsubscribe = store.subscribe (()) = > console.log (store.getState ()) unsubscribe () dispatch

Dispatch

Dispatch as a key function ~ in fact, its function is to trigger a change of state.

Parameter: action (object), which is an object that describes what happened, where type is a required attribute.

Return: this incoming object

Function dispatch (action) {if (! isPlainObject (action)) {throw new Error ('Actions must be plain objects. '+' Use custom middleware for async actions.')} / / if (typeof action.type = 'undefined') {throw new Error (' Actions may not have an undefined "type" property. '+' Have you misspelled a constant?')} / / prevent multiple dispatch requests from changing their status at the same time, which must be after the end of the previous dispatch Dispatch the next if (isDispatching) {throw new Error ('Reducers may not dispatch actions.')} try {isDispatching = true currentState = currentReducer (currentState, action)} finally {isDispatching = false} / / when dispatch, assign nextListeners back to currentListeners, const listeners = currentListeners = nextListeners for (let I = 0 I

< listeners.length; i++) { const listener = listeners[i] listener() } return action } 在上面一系列完成之后,需要初始化appState的状态。当INIT action被dispatched 的时候,每个reducer都会return回它的初始状态。 dispatch({ type: ActionTypes.INIT }) 自问自答环节 为什么createStore中既存在currentListeners也存在nextListeners? 在上面的源码中,createStore函数为了保存store的订阅者,不仅保存了当前的订阅者currentListeners而且也保存了nextListeners。createStore中有一个内部函数ensureCanMutateNextListeners: function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() } } 这个函数实质的作用是确保可以改变nextListeners,如果nextListeners与currentListeners一致的话,将currentListeners做一个拷贝赋值给nextListeners,然后所有的操作都会集中在nextListeners,比如我们看订阅的函数subscribe: function subscribe(listener) { // ...... let isSubscribed = true ensureCanMutateNextListeners() nextListeners.push(listener) return function unsubscribe() { // ...... ensureCanMutateNextListeners() const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) } 我们发现订阅和解除订阅都是在nextListeners做的操作,然后每次dispatch一个action都会做如下的操作: function dispatch(action) { try { isDispatching = true currentState = currentReducer(currentState, action) } finally { isDispatching = false } // 相当于currentListeners = nextListeners const listeners = currentListeners const listeners = currentListeners = nextListeners for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action } 我们发现在dispatch中做了const listeners = currentListeners = nextListeners,相当于更新了当前currentListeners为nextListeners,然后通知订阅者,到这里我们不禁要问为什么要存在这个nextListeners? 其实代码中的注释也是做了相关的解释: The subscriptions are snapshotted just before every dispatch() call.If you subscribe or unsubscribe while the listeners are being invoked, this will not have any effect on the dispatch() that is currently in progress.However, the next dispatch() call, whether nested or not, will use a more recent snapshot of the subscription list. 来让我这个六级没过的渣渣翻译一下: 订阅者(subscriptions)在每次dispatch()调用之前都是一份快照(snapshotted)。如果你在listener被调用期间,进行订阅或者退订,在本次的dispatch()过程中是不会生效的,然而在下一次的dispatch()调用中,无论dispatch是否是嵌套调用的,都将使用最近一次的快照订阅者列表。用图表示的效果如下: 我们从这个图中可以看见,如果不存在这个nextListeners这份快照的话,因为dispatch导致的store的改变,从而进一步通知订阅者,如果在通知订阅者的过程中发生了其他的订阅(subscribe)和退订(unsubscribe),那肯定会发生错误或者不确定性。例如:比如在通知订阅的过程中,如果发生了退订,那就既有可能成功退订(在通知之前就执行了nextListeners.splice(index, 1))或者没有成功退订(在已经通知了之后才执行了nextListeners.splice(index, 1)),这当然是不行的。因为nextListeners的存在所以通知订阅者的行为是明确的,订阅和退订是不会影响到本次订阅者通知的过程。 还是看不懂是什么意思?????一个简单粗俗的例子: 当在执行这段代码到第三个listener的时候: for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } 你突然把第2个listener给splice了。这样的话此时上面的循环本来是执行完第三个要执行第四个了,但是由于数组中的第2个listener被splice掉了,所以数组后面的元素都要往前移动一个位置,这时数组的第四个listener就移动到原先第三个的位置了,数组的第五个listener就移动到原先第四个的位置了,因此循环本要执行第四个的,结果由于第四个往前移动了,实际执行的是原先的第五个,所以导致原先的第四个没有被执行。。 没错,上面讲的就是这样的!!!!哈哈哈明白了吧!!!! 但是这里又有一个问题了: JavaScript不是单线程的吗?为啥在执行循环的时候,会执行unsubscribe()操作 百思不得其解的情况下,去Redux项目下开了一个issue,得到了维护者的回答:

Come on, let's take a look at the test-related code again. After reading it, I learned. Indeed, because JavaScript is a single-threaded language, it is impossible to have a multi-threaded scenario like the one mentioned above, but I overlooked the fact that when the subscriber function is executed, unsubscribe or subscription events can be performed in this callback function. For example:

Const store = createStore (reducers.todos) const unsubscribe1 = store.subscribe (() = > {const unsubscribe2 = store.subscribe (() = > {})})

Doesn't this make it possible to mix subscription subscribe and unsubscribe unsubscribe in the process of notifying listener?

Why can't dispatch operations be performed in Reducer?

We know that dispatch operations cannot be performed in reducer functions. On the one hand, reducer, as a pure function for calculating the next state, should not undertake to perform operations like dispatch. On the other hand, even if you try to execute dispatch in reducer, it will not succeed and you will get "Reducers may not dispatch actions." A hint. Because the restrictions are made in the dispatch function:

Function dispatch (action) {if (isDispatching) {throw new Error ('Reducers may not dispatch actions.')} try {isDispatching = true currentState = currentReducer (currentState, action)} finally {isDispatching = false} / /. Notice listener}

The flag bit isDispatching is set to true when the dispatch is executed. Then if dispatch is executed by currentReducer (currentState, action), an error ('Reducers may not dispatch actions.') is thrown. The reason for this restriction is that the execution of reducer is caused in dispatch, and if dispatch is executed in reducer at this time, it falls into an endless loop, so avoid executing dispatch in reducer.

At this point, I believe that everyone on the "Redux source code parsing series of what is createStore" have a deeper understanding, might as well to the actual operation of it! Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report