From e48ce557d4778d522bf2e649ec00b34301e84348 Mon Sep 17 00:00:00 2001 From: Olena Date: Tue, 25 Jul 2023 14:36:07 +0300 Subject: [PATCH 1/3] Solution --- README.md | 2 +- src/App.tsx | 66 +++++++++++++++++++++++++++++++++-------------- src/GoodsList.tsx | 18 ++++++++++--- src/api/goods.ts | 22 ++++++++++++---- 4 files changed, 80 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index aa688e6f2..7c439f332 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,4 @@ You have 3 button that should load [the goods](https://mate-academy.github.io/re - Implement a solution following the [React task guideline](https://github.com/mate-academy/react_task-guideline#react-tasks-guideline). - Use the [React TypeScript cheat sheet](https://mate-academy.github.io/fe-program/js/extra/react-typescript). - Open one more terminal and run tests with `npm test` to ensure your solution is correct. -- Replace `` with your Github username in the [DEMO LINK](https://.github.io/react_dynamic-list-of-goods/) and add it to the PR description. +- Replace `` with your Github username in the [DEMO LINK](https://olena-ole.github.io/react_dynamic-list-of-goods/) and add it to the PR description. diff --git a/src/App.tsx b/src/App.tsx index 2cf5239da..6610cf02e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,27 +1,55 @@ -import React from 'react'; +import React, { useState } from 'react'; import './App.scss'; import { GoodsList } from './GoodsList'; +import { getAll, get5First, getRedGoods } from './api/goods'; +import { Good } from './types/Good'; -// import { getAll, get5First, getRed } from './api/goods'; -// or -// import * as goodsAPI from './api/goods'; +export const App: React.FC = () => { + const [currentGoods, setCurrentGoods] = useState([]); + const [errorMessage, setErrorMessage] = useState(''); -export const App: React.FC = () => ( -
-

Dynamic list of Goods

+ const hadleClick = (fetchFromServer: () => Promise) => { + fetchFromServer() + .then(goods => { + setCurrentGoods(goods); + setErrorMessage(''); + }) + .catch(() => { + setErrorMessage('Something went wrong... Try again later!'); + }); + }; - + return ( +
+

Dynamic list of Goods

- + - + - -
-); + + + {errorMessage + ?

{errorMessage}

+ : } +
+ ); +}; diff --git a/src/GoodsList.tsx b/src/GoodsList.tsx index b56a4331e..6cf26cadd 100644 --- a/src/GoodsList.tsx +++ b/src/GoodsList.tsx @@ -5,12 +5,24 @@ type Props = { goods: Good[] }; -export const GoodsList: React.FC = ({ goods }) => ( +export const GoodsList: React.FC = React.memo(({ goods }) => (
    {goods.map(good => ( -
  • +
  • {good.name}
  • ))}
-); +), (prevProps, nextProps) => { + if (prevProps.goods.length !== nextProps.goods.length) { + return false; + } + + return prevProps.goods.every( + (good, index) => good.id === nextProps.goods[index].id, + ); +}); diff --git a/src/api/goods.ts b/src/api/goods.ts index f0d1659f8..2b0f273ce 100644 --- a/src/api/goods.ts +++ b/src/api/goods.ts @@ -5,15 +5,27 @@ const API_URL = `https://mate-academy.github.io/react_dynamic-list-of-goods/good export function getAll(): Promise { return fetch(API_URL) - .then(response => response.json()); + .then(response => { + if (!response.ok) { + throw new Error(); + } + + return response.json(); + }); } -export const get5First = () => { +export const get5First = (): Promise => { return getAll() - .then(goods => goods); // sort and get the first 5 + .then(goods => { + const sortedGoods = goods.sort( + (good1, good2) => good1.name.localeCompare(good2.name), + ); + + return sortedGoods.slice(0, 5); + }); }; -export const getRedGoods = () => { +export const getRedGoods = (): Promise => { return getAll() - .then(goods => goods); // get only red + .then(goods => goods.filter(good => good.color === 'red')); }; From 84f17ff687510804ea8f4dbc3bb46dc63aefc9ff Mon Sep 17 00:00:00 2001 From: Olena Date: Tue, 25 Jul 2023 23:51:40 +0300 Subject: [PATCH 2/3] fix typo, move arePropsEqual to utils --- src/App.tsx | 8 ++++---- src/GoodsList.tsx | 11 ++--------- src/utils.ts | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 src/utils.ts diff --git a/src/App.tsx b/src/App.tsx index 6610cf02e..4ce005175 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,7 +8,7 @@ export const App: React.FC = () => { const [currentGoods, setCurrentGoods] = useState([]); const [errorMessage, setErrorMessage] = useState(''); - const hadleClick = (fetchFromServer: () => Promise) => { + const handleClick = (fetchFromServer: () => Promise) => { fetchFromServer() .then(goods => { setCurrentGoods(goods); @@ -26,7 +26,7 @@ export const App: React.FC = () => { @@ -34,7 +34,7 @@ export const App: React.FC = () => { @@ -42,7 +42,7 @@ export const App: React.FC = () => { diff --git a/src/GoodsList.tsx b/src/GoodsList.tsx index 6cf26cadd..a274d7cf8 100644 --- a/src/GoodsList.tsx +++ b/src/GoodsList.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { Good } from './types/Good'; +import { arePropsEqual } from './utils'; type Props = { goods: Good[] @@ -17,12 +18,4 @@ export const GoodsList: React.FC = React.memo(({ goods }) => ( ))} -), (prevProps, nextProps) => { - if (prevProps.goods.length !== nextProps.goods.length) { - return false; - } - - return prevProps.goods.every( - (good, index) => good.id === nextProps.goods[index].id, - ); -}); +), arePropsEqual); diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 000000000..d7bd0e1e3 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,17 @@ +import { Good } from './types/Good'; + +type Props = { + goods: Good[], +}; + +type Callback = (goods1: Props, good2: Props) => boolean; + +export const arePropsEqual: Callback = (prevProps, nextProps) => { + if (prevProps.goods.length !== nextProps.goods.length) { + return false; + } + + return prevProps.goods.every( + (good, index) => good.id === nextProps.goods[index].id, + ); +}; From 676fa8878464d615fe265d3ea71680ccf01a7ce9 Mon Sep 17 00:00:00 2001 From: Olena Date: Thu, 27 Jul 2023 22:29:18 +0300 Subject: [PATCH 3/3] fix setting error message --- src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 4ce005175..a49ef9fe6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,10 +9,10 @@ export const App: React.FC = () => { const [errorMessage, setErrorMessage] = useState(''); const handleClick = (fetchFromServer: () => Promise) => { + setErrorMessage(''); fetchFromServer() .then(goods => { setCurrentGoods(goods); - setErrorMessage(''); }) .catch(() => { setErrorMessage('Something went wrong... Try again later!');