Hi everyone ??
大家好??
For a while now I’ve been hearing my friends and colleagues complaining about how hard it was to get into Redux.
一段時間以來,我一直在聽我的朋友和同事抱怨進入Redux有多困難。
I run a freeCodeCamp Study Group in the South of Portugal, Faro, so every week I try to motivate and mentor some fellow coders that have a lot of growing pains trying to make their way into programming.
我在葡萄牙南部的法魯(Faro)運營著一個freeCodeCamp研究小組,所以每周我都會激勵和指導一些編碼人員,他們在嘗試進入編程領域時會遇到很多麻煩 。
Dan Abramov created an amazing introduction course to Redux, which I had the pleasure to see in egghead.io, covering all the aspects of Redux. Also the Redux documentation site, here, is very complete.
Dan Abramov為Redux創建了一個很棒的入門課程,我很高興在egghead.io中看到了該課程 ,涵蓋了Redux的所有方面。 Redux文檔站點( 此處 )也非常完整。
But for some reason many people still do not grok Redux.
但是由于某些原因,許多人仍然不喜歡Redux。
The point is that Redux has a considerable entry-level learning curve!
關鍵是Redux具有相當大的入門級學習曲線!
You have to understand a lot of abstractions, you have to do a more functional approach to programming in JavaScript, know a lot of ES6 features and also understand very well a lot of JavaScript concepts such as immutability.
您必須了解很多抽象概念,必須使用一種更具功能性的方法來進行JavaScript編程,必須了解許多ES6功能,并且還必須非常了解很多JavaScript概念,例如不變性。
So, that’s why it might be very difficult for those of you that started React a few months ago and are very enthusiastic to abstract your state into a Redux store.
因此,這就是為什么對于幾個月前開始使用React并熱衷于將您的狀態抽象到Redux商店的人們來說,這可能是很難的。
You hear the chit-chat around the coffee machine of how Redux is acing it, about clean programming, single sources of truth and the three principles that drive this huge ‘tiny’ (2kB) library…
您會聽到關于咖啡機Redux如何處理它的閑聊,有關干凈編程,真理的單一來源以及驅動這個龐大的“小”(2kB)庫的三個原則的信息。
So, no worries, you’ve came to the right place! This article is for you! And I’ll show you with an application first principle approach how easy it is to get the ball rolling with Redux.
因此,不用擔心,您來對地方了! 本文適合您! 我將以應用程序優先的原則向您展示Redux使球滾動變得多么容易。
A lot of ink has already been spilled around this subject, but let’s go. Let me try to introduce you as fast as I can to Mr. Redux in a React context.
關于此主題,已經有很多墨水濺出來,但讓我們開始吧。 讓我嘗試在React上下文中盡快向您介紹Redux先生。
To begin with this herculean task, I’m going to show you how to make a very simple counter application with the following user story:
首先要完成這項艱巨的任務,我將向您展示如何使用以下用戶故事制作一個非常簡單的計數器應用程序:
- display the current count number; 顯示當前計數數字;
- provide the user with two buttons, for incrementing and decrementing the count number. 為用戶提供兩個按鈕,用于增加和減少計數。
Okay, at this point you think: I could do that very quickly with local state.
好的,這時您會認為:我可以使用本地狀態非常快地完成此操作。
True story! And that’s the way, mate! We’re going to start with a simple React example that uses local state and we’re going to transform the app into a React-Redux application.
真實的故事! 就是這樣,伙計! 我們將從一個使用本地狀態的簡單React示例開始,并將該應用轉換為React-Redux應用。
But, before that, let me introduce you the basic concepts and purposes of Redux in a quick intro.
但是,在此之前,讓我快速向您介紹Redux的基本概念和目的。
01.基本概念 (01. Basic concepts)
Redux was created by Dan Abramov, and it’s defined as a “predictable state container for JavaScript apps.”
Redux是由Dan Abramov創建的,它被定義為“ JavaScript應用程序的可預測狀態容器”。
The motivation for Dan to create Redux was that SPA complexity was increasing a lot. And we were left alone to manage the state of our data with two difficult concepts for the human mind to reason about: mutation and asynchronicity. He calls them “Mentos and Coke — Both can be great in separation, but together they create a mess”.
Dan創建Redux的動機是SPA的復雜性大大增加。 而且,我們不得不用兩個難以理解的概念來管理我們的數據狀態,這是人類頭腦中不可思議的概念: 突變和異步性 。 他稱它們為“ Mentos和可樂 -兩者的分離效果很好,但在一起卻造成混亂”。
So Redux proposes to describe the whole state of your app as a plain object. To change something in state you need to dispatch actions. Actions are plain Javascript objects that describe what happened to your app.
因此,Redux建議將應用程序的整個狀態描述為一個普通對象。 要更改狀態,您需要調度動作。 操作是描述您的應用程序發生了什么的簡單Javascript對象。
In the end, to tie actions and state together we write a function called a reducer. A reducer is just a Javascript function that takes state and action as arguments and returns the next state of the app.
最后,為了將動作和狀態聯系在一起,我們編寫了一個稱為reducer的函數。 reducer只是一個Javascript函數,它以狀態和操作作為參數并返回應用程序的下一個狀態。
Redux的三項原則: (Three Principles of Redux:)
Single source of truth: the state of your whole app is stored in an object tree within a single store.
單一事實來源:整個應用程序的狀態存儲在單個商店內的對象樹中。
State is read-only. This means that the only way to change the state is to emit an action (an object describing what happened).
狀態為只讀。 這意味著更改狀態的唯一方法是發出一個動作 (一個描述發生了什么的對象)。
Changes are made with pure functions. Pure functions are functions that return a value only depending on the value of its arguments. They have no observably side-effects. When you call the same function with the same argument you always get the same return value. Pure functions also do not modify the arguments they receive. They actually return a new object, array, or function with the changes made to it.
使用純函數進行更改。 純函數是僅根據其參數值返回值的函數。 它們沒有明顯的副作用。 當您使用相同的參數調用相同的函數時,您始終會獲得相同的返回值。 純函數也不會修改它們接收的參數。 他們實際上返回具有更改的新對象,數組或函數。
02.計數器應用程序(以本地狀態進行響應,此處沒有Redux) (02. The Counter App (React with local state, no Redux here))
Okay mates, getting back to where we were coming from, let’s make our small counter app with local state only.
好的伙伴們,回到我們的家鄉,讓我們讓小型計數器應用程序僅具有本地狀態。
To start these kind of boilerplates I always use create-react-app (CRA) with bootstrap (just to get things simple but a little bit more fancy).
為了開始這類樣板,我總是使用帶有引導程序的create-react-app(CRA)(只是為了使事情變得簡單,但花哨的多一點)。
I kept the src/index.js which calls the <App /> component (playing the role of the main App view) and I’ve created a small stateful component called Counter.
我保留了src / index.js來調用<App />組件(扮演App主視圖的角色),并且創建了一個名為Counter的小型有狀態組件。
If you wanna play with the code you can clone it from my GitHub repo here (keep in mind that it’s on the branch LocalStateApp).
如果您想使用該代碼,可以在這里從我的GitHub存儲庫中克隆它(請記住,它位于分支LocalStateApp上)。
So, let’s take a look at what we need to build our simple App.
因此,讓我們看一下構建簡單應用程序所需的內容。
As simple as it is out-of-the-box.
開箱即用就這么簡單。
I start my App Component initialising the state with a count variable which by default is set to zero.
我使用一個count變量初始化狀態來啟動我的App Component,默認將其設置為零。
I’ve built a very simple render method which destructures the count from state and shows some text. It also invokes the Counter stateful component passing the count value into it, and calls a small method called renderButtons() to render the increment/decrement buttons.
我建立了一個非常簡單的渲染方法,該方法從狀態中解構計數并顯示一些文本。 它還調用將有計數值傳遞到其中的Counter有狀態組件,并調用一個名為renderButtons()的小方法來呈現遞增/遞減按鈕。
Buttons call a method called updateCounter() and pass into it the type of update we want.
按鈕調用一個名為updateCounter()的方法,并將所需的更新類型傳遞給該方法。
Here we are already building our way into Redux. One detail of actions in Redux is that, besides being simple objects that are up to you, they need to have a type property which is not undefined. (Just keep this in mind for now.)
在這里,我們已經在建立進入Redux的方式。 Redux中操作的一個細節是,除了是由您自己決定的簡單對象外,它們還需要具有一個不確定的type屬性。 (現在請記住這一點。)
So here we have our updateCounter method which is very similar to what a reducer is in Redux. It gets the current state of the app, it gets the action wanted, and in the end it returns the new state of your app.
因此,這里有updateCounter方法,該方法與Redux中的reducer非常相似。 它獲取應用程序的當前狀態,獲取所需的操作,最后返回應用程序的新狀態。
No magic at all! Redux is so natural and easy that you won’t feel the difference at all since you know two or three little details that make things seem very complex and hard to grok.
根本沒有魔術! Redux非常自然和容易,您幾乎不會感覺到差異,因為您知道兩個或三個小細節,這些細節使事情看起來非常復雜且難以理解。
This is the final result of our app:
這是我們應用程序的最終結果:
03.計數器應用程序(帶有Redux狀態) (03. The Counter App (w/Redux State))
Okay friends! Let’s break down what we’ve done till now.
好的朋友! 讓我們分解到現在為止的工作。
To install Redux you have to do:
要安裝Redux,您必須執行以下操作:
npm install --save redux react-redux
npm install-保存redux react-redux
So after installing Redux your package.json dependencies should look like this ?.
因此,在安裝Redux之后,您的package.json依賴項應如下所示?
Now what?
怎么辦?
Let’s break our app! But not too much! ?
讓我們打破我們的應用程序! 但是不要太多! ?
So my first step will be to remove the state from the App Component and create a Redux store on index.js:
因此,我的第一步是從應用程序組件中刪除狀態,并在index.js上創建Redux存儲:
What have we done here? ??
我們在這里做了什么? ??
We’ve edited our main index.js file to create a Redux Store and pass it as a prop into our <App /> Component.
我們已經編輯了主要的index.js文件,以創建一個Redux商店,并將其作為道具傳遞到我們的<App />組件中。
You might notice the two imports on the top: Provider and createStore.
您可能會注意到頂部的兩個導入:Provider和createStore。
You shall also notice the usage of the HOC <Provider> around <App/>. It works from the outside embracing our main app (it can also embrace Router stuff) in order to pass its API functions as props into our main App.
您還將注意到<App />周圍的HOC <Provider>的用法。 它從外部擁抱我們的主應用程序(它也可以包含路由器的東西),以便將其API函數作為道具傳遞到我們的主應用程序中。
But wait!
可是等等!
What is the reducer in this variable definition?
這個變量定義中的reducer是什么?
Oh, we’re missing the reducer!
哦,我們缺少減速器!
So the store needs to receive at least one reducer function to actually know how changes to the state operate.
因此,商店需要接收至少一個reducer函數,才能真正知道狀態更改的操作方式。
Let’s do it!
我們開始做吧!
In our old app we had that updateCounter method that we said was kind of a reducer.
在我們的舊應用中,我們有一個updateCounter方法,我們說它是一個簡化器。
So let’s move it to index.js (you can also extract it to another file and import it but let’s keep things simple for now).
因此,讓我們將其移至index.js(您也可以將其提取到另一個文件中并導入,但現在讓我們保持簡單)。
So we’ve extracted the updateCounter method from our App Component and we tweaked it a bit to give it some more context.
因此,我們從應用程序組件中提取了updateCounter方法,并對其進行了一些微調以提供更多上下文。
We’ve called it reducer. It’s the reducer we want to pass into the createStore method.
我們稱之為減速器。 這是我們要傳遞給createStore方法的reducer。
We’ve also added state as an argument because when we’ve extracted it from the <App /> Component context, it is not aware of any state anymore. We also stopped using setState and started to return the new count according to the action type we’re receiving (destructured it from the action arg).
我們還添加了狀態作為參數,因為當從<App /> Component上下文中提取狀態時,它不再知道任何狀態。 我們也停止使用setState并開始根據接收到的操作類型返回新計數(從操作arg對其進行了結構分解)。
We’ve used ES6 features to define an initialState by default if state is undefined. Remember what I told you above ?, that state couldn’t be undefined. It is one of Redux reducer’s conditions.
如果狀態未定義,我們默認使用ES6功能來定義initialState。 還記得我在上面告訴您的內容嗎,狀態不能不確定。 這是Redux減速器的條件之一。
Besides that, nothing new everyone! Guess what? We have our reducer set and ready to do its job!
除此之外,沒有什么新鮮的大家! 你猜怎么了? 我們已準備好減速機,并準備好工作了!
Now let’s pay attention to the actions!
現在讓我們注意動作!
In our old app they were the updateCounter invocation. But now as you remember we need to use the dispatch() method from Redux to dispatch actions so we need to add this layer of the API to our app.
在我們的舊應用中,它們是updateCounter調用。 但是現在您還記得,我們需要使用Redux中的dispatch()方法來分派操作,因此我們需要將API的這一層添加到我們的應用程序中。
We’ve tweaked only two things folks! We’ve got the dispatch method, destructuring it from the props. Remember the <Provider /> HOC? Its role is to introduce these few Redux methods into your main app.
我們只調整了兩件事! 我們已經有了調度方法,可以從道具中將其破壞。 還記得<Provider /> HOC嗎? 它的作用是將這幾種Redux方法引入您的主應用程序。
Instead of calling this.updateCounter we are now calling an updateCounter detached function supplying to it the action type (as we already were in the old app).
現在,我們不再調用this.updateCounter,而是調用一個updateCounter分離函數,向其提供操作類型(就像我們在舊應用程序中一樣)。
Let’s now see what’s the new updateCounter function:
現在,讓我們看看新的updateCounter函數是什么:
Okay, nothing new, we just receive the dispatch method and return it with the type of action we want to fire.
好的,沒什么新鮮的,我們只接收dispatch方法,并以我們要觸發的操作類型返回它。
At this time we’ve already created the store. We’ve created the reducer to grab the previous state of the app and the action and return the new state. We’ve built an action function to dispatch our app actions.
目前,我們已經創建了商店。 我們已經創建了reducer來獲取應用程序和操作的先前狀態并返回新狀態。 我們已經構建了一個動作函數來調度我們的應用動作。
What more? This should be working by now! Why it is not?
還有什么? 現在應該可以工作了! 為什么不是呢?
Ohhh! Our App Component must be connected to Redux!
哦! 我們的應用程序組件必須連接到Redux!
So this is our final step everyone! ?
因此,這是我們所有人的最后一步! ?
We start by importing the connect method from react-redux (into our App.js file).
我們首先從react-redux導入connect方法(到我們的App.js文件中)。
Now at the end of our file, where we do the export default app of our component, we need to do the connection:
現在,在文件末尾,我們在其中執行組件的導出默認應用程序,我們需要進行連接:
Okay! Remember we’ve removed the local state from our App component?
好的! 還記得我們已經從我們的App組件中刪除了本地狀態嗎?
So… how do we inject the state of the store into our component?
那么……我們如何將商店的狀態注入到我們的組件中?
We need to do a “mapStateToProps”! Get used to this because it will always be needed. App component will receive the new state as a prop. You have no this.state anymore!!
我們需要做一個“ mapStateToProps”! 習慣這一點,因為將始終需要它。 應用組件將接收新狀態作為道具。 您沒有this.state了!
mapStateToProps grabs the state from the connect method (HOC) and binds it to App Component.
mapStateToProps從connect方法(HOC)中獲取狀態并將其綁定到App Component。
And that’s it everyone! By this time your app should be running.
就是每個人! 到此時,您的應用程序應已運行。
Feel free to take a look at the code in my GitHub repo (branch ReduxStateApp) here.
請在此處隨意查看我的GitHub存儲庫(分支ReduxStateApp)中的代碼。
Of course there’s a lot of things to learn after this, but this is the main first step for you to understand how to get the ball rolling with Redux.
當然,此后還有很多事情要學習,但這是您了解如何使Redux發揮作用的主要第一步。
Now I ask you to do the homework: check out the two apps! Make sure you grok all the steps and compare them. Put a lot of console.log to understand what’s going on, and above all accept that there’s an API in Redux that has a few but strict rules. Not everything is so logical for an entry-level as it’s expected to be! But those are only good growing pains for the sake of JavaScript!
現在,我要求您做作業:檢查這兩個應用程序! 確保您完成所有步驟并進行比較。 放很多console.log來了解發生了什么,最重要的是,Redux中有一個API,它有一些但嚴格的規則。 對于入門級而言,并非所有事情都像預期的那樣合理! 但是,僅出于JavaScript的考慮,這些只是長大的痛苦!
Always remember to Be Strong and Code On everyone ??
永遠記住要堅強并為每個人編碼??
And keep your pain in check with a good and hot ?? ?
并通過好又熱的???來控制疼痛
04.參考書目 (04. Bibliography)
01. Redux Docs
01. Redux文檔
02. egghead.io Dan Abramov’s course on Getting Started With Redux
02. egghead.io Dan Abramov的Redux入門課程
翻譯自: https://www.freecodecamp.org/news/redux-get-the-ball-rolling-in-10min-9d9551ff4b3c/