diff --git a/.eslintrc.js b/.eslintrc.js index 1b4e795..3ceadf9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,7 +23,8 @@ module.exports = { }, plugins: [ 'react', - 'prettier' + 'prettier', + 'react-hooks' ], rules: { 'prettier/prettier':'error', @@ -35,6 +36,8 @@ module.exports = { 'react/state-in-constructor': 'off', 'react/static-property-placement': 'off', 'no-console': ["error", {allow: ["tron"]}], - 'no-param-reassign': 'off' + 'no-param-reassign': 'off', + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn' }, }; diff --git a/package.json b/package.json index eb6b2fc..15127aa 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "immer": "^6.0.2", "intl": "^1.2.5", "polished": "^3.5.0", - "prop-types": "^15.7.2", "react": "16.9.0", "react-native": "0.61.5", "react-native-flash-message": "^0.1.15", @@ -47,7 +46,7 @@ "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-prettier": "^3.1.2", "eslint-plugin-react": "^7.19.0", - "eslint-plugin-react-hooks": "^2.5.0", + "eslint-plugin-react-hooks": "^2.5.1", "jest": "^25.1.0", "metro-react-native-babel-preset": "^0.58.0", "prettier": "^1.19.1", diff --git a/src/components/Header/index.js b/src/components/Header/index.js index cb65d01..fdfe137 100644 --- a/src/components/Header/index.js +++ b/src/components/Header/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import { connect } from 'react-redux'; +import { useSelector } from 'react-redux'; import { useNavigation } from '@react-navigation/native'; import Icon from 'react-native-vector-icons/MaterialIcons'; @@ -12,7 +12,9 @@ import { AmountText, } from './styles'; -function Header({ cartSize }) { +export default function Header() { + const cartSize = useSelector(state => state.cart.length); + const navigation = useNavigation(); return ( @@ -27,7 +29,3 @@ function Header({ cartSize }) { ); } - -export default connect(state => ({ - cartSize: state.cart.length, -}))(Header); diff --git a/src/pages/Cart/index.js b/src/pages/Cart/index.js index 72b9d4a..d3b990d 100644 --- a/src/pages/Cart/index.js +++ b/src/pages/Cart/index.js @@ -1,7 +1,5 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; +import { useDispatch, useSelector } from 'react-redux'; import Icon from 'react-native-vector-icons/MaterialIcons'; import { Container, @@ -31,12 +29,30 @@ import Header from '../../components/Header'; import * as CartActions from '../../store/modules/cart/actions'; -function Cart({ cart, total, removeFromCart, updateAmountRequest }) { +export default function Cart() { + const total = useSelector(state => + formatPrice( + state.cart.reduce((totalSum, product) => { + return totalSum + product.price * product.amount; + }, 0) + ) + ); + + const cart = useSelector(state => + state.cart.map(product => ({ + ...product, + subtotal: formatPrice(product.price * product.amount), + })) + ); + + const dispatch = useDispatch(); + function increment(product) { - updateAmountRequest(product.id, product.amount + 1); + dispatch(CartActions.updateAmountRequest(product.id, product.amount + 1)); } + function decrement(product) { - updateAmountRequest(product.id, product.amount - 1); + dispatch(CartActions.updateAmountRequest(product.id, product.amount - 1)); } return ( @@ -67,7 +83,9 @@ function Cart({ cart, total, removeFromCart, updateAmountRequest }) { removeFromCart(product.id)} + onPress={() => + dispatch(CartActions.removeFromCart(product.id)) + } > @@ -96,27 +114,3 @@ function Cart({ cart, total, removeFromCart, updateAmountRequest }) { ); } - -Cart.propTypes = { - cart: PropTypes.arrayOf(PropTypes.object).isRequired, - total: PropTypes.string.isRequired, - removeFromCart: PropTypes.func.isRequired, - updateAmountRequest: PropTypes.func.isRequired, -}; - -const mapStateToProps = state => ({ - cart: state.cart.map(product => ({ - ...product, - subtotal: formatPrice(product.price * product.amount), - })), - total: formatPrice( - state.cart.reduce((total, product) => { - return total + product.price * product.amount; - }, 0) - ), -}); - -const mapDispatchToProps = dispatch => - bindActionCreators(CartActions, dispatch); - -export default connect(mapStateToProps, mapDispatchToProps)(Cart); diff --git a/src/pages/Home/index.js b/src/pages/Home/index.js index e3b392f..7757420 100644 --- a/src/pages/Home/index.js +++ b/src/pages/Home/index.js @@ -1,7 +1,5 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; +import React, { useState, useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import Icon from 'react-native-vector-icons/MaterialIcons'; import { Container, @@ -22,74 +20,59 @@ import * as CartActions from '../../store/modules/cart/actions'; import { formatPrice } from '../../util/format'; import api from '../../services/api'; -class Home extends Component { - state = { - products: [], - }; +export default function Home() { + const [products, setProducts] = useState([]); - static propTypes = { - addToCartRequest: PropTypes.func.isRequired, - amount: PropTypes.objectOf(PropTypes.number).isRequired, - }; + const amount = useSelector(state => + state.cart.reduce((sumAmount, product) => { + sumAmount[product.id] = product.amount; - async componentDidMount() { - const response = await api.get('products'); + return sumAmount; + }, {}) + ); - const data = response.data.map(product => ({ - ...product, - priceFormatted: formatPrice(product.price), - })); + const dispatch = useDispatch(); - this.setState({ products: data }); - } - - handleAddProduct = id => { - const { addToCartRequest } = this.props; - - addToCartRequest(id); - }; + useEffect(() => { + async function loadProducts() { + const response = await api.get('products'); - render() { - const { products } = this.state; - const { amount } = this.props; + const data = response.data.map(product => ({ + ...product, + priceFormatted: formatPrice(product.price), + })); + setProducts(data); + } + loadProducts(); + }, []); - return ( - -
- String(product.id)} - renderItem={({ item }) => ( - - - {item.title} - {item.priceFormatted} - this.handleAddProduct(item.id)}> - - - {amount[item.id] || 0} - - - ADD TO CART - - - )} - /> - - ); + function handleAddProduct(id) { + dispatch(CartActions.addToCartRequest(id)); } -} -const mapStateToProps = state => ({ - amount: state.cart.reduce((amount, product) => { - amount[product.id] = product.amount; - - return amount; - }, {}), -}); - -const mapDispatchToProps = dispatch => - bindActionCreators(CartActions, dispatch); - -export default connect(mapStateToProps, mapDispatchToProps)(Home); + return ( + +
+ String(product.id)} + renderItem={({ item }) => ( + + + {item.title} + {item.priceFormatted} + handleAddProduct(item.id)}> + + + {amount[item.id] || 0} + + + ADD TO CART + + + )} + /> + + ); +}