Skip to content

Commit

Permalink
refactoring components to react-hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielbarth committed Mar 25, 2020
1 parent 91ae5b1 commit 96d1c2c
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 108 deletions.
7 changes: 5 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ module.exports = {
},
plugins: [
'react',
'prettier'
'prettier',
'react-hooks'
],
rules: {
'prettier/prettier':'error',
Expand All @@ -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'
},
};
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
10 changes: 4 additions & 6 deletions src/components/Header/index.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 (
<Container>
Expand All @@ -27,7 +29,3 @@ function Header({ cartSize }) {
</Container>
);
}

export default connect(state => ({
cartSize: state.cart.length,
}))(Header);
56 changes: 25 additions & 31 deletions src/pages/Cart/index.js
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -67,7 +83,9 @@ function Cart({ cart, total, removeFromCart, updateAmountRequest }) {
</ProductControlButton>
</ProductAmountContainer>
<ProductDeleteButton
onPress={() => removeFromCart(product.id)}
onPress={() =>
dispatch(CartActions.removeFromCart(product.id))
}
>
<Icon name="delete" color="#7159c1" size={24} />
</ProductDeleteButton>
Expand Down Expand Up @@ -96,27 +114,3 @@ function Cart({ cart, total, removeFromCart, updateAmountRequest }) {
</Container>
);
}

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);
117 changes: 50 additions & 67 deletions src/pages/Home/index.js
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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 (
<Container>
<Header />
<ProductList
data={products}
horizontal
keyExtractor={product => String(product.id)}
renderItem={({ item }) => (
<Product>
<ProductImage source={{ uri: item.image }} size={200} />
<ProductTitle>{item.title}</ProductTitle>
<ProductPrice>{item.priceFormatted}</ProductPrice>
<ProductButton onPress={() => this.handleAddProduct(item.id)}>
<ProductAmount>
<Icon name="add-shopping-cart" color="#FFF" size={20} />
<ProductAmountText>{amount[item.id] || 0}</ProductAmountText>
</ProductAmount>

<ProductButtonText>ADD TO CART</ProductButtonText>
</ProductButton>
</Product>
)}
/>
</Container>
);
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 (
<Container>
<Header />
<ProductList
data={products}
horizontal
keyExtractor={product => String(product.id)}
renderItem={({ item }) => (
<Product>
<ProductImage source={{ uri: item.image }} size={200} />
<ProductTitle>{item.title}</ProductTitle>
<ProductPrice>{item.priceFormatted}</ProductPrice>
<ProductButton onPress={() => handleAddProduct(item.id)}>
<ProductAmount>
<Icon name="add-shopping-cart" color="#FFF" size={20} />
<ProductAmountText>{amount[item.id] || 0}</ProductAmountText>
</ProductAmount>

<ProductButtonText>ADD TO CART</ProductButtonText>
</ProductButton>
</Product>
)}
/>
</Container>
);
}

0 comments on commit 96d1c2c

Please sign in to comment.