diff --git a/README.md b/README.md index aba1d63..446e0f9 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ Check out the different branches to see how this repo evolved over a week of Rea - (main) React components & props - (react-state) React state with useState & useEffect +- (react-lifting-state) React lifting state +- (react-router) Reacter router You can see the changes from day to day in the ["Pull Requests"](https://github.com/TechmongersNL/fs04-react/pulls) in this repo diff --git a/package-lock.json b/package-lock.json index 8e7ff14..7e493da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "axios": "^1.6.5", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.21.3", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" } @@ -3353,6 +3354,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.2.tgz", + "integrity": "sha512-ACXpdMM9hmKZww21yEqWwiLws/UPLhNKvimN8RrYSqPSvB3ov7sLvAcfvaxePeLvccTQKGdkDIhLYApZVDFuKg==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -14937,6 +14946,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.3.tgz", + "integrity": "sha512-a0H638ZXULv1OdkmiK6s6itNhoy33ywxmUFT/xtSoVyf9VnC7n7+VT4LjVzdIHSaF5TIh9ylUgxMXksHTgGrKg==", + "dependencies": { + "@remix-run/router": "1.14.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.3.tgz", + "integrity": "sha512-kNzubk7n4YHSrErzjLK72j0B5i969GsuCGazRl3G6j1zqZBLjuSlYBdVdkDOgzGdPIffUOc9nmgiadTEVoq91g==", + "dependencies": { + "@remix-run/router": "1.14.2", + "react-router": "6.21.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", diff --git a/package.json b/package.json index 906fb59..3e6ba3a 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "axios": "^1.6.5", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.21.3", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, diff --git a/src/App.css b/src/App.css index 74b5e05..7dc8026 100644 --- a/src/App.css +++ b/src/App.css @@ -36,3 +36,7 @@ transform: rotate(360deg); } } + +.background-blue { + background-color: rgb(232, 241, 244); +} diff --git a/src/App.js b/src/App.js index 358e3b6..925c682 100644 --- a/src/App.js +++ b/src/App.js @@ -1,14 +1,27 @@ import "./App.css"; -import CharacterList from "./components/character-list"; +import CharacterListPage from "./pages/character-list-page"; +import { Route, Routes } from "react-router-dom"; +import HomePage from "./pages/home-page"; +import CharacterDetailPage from "./pages/character-detail-page"; // import something from 'some place' // App.js is the entry point to the rest of your app +// You can see how this behavior is set up in src/index.js // This is default behavior for create-react-app function App() { return (
- {/* Now have a new CharactersList component, to keep our App component more clean and organized */} - +
+ Here is a header that appears above every page +
+ + } /> + } /> + } /> + +
+ Here is a footer that appears below every page +
); } diff --git a/src/components/character.js b/src/components/character.js index 45572ed..cd53c4c 100644 --- a/src/components/character.js +++ b/src/components/character.js @@ -1,6 +1,7 @@ // You can import other components and use them too! import Counter from "./counter"; import Image from "./image"; +import { Link } from "react-router-dom"; // A React component is just a function that returns some JSX // Specifically, it returns some JSX with only one parent element @@ -14,12 +15,6 @@ const Character = (props) => { return ( <>

{props.name}

-

Blood type

-

{props.blood}

-

Birthday

-

{props.birthday}

-

Quote

-

{props.quote}

{/* using a component within a component also works! */} {/* Passing props from CharacterList even further down into Counter */} @@ -28,6 +23,14 @@ const Character = (props) => { increaseLikes={props.increaseLikes} id={props.id} /> + {/* Link to /characters/1 if we're looking at Luna with id 1 */} + {/* Link to /characters/2 if we're looking at the second character with id 2 */} + {/* ...etc */} + {/* Then this will get matched to a Route defined in App.js */} + {/* You should never have a colon (:) in your Link "to" */} + + Go to {props.name}'s detail page +
); diff --git a/src/components/counter.js b/src/components/counter.js index b5181f6..8b817d7 100644 --- a/src/components/counter.js +++ b/src/components/counter.js @@ -24,7 +24,6 @@ const Counter = (props) => { > Increase likes -
diff --git a/src/index.js b/src/index.js index d563c0f..b390529 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,16 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./index.css"; +import App from "./App"; +import reportWebVitals from "./reportWebVitals"; +import { BrowserRouter } from "react-router-dom"; -const root = ReactDOM.createRoot(document.getElementById('root')); +const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - + + + ); diff --git a/src/pages/character-detail-page.js b/src/pages/character-detail-page.js new file mode 100644 index 0000000..3bf3c22 --- /dev/null +++ b/src/pages/character-detail-page.js @@ -0,0 +1,47 @@ +import { useParams } from "react-router-dom"; +import axios from "axios"; +import { useEffect, useState } from "react"; +import { Link } from "react-router-dom"; + +const CharacterDetailPage = () => { + // Get the value out of the path + // The useParams hook will get the variable named in your Route in your App.js + // useParams will that path variable in an object that we save into our own params variable + // I expect this to be the id of the character whose details we want to see + const params = useParams(); + console.log(params); + + const [characterDetailInfo, setCharacterDetailInfo] = useState(null); + + // Get the characters detail data from the API + // Use the params object from above to get details for one specific character + const getCharacterDetail = async () => { + const response = await axios.get( + `https://my-json-server.typicode.com/TechmongersNL/fs03-react/characters/${params.id}` + ); + + console.log("response:", response.data); + setCharacterDetailInfo(response.data); + }; + + useEffect(() => { + getCharacterDetail(); + }, []); + + return characterDetailInfo ? ( +
+ Go back to character list +

{characterDetailInfo.name}

+

Blood type

+

{characterDetailInfo.blood}

+

Birthday

+

{characterDetailInfo.born}

+

Quote

+

{characterDetailInfo.quote}

+
+ ) : ( + "Loading..." + ); +}; + +export default CharacterDetailPage; diff --git a/src/pages/character-list-page.js b/src/pages/character-list-page.js new file mode 100644 index 0000000..7ee95c1 --- /dev/null +++ b/src/pages/character-list-page.js @@ -0,0 +1,13 @@ +import { Link } from "react-router-dom"; +import CharacterList from "../components/character-list"; + +const CharacterListPage = () => { + return ( +
+ Go back to Home Page + +
+ ); +}; + +export default CharacterListPage; diff --git a/src/pages/home-page.js b/src/pages/home-page.js new file mode 100644 index 0000000..7738f30 --- /dev/null +++ b/src/pages/home-page.js @@ -0,0 +1,12 @@ +import { Link } from "react-router-dom"; + +const HomePage = () => { + return ( + <> +

Home Page

+ Go to Character List page + + ); +}; + +export default HomePage;