From f7687b5f75d6605f8fa4477114e0878b00e02b8c Mon Sep 17 00:00:00 2001 From: tessawiedmann Date: Thu, 23 Nov 2023 12:30:30 +0100 Subject: [PATCH 1/4] useState notes and lecture code --- README.md | 14 +++++++++++++- src/App.js | 3 ++- src/components/character.js | 4 +++- src/components/like-counter.js | 35 ++++++++++++++++++++++++++++++++++ src/styles/like-counter.css | 4 ++++ 5 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/components/like-counter.js create mode 100644 src/styles/like-counter.css diff --git a/README.md b/README.md index cf7f850..3f2faa7 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,16 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo ## Setup - Git clone this repo - Run `npm install` to install all the dependencies listed in package.json -- Run `npm run start` to start the local development server \ No newline at end of file +- Run `npm run start` to start the local development server + +## What are React Hooks? +- Functions that let you perform a specific task inside React, like "hooking into" React state or component lifecycles +- Start with the word "use" -- useState and useEffect for example +- Pieces of code (functions) that someone wrote +- Hooks can be inside React or you can import them from somewhere else, but today we'll focus on just useState and useEffect from React +- You can write your own hooks (custom hooks) + +## useState +-A hook that creates state variables that React listens to. It "reacts" when the values of these state variables change +- Used when we have variables whose value should change when an event happens (user generated) +- When the value of the state variable changes, React re-renders the component in a smart, optimized way for you diff --git a/src/App.js b/src/App.js index c44fa02..1281092 100644 --- a/src/App.js +++ b/src/App.js @@ -24,9 +24,10 @@ function App() { { /* The result of map is another array with new data */} { /* In our case, this new data is a Character component */} { - charactersData.map((character) => { + charactersData.map((character, index) => { return ( const Character = (props) => { - console.log(props) + //console.log(props) // React requires you return only one parent element // You can use a React Fragment (an empty html element) to fix this issue return ( @@ -21,6 +22,7 @@ const Character = (props) => {

Quote

{props.quote}

+
) diff --git a/src/components/like-counter.js b/src/components/like-counter.js new file mode 100644 index 0000000..762cfdb --- /dev/null +++ b/src/components/like-counter.js @@ -0,0 +1,35 @@ +import {useState} from 'react'; +import '../styles/like-counter.css'; + +const LikeCounter = () => { + const [count, setCount] = useState(0); + const [favorite, setFavorite] = useState(false); + + const whenIncreaseButtonClicked = () => { + setCount(count + 1); + }; + const whenDecreaseButtonClicked = () => { + if (count > 0) { + setCount(count - 1); + } + } + + return ( + <> +
+

Number of likes: {count}

+ + +
+
+

{favorite && '⭐️'}

+ +
+ + ) +} + +export default LikeCounter; \ No newline at end of file diff --git a/src/styles/like-counter.css b/src/styles/like-counter.css new file mode 100644 index 0000000..d63f939 --- /dev/null +++ b/src/styles/like-counter.css @@ -0,0 +1,4 @@ +.buttonStyle { + padding: 10px; + background-color: pink; +} \ No newline at end of file From 276e1fded7bec934ff346313635fc9ac24844d74 Mon Sep 17 00:00:00 2001 From: tessawiedmann Date: Thu, 23 Nov 2023 15:17:54 +0100 Subject: [PATCH 2/4] Imported axios --- package-lock.json | 29 +++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 30 insertions(+) diff --git a/package-lock.json b/package-lock.json index ae01267..3424db4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.6.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", @@ -5321,6 +5322,29 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -14443,6 +14467,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", diff --git a/package.json b/package.json index 6e75333..e232f7a 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.6.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", From b09900562dcb289fa1948866b06d70c1d8942c5b Mon Sep 17 00:00:00 2001 From: tessawiedmann Date: Thu, 23 Nov 2023 15:18:43 +0100 Subject: [PATCH 3/4] Refactored App.js to use new CharactersList component --- src/App.js | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/App.js b/src/App.js index 1281092..7dbbc3d 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,7 @@ import './App.css'; import Character from './components/character'; import charactersData from './charactersData'; +import CharacterList from './components/character-list'; // import something from 'some place' // Creating a new function component in the same file @@ -23,24 +24,8 @@ function App() { { /* The below array iterator (map), loops over every element in the charactersData array */} { /* The result of map is another array with new data */} { /* In our case, this new data is a Character component */} - { - charactersData.map((character, index) => { - return ( - - ) - }) - } + { /* Using array iterator (map) instead of repeating like below: */ } - - - ); } From ee7edb28dabd1b6aec3bab516920662dc64e5f84 Mon Sep 17 00:00:00 2001 From: tessawiedmann Date: Thu, 23 Nov 2023 15:33:30 +0100 Subject: [PATCH 4/4] Add useEffect --- README.md | 16 ++++++++++- src/components/character-list.js | 48 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/components/character-list.js diff --git a/README.md b/README.md index 3f2faa7..9651a8d 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,20 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo - You can write your own hooks (custom hooks) ## useState --A hook that creates state variables that React listens to. It "reacts" when the values of these state variables change +- A hook that creates state variables that React listens to. It "reacts" when the values of these state variables change - Used when we have variables whose value should change when an event happens (user generated) - When the value of the state variable changes, React re-renders the component in a smart, optimized way for you + +## useEffect +- A hook thats used when you want React to re-render without user interaction +- Used to fetch data (async) +- Helps control the amount of re-renders on the page + +Fetching data from API flow +1. Write an async function +2. Make a request with axios +3. Console.log what I'm getting back to make sure it's what I expect (and don't forget to call the function) +4. Import useEffect from 'react' +5. Call the async function inside useEffect +6. Check my console.log and put the data in the state +7. Render something on the screen based on state diff --git a/src/components/character-list.js b/src/components/character-list.js new file mode 100644 index 0000000..23d9f2e --- /dev/null +++ b/src/components/character-list.js @@ -0,0 +1,48 @@ +import Character from "./character"; +import axios from 'axios'; +import {useEffect, useState} from 'react'; +//import charactersData from "../charactersData"; +// ^ we don't have to import from charactersData anymore! We can now make a network request with axios + +const CharacterList = () => { + const [characters, setCharacters] = useState(null); + + const getCharacters = async () => { + const response = await axios.get('https://my-json-server.typicode.com/TechmongersNL/fs03-react/characters'); + console.log(response.data); + setCharacters(response.data); + } + + // If you don't put getCharacters in a useEffect hook, getCharacters will be called (and will make an Axios request) every time CharactersList gets re-rendered + // We only want getCharacters to be called once, the first time getCharacters is rendered, which we can do by using useEffect with an empty dependency array at the end + // Don't do this!: + //getCharacters(); + // Instead, do this: + useEffect(() => { + getCharacters(); + }, []); + + const getCharactersComponents = () => { + return characters.map((character, index) => { + return ( + + ) + }) + } + + return ( + // if characters data is not null (the initial value of the characters state variable) + // then I want to show Characters components + // else I want to show "loading..." + characters ? getCharactersComponents() : 'Loading...' + ) +} + +export default CharacterList; \ No newline at end of file