React + Redux: prosty przykład zastosowania
Opublikowano ndz 08 listopada 2020 w redux • 2 min read
Poniżej przedstawię przykład (oraz kolejne kroki powstania) bardzo prostego projektu wykorzystującego stan kontrolowany przez Redux. Projekt bazuje na React (CRA).
1) Instalacja narzędzi/zależności
npx create-react-app <nazwa_projektu>
npm i redux react-redux
2) Struktura projektu (istotne pliki/te które są edytowane oraz które zostaną/ły dodane)
{public}
|
|_ [...]
{src}
|
|_ {actions}
| |
| | --- index.js
|
|_ {reducers}
| |
| | --- index.js
| | --- counter.js
| | --- isLogged.js
|
|---App.js
|---index.js
|
[...]
3) >>index.js<< - tutaj należy stworzyć store oraz zaimportować reduktory - window.REDUX_DEVTOOLS_EXTENSION && window.REDUX_DEVTOOLS_EXTENSION() [wcześniej window.devToolsExtension] jest przydatne w momencie tworzenia układu stanu za pomocą Reduxa, gdy nie jest jeszcze podpięty z Reactem (umożliwia komunikację z Redux Dev Tools, więcej na ten temat tutaj: Redux DevTools Extension) - App jest wskazany jako Provider (komponent wyższego rzędu) gdzie jako props przekazywany jest store
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { createStore } from "redux";
import allReducers from './reducers'
import {Provider} from 'react-redux'
const store = createStore(allReducers,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById("root")
);
4) >>{reducers}<<
- w tym folderze w poszczególnych plikach przechowywane są reduktory - funkcje tworzące nowy stan
-
ogólnie przyjęta zasada 1 plik = 1 stan (innymi słowy każdy stan posiada własny plik)
-
isLogged.js - loggedReducer przyjmuje 2 arg. 1. stan = false oraz akcję, jeśli typ akcji będzie równy SIGN_IN wówczas stan zostanie zmieniony na True
const loggedReducer = (state=false, action) =>{ switch(action.type) { case "SIGN_IN" : return !state; default: return state; } } export default loggedReducer
-
counter.js - counterReducer przyjmuje 2 arg. 1 stan = 0 oraz akcję (będącą obiektem) jeśli typ akcji jest równy INCREMENT wówczas należy stan zwiększyć o wartość zawartą w action.payload a jeśli DECREMENT - odjąć 1.
const counterReducer = (state=0, action) =>{ switch(action.type) { case "INCREMENT" : return state + action.payload; case "DECREMENT" : return state - 1; default: return state; } } export default
-
index.js - skupie w sobie reduktory (przy pomocy combineReducers) i eksportuje w postaci obiektu
import counterReducer from './counter' import loggedReducer from './isLogged' import { combineReducers } from 'redux' //function with object const allReducers = combineReducers({ counter: counterReducer, isLogged: loggedReducer }) export default allReducers
5) >>{actions}<<
- index.js - zawiera akcje (faktyczne funkcje zwracające obiekty do których należy odwołać się w komponentach), funkcja increment przyjmuje jeden argument, którego wartość przechowywana jest w zmiennej o nazwie payload
export const increment = (num) => { return { type: "INCREMENT", payload: num, }; }; export const decrement = () => { return { type: "DECREMENT" }; };
6) >>App.js<<
- aplikacja - wymaga zaimportowania akcji oraz 2 hooków useSelectors oraz useDispatch
- useSelectors jest wykorzystywany do stworzenia funkcji zmieniającej stan przy użyciu akcji
- useDispatch jest wykorzystywany do aktualizacji stanu
import "./App.css"; import { useSelector, useDispatch } from "react-redux"; import { increment, decrement } from "./actions"; function App() { const counter = useSelector((state) => state.counter); const isLogged = useSelector((state) => state.isLogged); const dispatch = useDispatch(); return ( <div className="App"> <h2>Counter: {counter} </h2> <button onClick={()=>dispatch(increment(5))}>+</button> <button onClick={()=>dispatch(decrement())}>-</button> {isLogged ? <h3>Info only seen if logged</h3> : ""} </div> ); } export default App;
Źródła: