by Mark Hopson
馬克·霍普森(Mark Hopson)
如何使用React和Redux前端(加上Typescript!)創建Rails項目 (How to create a Rails project with a React and Redux front-end (plus Typescript!))
在Rails項目中使用React和Redux設置單頁Javascript App的完整指南。 (A complete guide to setting up a single-page Javascript App with React and Redux inside a Rails project.)
Update (Mar 17, 2019): Added Typescript to the last step of this project.
更新(2019年3月17日):在此項目的最后一步中添加了打字稿 。
This tutorial will show you how to create a single-page app with React (and Redux and Semantic UI) inside a Rails project.
本教程將向您展示如何在Rails項目中使用React(以及Redux和Semantic UI )創建單頁應用程序 。
This tutorial will also include:
本教程還將包括:
Redux
Redux
React Router
React路由器
Reselect
重新選擇
Redux Think
Redux Think
Semantic UI
語義UI
Side note #1. I saw this wonderful guide recently and it inspired me to write one for Rails.
旁注1。 我最近看到了這個很棒的指南 ,它啟發了我為Rails編寫指南 。
Side note #2. Here is the finished tutorial. The commit history corresponds (kind of) with the steps in this guide.
旁注2。 這是完成的教程 。 提交歷史記錄與本指南中的步驟相對應(類似)。
總覽 (Overview)
To give you a sense of what we’re going to build and how things will work, see the 2 diagrams below.
為了讓您大致了解我們將要構建的內容以及它們將如何工作,請參見下面的2個圖表。
圖1:處理第一個HTTP請求(即,從瀏覽器到我們的Rails App的請求) (Diagram 1: Handling the first HTTP request (i.e. requests from the browser to our Rails App))
The diagram below illustrates your React App inside your Rails project, and the path (solid black line) that the first request takes to return the React App back to the client (browser).
下圖說明了Rails項目中的React App,以及第一個請求將React App返回給客戶端(瀏覽器)的路徑(實線)。
圖2:處理后續的HTTP請求(即,從我們的React App到Rails App的請求) (Diagram 2: Handling subsequent HTTP requests (i.e. requests from our React App to our Rails App))
After the React App is loaded in the user’s browser, the React App will be responsible for sending requests to your Rails App (solid black line). In other words, once React is loaded, requests to Rails will come from Javascript code, and not the browser.
在用戶瀏覽器中加載React App之后,React App將負責向您的Rails App發送請求(黑色實線)。 換句話說,一旦React被加載,對Rails的請求將來自Javascript代碼,而不是瀏覽器。
開始編碼之前的其他重要說明 (Other Important notes before we start coding)
- Think of your React App as being separate from your Rails App. The React App is strictly for the front-end and runs in the user’s browser. The Rails part is strictly for the back-end and runs on the server. The Rails App does not know anything about the React App except for when to return its static assets (Webpack compiled HTML, JS, and CSS). 將您的React App與Rails App分開。 React App嚴格用于前端,并在用戶的瀏覽器中運行。 Rails部分嚴格用于后端,并在服務器上運行。 除了何時返回靜態資產(Webpack編譯HTML,JS和CSS)外,Rails應用程序對React應用程序一無所知。
- Once your React App is loaded by your browser, all the logic to make HTTP requests (retrieve data, and turn that data into a view) is done in the front-end (i.e. browser). 一旦瀏覽器加載了您的React App,所有發出HTTP請求(檢索數據并將其轉換為視圖)的邏輯都在前端(即瀏覽器)中完成。
Your Rails App effectively does not serve any views except for the one that serves your React App. In this tutorial, the only Rails view is
/app/views/static/index.html.erb
除了為您的React App提供服務的視圖外,您的Rails應用程序實際上不會提供任何視圖。 在本教程中,唯一的Rails視圖是
/app/views/static/index.html.erb
All
/api/*
paths gets handled by the Rails App, while all other paths gets handled by React inside the browser (after your browser has loaded the first request). For example,http://your-app.com/something
will be sent to the Rails App, and then returned back to your React App (the HTML/JS/CSS that has already loaded in the browser), which will decide what to show on the screen.所有
/api/*
路徑均由Rails App處理,而其他所有路徑均由瀏覽器內部的React處理(在瀏覽器加載第一個請求之后)。 例如,http://your-app.com/something
將被發送到Rails App,然后返回到您的React App(已經在瀏覽器中加載HTML / JS / CSS),這將決定顯示在屏幕上。Considerations for building a single-page app. Not necessary for this tutorial but useful.
構建單頁應用程序的注意事項 。 本教程不是必需的,但很有用。
React Component design patterns. Again, not necessary but useful.
React組件設計模式 。 同樣,沒有必要,但有用。
系統要求 (System Requirements)
FYI here’s my system config. Not saying you need this, but something similar will make this tutorial experience smoother.
僅供參考,這是我的系統配置。 并不是說您需要這樣做,但是類似的操作會使本教程的體驗更流暢。
- macOS 10.13.6 (High Sierra) macOS 10.13.6(High Sierra)
- Ruby 2.5.1 Ruby 2.5.1
- Rails 5.2.1 (and Bundler 1.16.6) Rails 5.2.1(和Bundler 1.16.6)
- - gem install bundler -v 1.16.6 -gem install bundler -v 1.16.6
- Node 9.8.0 節點9.8.0
Finally, on to the code!
最后,繼續執行代碼!
第1步:使用Webpack和React創建一個新的Rails項目 (Step 1: Create a new Rails project with Webpack and React)
Create a new Rails app. I’ve named mine rails-react-tutorial
.
創建一個新的Rails應用程序。 我將其命名為mine rails-react-tutorial
。
rails new rails-react-tutorial --webpack=react
See here for more info on the --webpack=react
flag introduced in Rails 5.1.
有關在Rails 5.1中引入的--webpack=react
標志的更多信息,請參見此處 。
步驟2:確保已安裝Webpacker和React-Rails gem (Step 2: Make sure the Webpacker and React-Rails gems are installed)
Check if the Webpacker and React-Rails gems are in your Gemfile
. If the gems are not there, then add it:
檢查Webpacker和React-Rails寶石是否在您的Gemfile
。 如果寶石不存在,則添加它:
Now run these commands to install everything.
現在運行這些命令以安裝所有內容。
bundle install
# This command might not be necessary.# If already installed, then it will# ask you to override some files.rails webpacker:install
rails webpacker:install:react rails generate react:installyarn install
Now run rails server -p 3000
and visit http://localhost:3000
to make sure our project is working.
現在運行rails server -p 3000
并訪問http://localhost:3000
以確保我們的項目正在運行。
Pro Tip #1: run ./bin/webpack-dev-server
in a separate window while coding to have any changes automatically build and reload the browser.
專家提示1 :在單獨的窗口中運行./bin/webpack-dev-server
,同時進行編碼以自動構建并重新加載瀏覽器,以進行任何更改。
Pro Tip #2: If you get this error can’t activate sqlite3 (~> 1.3.6), already activated sqlite3–1.
4.0 then add gem ‘sqlite3’, ‘~>
1.3.6’ to Gemfile. See this link for more info.
專家提示2 :如果收到此錯誤, can't activate sqlite3 (~> 1.3.6), already activated sqlite3–1.
4.0,然后將dd gem 'sqlite3', '~>
gem'sqlite3 dd gem 'sqlite3', '~>
1.3.6'轉換為Gemfile。 有關更多信息,請參見此鏈接。
步驟3:將Controller類和Route添加到我們的Rails應用中 (Step 3: Add a Controller class, and Route, to our Rails app)
Add a new route to our Rails app. For this example, we will add GET /v1/things
endpoint to config/routes.rb
`.
向我們的Rails應用添加新路線。 對于此示例,我們將GET /v1/things
端點添加到config/routes.rb
。
This new route will require a ThingsController. Create a new app/controllers/v1/things_controller.rb
file. Remember, it should be in the v1
folder because it belongs to our Rails API.
這條新路線將需要一個ThingsController。 創建一個新的app/controllers/v1/things_controller.rb
文件。 請記住,它應該位于v1
文件夾中,因為它屬于我們的Rails API。
Our Things controller will return a hard-coded response for GET /v1/things
.
我們的Things控制器將返回GET /v1/things
的硬編碼響應。
At this point, you should be able to re-run rails server -p 3000
and visit http://localhost:3000/v1/things
.
此時,您應該能夠重新運行rails server -p 3000
并訪問http://localhost:3000/v1/things
。
Next, we will create a new React component.
接下來,我們將創建一個新的React組件。
步驟4:生成一個新的React組件 (Step 4: Generate a new React component)
Create a HelloWorld React component that accepts a String parameter named greeting
by running the following command:
通過運行以下命令,創建一個HelloWorld React組件,該組件接受名為greeting
的String參數:
rails generate react:component HelloWorld greeting:string
A file should be created: app/javascript/components/HelloWorld.js
.
應該創建一個文件: app/javascript/components/HelloWorld.js
。
步驟5:使用我們的HelloWorld組件 (Step 5: Use our HelloWorld component)
To use and see our new HelloWorld component we need to 2 things: create a view embeds this component, and add a route to point to this view.
要使用和查看新的HelloWorld組件,我們需要做兩件事:創建一個嵌入該組件的視圖,并添加指向該視圖的路徑。
To create a view, create the file app/views/static/index.html.erb
and add the following:
要創建視圖,請創建文件app/views/static/index.html.erb
并添加以下內容:
For our new route, add the following line to our routes.rb
file, and an empty StaticController to support it.
對于我們的新路由, routes.rb
添加到routes.rb
文件中,并添加一個空的StaticController來支持它。
Add this to app/controllers/static_controller.rb
:
將此添加到app/controllers/static_controller.rb
:
You should now be able to re-run rails server -p 3000
and visit http://localhost:3000/
to see your new React component (remember to run ./bin/webpack-dev-server
in a separate window to have an Javascript changes automatically get packaged by webpack).
現在,您應該能夠重新運行rails server -p 3000
并訪問http://localhost:3000/
來查看新的React組件(記住要在單獨的窗口中運行./bin/webpack-dev-server
,以使JavaScript更改將自動由webpack打包)。
Now that we have a React component that renders in our view, let’s expand our app to support multiple views with react-router
.
現在我們有了一個可在視圖中呈現的React組件,讓我們擴展應用程序以使用react-router
支持多個視圖。
第6步:添加React-Router (Step 6: Add React-Router)
First, run this command to add react-router-dom
, which includes and exports all of react-router
and some additional helper components for web browsing. More info here.
首先,運行此命令以添加react-router-dom
,其中包括并導出所有react-router
和一些其他輔助組件以進行網絡瀏覽。 更多信息在這里 。
npm install --save react-router-domyarn install
This command should add the following line to your package.json
file. Note, 4.2.2 was used here, but your version could be different.
此命令應將以下行添加到package.json
文件。 注意,此處使用的是4.2.2,但您的版本可能有所不同。
Now let’s use React Router to make some routes for our React Front-End.
現在,讓我們使用React Router為我們的React前端創建一些路由。
第6步:使用React-Router (Step 6: Using React-Router)
react-router
allows us to manage all our UI routes strictly with Javascript. This means that we will need a single “App” component that encapsulates our entire application. “App” will also use React-Router to present the correct “Page” component for the URL being requested.
react-router
允許我們嚴格使用Javascript管理所有UI路由。 這意味著我們將需要一個封裝整個應用程序的“應用程序”組件。 “應用程序”還將使用React-Router為請求的URL呈現正確的“頁面”組件。
To start, run this command to add an App component that will represent our entire front-end application.
首先,運行此命令以添加一個App組件,該組件將代表我們的整個前端應用程序。
rails generate react:component App
Next, open the file for the newly created React component, app/javascript/components/App.js
, and add the following …
接下來,打開新創建的React組件的文件app/javascript/components/App.js
,并添加以下內容……
Now change index.html.erb
to point to our new App component.
現在更改index.html.erb
以指向我們的新App組件。
Lastly, edit your routes.rb
to have Rails send all requests that are not for the API to our App component (via StaticController#index
).
最后,編輯您的routes.rb
以使Rails將所有非該API的請求發送到我們的App組件(通過StaticController#index
)。
We can now run rails server -p 3000
and visit http://localhost/
and http://localhost/hello
to see React-Router working (remember ./bin/webpack-dev-server
enables auto-webpacking).
我們現在可以運行rails server -p 3000
并訪問http://localhost/
和http://localhost/ hello
來查看React-Router的工作情況(記住./bin/webpack-dev-server
啟用自動webpacking)。
Next, we’ll need to install some additional dependencies before we can connect our React front-end to our Rails API.
接下來,我們需要安裝一些其他的依賴關系,然后才能將React前端連接到Rails API。
步驟7:添加Redux,Sagas,Babel Polyfill和Axios (Step 7: Adding Redux, Sagas, Babel Polyfill, and Axios)
Now let’s add the following Javascript libraries for our front-end.
現在讓我們為前端添加以下Javascript庫。
Redux to manage the global state of our application.
Redux用于管理應用程序的全局狀態。
- Babel-Polyfill to enable fancy Javascript features that might not otherwise be available on older web browsers. Babel-Polyfill可啟用花哨的Javascript功能,而這些功能在舊的Web瀏覽器上可能無法使用。
Reselect and React-Redux to make working with Redux easier.
重新選擇和React-Redux ,使使用Redux更加容易。
To install everything, run the following:
要安裝所有內容,請運行以下命令:
npm install --save redux babel-polyfill reselect react-reduxyarn install
Now we will use these tools to set up a Redux State Store, then add some Actions and Reducers to use it.
現在,我們將使用這些工具來設置Redux狀態存儲,然后添加一些操作和Reducer來使用它。
步驟8:設置Redux State Store (Step 8: Set up Redux State Store)
In this step, we will set up the Redux State Store for our app with the following template (we will add and remove “things” in the next steps).
在此步驟中,我們將使用以下模板為我們的應用設置Redux State Store(在接下來的步驟中,我們將添加和刪除“事物”)。
{ "things": [ { "name": "...", "guid": "..." } ]}
First, create a configureStore.js
file. This will initialize our Redux Store.
首先,創建一個configureStore.js
文件。 這將初始化我們的Redux Store。
Now import and use configureStore()
in the App Component to create a Redux State and hook it up to our App.
現在,在應用程序組件中導入并使用configureStore()
來創建Redux狀態并將其連接到我們的應用程序。
Now you have Redux installed in your app! Next, we will create an Action and a Reducer, and begin to write and read from our Redux State.
現在,您已在應用程序中安裝了Redux! 接下來,我們將創建一個Action和一個Reducer,并開始從Redux State進行讀寫。
步驟9:添加動作和減速器 (Step 9: Add an Action and a Reducer)
Now that the App has a Redux State, we will add a <butt
on> to HelloWorld that dispatches an Action (that we will define here) that will be received by the rootRed
ucer().
現在,該應用程序具有Redux狀態,我們將向HelloWorld添加<butt
on>,以調度一個Action(我們將在此處定義),該Action將通過y the rootRed
ucer()接收。
First, add getThings()
Action definition and import createStructuredSelector()
and connect()
into theHelloWorld Component. This maps parts of the Redux State, and Actions (i.e. dispatching getThings()
) , to HelloWorld’s prop.
首先,添加getThings()
動作定義,并將createStructuredSelector()
和connect()
導入到HelloWorld組件中。 這會將Redux State和Actions(即調度getThings()
)的一部分getThings()
到HelloWorld的prop。
Next, add a <butt
on> to HelloWorld that dispatches a getTh
ings() Action (from ./actions/index.js) on every click.
接下來,在HelloWorld上添加一個<butt
on>,它在每次單擊時都會hes a getTh
()動作(來自./actions/index.js)。
After everything is added to HelloWorld, go to http://localhost:3000/hello
, open the Console, and click the “getThings” button to see your Action and Reducer functions being called.
將所有內容添加到HelloWorld之后,請轉到http://localhost:3000/hello
,打開控制臺,然后單擊“ getThings”按鈕以查看您的Action和Reducer函數正在被調用。
Now that you can send an Action that can be received by a Reducer, let’s have the Reducer alter the Redux State.
現在您可以發送一個可以被Reducer接收的動作,讓我們讓Reducer更改Redux State。
步驟10:讓HelloWorld讀取React State并顯示“事物” (Step 10: Have HelloWorld read React State and display “things”)
Insert a List <
ul> in HelloWorld and fill it with “things” from your Redux State.
在HelloWorld中插入列表<
ul>,并用Redux State中的“事物”填充它。
To test if this is actually working, we can initialize with some “things” data. Once this is done, we can refresh the page and see it in our list.
為了測試它是否真的有效,我們可以使用一些“事物”數據進行初始化。 完成此操作后,我們可以刷新頁面并在列表中看到它。
Now that we have a simple Action and Reducer working, we will extend this so that the Action queries our Rails API and the Reducer sets the content of “things” with the API response.
現在,我們已經完成了一個簡單的Action和Reducer的工作,我們將對其進行擴展,以便Action查詢我們的Rails API,并且Reducer通過API響應設置“事物”的內容。
第11步:安裝Redux-Thunk (Step 11: Install Redux-Thunk)
We will need Redux-Thunk to allow async workflows (like an HTTP request) to dispatch Actions.
我們將需要Redux-Thunk來允許異步工作流(例如HTTP請求)來分派Action。
Install redux-thunk
by running this command:
通過運行以下命令來安裝redux-thunk
:
npm install --save redux-thunkyarn install
Now, let’s use Thunk in our Action!
現在,讓我們在動作中使用Thunk!
第12步:使用redux-thunk和fetch()查詢API并使用結果設置React State (Step 12: Use redux-thunk and fetch() to query API and set React State with results)
First, let’s import redux-thunk
in configureStore.js
and install it our Redux Store so our App can handle “Thunk” Actions.
首先,讓我們在configureStore.js
導入redux-thunk
并將其安裝到我們的Redux Store中,以便我們的應用程序可以處理“ Thunk”操作。
Now test that everything is working by starting the App and loading a page.
現在,通過啟動應用程序并加載頁面來測試一切是否正常。
Next, let’s change the getThings()
Action to return a function that performs the following (instead of returning the Action object):
接下來,讓我們更改getThings()
操作以返回執行以下操作的函數(而不是返回Action對象):
- Dispatch the original Action object 派發原始的Action對象
- Make a call to our Rails API. 調用我們的Rails API。
Dispatch a new Action
getThingsSuccess(json)
when the call succeeds.調用成功時,調度新的Action
getThingsSuccess(json)
。
For this step, we will also need to add the getThingsSuccess(json)
Action.
對于此步驟,我們還需要添加getThingsSuccess(json)
Action。
Of course, this does nothing to the Redux State since our Reducer is not making any changes. To fix this, change the Reducer to handle the GET_THINGS_SUCCESS
Action and return the new State (with the response from the Rails API).
當然,這對Redux State沒有任何作用,因為我們的Reducer并未進行任何更改。 要解決此問題,請更改Reducer以處理GET_THINGS_SUCCESS
操作并返回新的State(帶有Rails API的響應)。
Now if you start your App, navigate to localhost:3000/hello
and click the button, your list should change!
現在,如果您啟動您的應用程序,請導航至localhost:3000/hello
并單擊按鈕,您的列表應會更改!
There you have it. A Rails API hooked up to a React+Redux App.
你有它。 Rails API已連接到React + Redux應用程序。
(獎金)第13步:安裝Redux開發工具 ((Bonus) Step 13: Installing Redux Dev Tools)
Maybe I should’ve put this step earlier, but Redux Dev Tools is essential for debugging the Actions your App is sending, and how those Actions are changing your State.
也許我應該早點采取這一步驟,但是Redux Dev Tools對于調試您的應用正在發送的動作以及這些動作如何改變您的狀態至關重要。
This is how you install it. First, install the proper extension for your browser (Chrome, Firefox).
這就是您的安裝方式。 首先,為您的瀏覽器安裝適當的擴展程序( Chrome ,Firefox)。
Next, run the following to install the library.
接下來,運行以下命令安裝庫。
npm install --save-dev redux-devtools-extensionyarn install
Now, use it to initialize your Redux State Store.
現在,使用它來初始化您的Redux狀態存儲。
After all this is done, you should be able to see a new tab, Redux, in your Chrome (or Firefox) dev tools, that lets you see which Actions were dispatched, and how each one changed the App’s State. The React tab will also show you all your components and their props and states.
完成所有這些操作后,您應該能夠在Chrome(或Firefox)開發工具中看到一個新的標簽Redux,該標簽可讓您查看分配了哪些操作,以及每個操作如何更改應用程序的狀態。 React選項卡還將顯示所有組件及其道具和狀態。
Happy debugging!
調試愉快!
(獎金)第14步:語義UI ((Bonus) Step 14: Semantic UI)
Semantic is a great library for UI components that makes it really easy to build nice looking websites quickly.
語義是用于UI組件的出色庫,它使真正快速構建美觀的網站變得非常容易。
To install this library, run the following.
要安裝此庫,請運行以下命令。
npm install --save semantic-ui-css semantic-ui-reactyarn install
Add this to app/javascript/packs/application.js
:
將此添加到app/javascript/packs/application.js
:
import 'semantic-ui-css/semantic.min.css';
And add this to app/views/static/index.html.erb
:
并將其添加到app/views/static/index.html.erb
:
<%= stylesheet_pack_tag "application", :media => 'all' %
(獎勵)步驟15:使用合理的目錄結構 ((Bonus) Step 15: Using a Reasonable Directory Structure)
This step is totally optional, and it has nothing to do with the function of the App. Just my opinion on how you should organize your files.
此步驟完全是可選步驟,與應用程序的功能無關。 我對如何組織文件的看法。
So as you can probably guess, stuffing your Actions into the same file as your Components, and having a single reducer for your entire App, does not scale very nicely when your App grows. Here is my suggested file structure:
因此,您可能會猜到,將Action填充到與Components相同的文件中,并且為整個App配備一個reducer時,隨著App的增長,伸縮性不會很好。 這是我建議的文件結構:
app|-- javascript |-- actions |-- index.js |-- things.js |-- components |-- packs |-- reducers |-- index.js |-- things.js
(獎金-2019年3月17日更新)第16步:安裝打字稿! ((Bonus — Mar 17 2019 Update) Step 16: Install Typescript!)
Typescript is just like Javascript but with types! It is described as a “strict syntactical superset of Javascript”, meaning that Javascript is considered valid Typescript, and the “type features” are all optional.
Typescript就像Javascript一樣,但是帶有類型! 它被描述為“ 嚴格的Java語法語法超集 ”,這意味著Javascript被視為有效的Typescript,并且“ type features”都是可選的。
IMO Typescript is fantastic for large Javscript projects, such as a big React front-end. Below are instructions on how to install it, and a small demo of it inside our project.
IMO Typescript對于大型Javscript項目(例如大型React前端)而言非常理想。 以下是有關如何安裝它的說明,以及在我們的項目中的小演示。
First, run the following commands (taken from the Webpacker Readme):
首先,運行以下命令(摘自Webpacker自述文件 ):
bundle exec rails webpacker:install:typescriptyarn add @types/react @types/react-dom
Now, to see it in action, let’s rename app/javascript/reducers/things.js
to things.tsx
and add the following lines to the top of the file:
現在,要查看它的實際效果,讓我們將app/javascript/reducers/things.js
重命名為things.tsx
并將以下行添加到文件頂部:
After you add interface Thing
, let’s use it by having const initialState
use that type (seen in the screenshot above), and specify that thingsReducer
return an array of type Thing
(also seen in the screenshot).
添加interface Thing
,讓我們使用const initialState
使用該類型(在上面的屏幕快照中看到),并指定它讓thingsReducer
返回Thing
類型的數組(在屏幕快照中也可以看到)來使用它。
Everything should still work, but to see Typescript in action, lets add a default
case to thingsReducer
and add return 1
. Since 1
is not a Thing
type we will see the output of ./bin/webpack-dev-server
fail with the following:
一切仍然應該正常工作,但是要查看Typescript的實際效果,我們可以向thingsReducer
添加default
大小寫并添加return 1
。 由于1
不是Thing
類型,我們將看到./bin/webpack-dev-server
的輸出失敗,并顯示以下內容:
And that’s it! You can now add Typescript .tsx
files to your project and start using Types with your project.
就是這樣! 現在,您可以將Typescript .tsx
文件添加到項目中,并開始在項目中使用Types。
Here’s a great overview of Typescript and why you should use it.
這是Typescript的概述,以及為什么要使用它 。
結束 (The End)
You made it! You’ve made a Rails App that uses React and Redux. That’s pretty much it for the tutorial. I hope you had fun and learned something along the way.
你做到了! 您已經制作了一個使用React和Redux的Rails應用程序。 對于本教程來說就差不多了。 希望您玩得開心,并從中學到一些東西。
If you build something with React and Rails, please do share it in the comments below — along with any questions or comments you may have for me.
如果您使用React和Rails進行構建,請在下面的評論中分享它-以及您可能對我有的任何問題或評論。
Thanks for reading!
謝謝閱讀!
翻譯自: https://www.freecodecamp.org/news/how-to-create-a-rails-project-with-a-react-and-redux-front-end-8b01e17a1db/