From f970b81fb5844c3859f568d7cd72bcf2e1e4bbdf Mon Sep 17 00:00:00 2001 From: Luiz Felicio Date: Thu, 19 Dec 2019 11:34:12 -0300 Subject: [PATCH] Refactoring application to redux (flux pattern) --- package.json | 2 ++ src/App.js | 23 +++++++++++-------- src/Routes.js | 4 ++-- src/components/Header/index.js | 2 ++ src/components/TextInput/index.js | 9 ++++++-- src/index.js | 10 ++++++-- src/redux/actions/fetchCards.js | 16 +++++++++++++ src/redux/actions/index.js | 17 ++++++++++++++ src/redux/reducers/cardsReducer.js | 37 ++++++++++++++++++++++++++++++ src/redux/store/cards.js | 15 ++++++++++++ src/redux/types/index.js | 5 ++++ yarn.lock | 10 ++++++++ 12 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 src/redux/actions/fetchCards.js create mode 100644 src/redux/actions/index.js create mode 100644 src/redux/reducers/cardsReducer.js create mode 100644 src/redux/store/cards.js create mode 100644 src/redux/types/index.js diff --git a/package.json b/package.json index f8e5bf8..db7db61 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,8 @@ "react-router-dom": "^5.1.2", "react-scripts": "3.3.0", "redux": "^4.0.4", + "redux-devtools-extension": "^2.13.8", + "redux-thunk": "^2.3.0", "styled-components": "^4.4.1" }, "devDependencies": { diff --git a/src/App.js b/src/App.js index 6c0061e..04d9be4 100644 --- a/src/App.js +++ b/src/App.js @@ -1,21 +1,20 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { BrowserRouter as Router } from 'react-router-dom'; import Header from './components/Header'; import RoutesContainer from './Routes'; - -import api from './api'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { fetchCards, fetchCardByPokeName } from './redux/actions/fetchCards'; import './app.css'; -function App() { - const [cards, setCards] = useState([]); - +function App({ cards, fetchCards, fetchCardByPokeName }) { useEffect(() => { - api.get('/cards').then((response) => setCards(response.data.cards)); + fetchCards(); }, []); const doSearchPokemon = (input) => { - api.get(`/cards?name=${input}`).then((response) => setCards(response.data.cards)); + fetchCardByPokeName(input); }; return ( @@ -26,4 +25,10 @@ function App() { ); } -export default App; +const mapStateToProps = (state) => ({ + cards: state.cards, +}); + +const mapDispatchToProps = (dispatch) => bindActionCreators({ fetchCards, fetchCardByPokeName }, dispatch); + +export default connect(mapStateToProps, mapDispatchToProps)(App); diff --git a/src/Routes.js b/src/Routes.js index 4ff9609..938c946 100644 --- a/src/Routes.js +++ b/src/Routes.js @@ -3,12 +3,12 @@ import React from 'react'; import { Route, Switch } from 'react-router-dom'; import CardDetails from './components/CardDetails'; -import Cards from './components/CardsList'; +import CardsList from './components/CardsList'; const RoutesContainer = ({ cards }) => ( <> - } /> + } /> diff --git a/src/components/Header/index.js b/src/components/Header/index.js index 547248c..8c5bdd1 100644 --- a/src/components/Header/index.js +++ b/src/components/Header/index.js @@ -29,6 +29,8 @@ const Header = ({ doSearchPokemon, history }) => { labelText="Digite o nome do Pokemón" name="txtPokemon" placeholder="Digite o nome do Pokemón" + type="search" + autoComplete="off" /> diff --git a/src/components/TextInput/index.js b/src/components/TextInput/index.js index f965797..0a3b071 100644 --- a/src/components/TextInput/index.js +++ b/src/components/TextInput/index.js @@ -76,7 +76,7 @@ const StyledInput = styled.input` `; const TextInput = ({ - labelText, name, placeholder, value, onChange, + labelText, autoComplete, name, placeholder, type, value, onChange, }) => { const [active, setActive] = useState(false); @@ -84,7 +84,8 @@ const TextInput = ({ , document.getElementById('root')); - +ReactDOM.render( + + + , + document.getElementById('root'), +); if (module.hot) { module.hot.accept(); } diff --git a/src/redux/actions/fetchCards.js b/src/redux/actions/fetchCards.js new file mode 100644 index 0000000..78dc0bf --- /dev/null +++ b/src/redux/actions/fetchCards.js @@ -0,0 +1,16 @@ +import { fetchCardsPending, fetchCardsSuccess, fetchCardsFailure } from './index'; +import api from '../../api'; + +export const fetchCards = () => (dispatch) => { + dispatch(fetchCardsPending()); + api.get('/cards') + .then((response) => dispatch(fetchCardsSuccess(response.data.cards))) + .catch((error) => dispatch(fetchCardsFailure(error))); +}; + +export const fetchCardByPokeName = (input) => (dispatch) => { + dispatch(fetchCardsPending()); + api.get(`/cards?name=${input}`) + .then((response) => dispatch(fetchCardsSuccess(response.data.cards))) + .catch((error) => dispatch(fetchCardsFailure(error))); +}; diff --git a/src/redux/actions/index.js b/src/redux/actions/index.js new file mode 100644 index 0000000..99f10bc --- /dev/null +++ b/src/redux/actions/index.js @@ -0,0 +1,17 @@ +import { FETCH_CARDS_PENDING, FETCH_CARDS_SUCCESS, FETCH_CARDS_ERROR } from '../types'; + +export const test = () => {}; + +export const fetchCardsPending = () => ({ + type: FETCH_CARDS_PENDING, +}); + +export const fetchCardsSuccess = (payload) => ({ + type: FETCH_CARDS_SUCCESS, + payload, +}); + +export const fetchCardsFailure = (payload) => ({ + type: FETCH_CARDS_ERROR, + payload, +}); diff --git a/src/redux/reducers/cardsReducer.js b/src/redux/reducers/cardsReducer.js new file mode 100644 index 0000000..a927dd0 --- /dev/null +++ b/src/redux/reducers/cardsReducer.js @@ -0,0 +1,37 @@ +import { FETCH_CARDS_PENDING, FETCH_CARDS_SUCCESS, FETCH_CARDS_ERROR } from '../types'; + +const INITAL_STATE = { + cards: [], + loading: false, + error: false, +}; + +const cardsReducer = (state = INITAL_STATE, action) => { + switch (action.type) { + case FETCH_CARDS_PENDING: + return { + ...state, + loading: true, + error: false, + }; + case FETCH_CARDS_SUCCESS: + return { + ...state, + cards: state.cards.concat(action.payload), + loading: true, + error: false, + }; + + case FETCH_CARDS_ERROR: + return { + ...state, + loading: false, + error: true, + }; + + default: + return state; + } +}; + +export default cardsReducer; diff --git a/src/redux/store/cards.js b/src/redux/store/cards.js new file mode 100644 index 0000000..f9328dd --- /dev/null +++ b/src/redux/store/cards.js @@ -0,0 +1,15 @@ +import { createStore, applyMiddleware } from 'redux'; +import { composeWithDevTools } from 'redux-devtools-extension'; +import cardsReducer from '../reducers/cardsReducer'; +import thunk from 'redux-thunk'; + +const middlewares = [thunk]; + +const store = createStore( + cardsReducer, + composeWithDevTools( + applyMiddleware(...middlewares), + ), +); + +export default store; diff --git a/src/redux/types/index.js b/src/redux/types/index.js new file mode 100644 index 0000000..0c51924 --- /dev/null +++ b/src/redux/types/index.js @@ -0,0 +1,5 @@ +export const FETCH_CARDS_PENDING = 'FETCH_CARDS_PENDING'; +export const FETCH_CARDS_SUCCESS = 'FETCH_CARDS_SUCCESS'; +export const FETCH_CARDS_ERROR = 'FETCH_CARDS_ERROR'; +export const UPDATE_CARDS = 'UPDATE_CARDS'; +export const DELETE_CARDS = 'DELETE_CARDS'; diff --git a/yarn.lock b/yarn.lock index 6d3e814..5b9cbcc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8820,6 +8820,16 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redux-devtools-extension@^2.13.8: + version "2.13.8" + resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1" + integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg== + +redux-thunk@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" + integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== + redux@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796"