一個最常見的作法。
簡述
雖然說你也可以自己手動把 Redux 跟 React 給串起來,但透過套件來處理會更好。這邊會介紹一套叫做 react-redux 的 library,用它來把 React 跟 Redux 串接起來。
記得,redux 跟 react-redux 是不同的東西:
- Redux 是管理狀態的 library
- react-redux 是用來把 React 跟 redux 結合起來的 library
不要再搞混啦!
要用 react-redux 的方式 有兩種,一種是建立 create-react-app 時加上參數:
1
| npx create-react-app my-app --template redux
|
一種是對現有的 create-react-app 來加上 react-redux:
1 2
| npm install redux npm install react-redux
|
我們要介紹的是第二種。
基本的資料夾結構
在串接之前記得先做好 redux 前置作業,你的資料夾結構應該會長成這樣:
- redux
- reducers
- todos.js
- users.js
- index.js (把所有 reducer 集合起來)
- store.js(負責建立 store)
- actionTypes.js(把 action type 的常數集合起來)
- actions(action creator 管理)
- selectors(把選出 state 的 function 集合起來)
這邊列出我覺得需要知道一下內容的幾個檔案:
1. reducers/index.js
1 2 3 4 5 6 7 8 9
| import { combineReducers } from "redux"; import todosReducer from "./todos" import usersReducer from "./users"
export default combineReducers({ todosReducer, usersReducer })
|
這邊因為是「多個」reducer,所以資料結構會跟只有「單一個」的時候不太一樣,要多注意一下。
單一個的時候:
1 2
| const store = createStore(todosReducer); console.log(store.getState());
|
output:
1 2 3
| { todos: ['todo1', 'todo2', 'todo3'] }
|
多個的時候:
1 2
| const store = createStore(todosReducer); console.log(store.getState());
|
output:
1 2 3 4 5 6 7 8
| { todosReducer: { todos: ['todo1', 'todo2'] }, usersReducer: { users: ['user1', 'user2'] } }
|
2. redux/store.js
1 2 3 4 5
| import { createStore } from "redux"; import rootReducer from "./reducers";
export default createStore(rootReducer);
|
3. redux/selectors.js
這邊做個補充,selector 的用途只是「把我想要的 state 選出來」而已,畢竟你應該不會想在一個 Component 裡面拿到所有的 state,所以才會衍伸出這個東西。
另外之所以會抽出去建立成 constant 只是因為 code 寫起來會比較簡潔而已。
1 2 3
| export const selectTodos = state => state.todosReducer.todos; export const selectUsers = state => state.usersReducer.users;
|
其他的就只是把原本的東西抽出去寫成一個檔案而已,忘記的話可以參考:初探 Redux
正式串接
這邊寫個懶人包:
- 定義
Provider
- 把
store
傳入 Provider
,讓底下所有元件能夠接收
- 在元件內使用
useSelector
取出需要的 state(搭配前面寫好的 selectors.js)
- 先引入
useDispatch
,接著就能透過 dispatch
發出 action
這邊直接附上 code,你邊看邊想一下應該就懂了:
1 2 3 4 5 6 7 8 9 10
| import { Provider } from "react-redux"; import store from "./redux/store"
const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <Provider store={store}> <App /> </Provider> );
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import { useState, useEffect } from "react"; import { useSelector, useDispatch } from "react-redux"; import { selectTodos } from "./redux/selectors" import { addTodo } from "./redux/actions"
function App() { const [value, setValue] = useState(""); const todos = useSelector(selectTodos); const dispatch = useDispatch(); const handleSubmit = e => { e.preventDefault(); dispatch(addTodo(value)); setValue("") }
return ( <div className="App"> <form onSubmit={handleSubmit}> <input value={value} onChange={e => setValue(e.target.value)} /> </form> <ul> {todos.map(todo => <li key={todo.id} data-id={todo.id} >{todo.name}</li>)} </ul> </div> ); }
export default App;
|
這樣子其實就串好囉!有疑問的話也可以去我寫的 範例 參考。