Skip to content

Commit

Permalink
Merge branch 'redux-toolkit'
Browse files Browse the repository at this point in the history
  • Loading branch information
mathiasbergqvist committed Oct 10, 2024
2 parents 23b9fa8 + 6b2208e commit a7fa1b6
Show file tree
Hide file tree
Showing 25 changed files with 355 additions and 188 deletions.
28 changes: 13 additions & 15 deletions lab1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,18 @@

1. Skapa ett nytt projekt med create-react-app CLI

1. `$ npx create-react-app my-app`
1. `$ npx create-react-app my-app`. _`npx` är en package runner för att köra npm-paket direkt från kommandoraden utan att behöva installera dem globalt_.

2. Kör projektet
1. `$ cd my-app`
2. `$ npm start`
3. Nu bör ett browser-fönster med en grundapp i React öppnas.
4. Om du inte redan har React Developer Tools till din browser, ladda ner detta nu.
[React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)

2. Kör projektet
1. `$ cd my-app`
2. `$ npm start`
3. Nu bör ett browser-fönster med en grundapp i React öppnas.
4. Om du inte redan har React Developer Tools till din browser, ladda ner detta nu.
[React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)
3. Kolla runt i källkoden och fundera på/testa att...
1. Vad får jag out of the box?
2. Vilka paket är installerade?
3. Vilka beroenden har React?
4. Vilka komponenter existerar från början? ___Hint: React Devtools Extension___
5. Ersätt texten "Edit src/App.jsx and save to reload." med "Peace, Love & OP Web". Du behöver INTE kompilera om vid ändringar!
6. Lek runt lite!

1. Vad får jag out of the box?
2. Vilka paket är installerade?
3. Vilka beroenden har React?
4. Vilka komponenter existerar från början? **_Hint: React Devtools Extension_**
5. Ersätt texten "Edit src/App.jsx and save to reload." med "Peace, Love & OP Web". Du behöver INTE kompilera om vid ändringar!
6. Lek runt lite!
3 changes: 2 additions & 1 deletion lab2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ Från projektroten: `$ cd lab2`, `$ npm install` följt av `$ npm start`. Gå se

1. Hjälp en vän.
2. Utöka List-komponenten till att innehålla lite mer detaljerad användarinformation för varje item i listan.
3. Ta en kaffe ☕️
3. Testa att skapa och styla en egen komponent från grunden.
4. Ta en kaffe ☕️
7 changes: 2 additions & 5 deletions lab2/src/components/App/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const App = () => {
}, []);

const changeBackgroundColor = (e) => {
// const color = e.target.value;
const color = e.target.value;
// TODO: Task 3 - change background color by setting state.
};

Expand All @@ -35,10 +35,7 @@ const App = () => {
</p>
</div>
<BackgroundColorPicker onChange={changeBackgroundColor} />
<List
title={/*TODO: Task 2*/ "*Insert title"}
items={/*TODO: Task 4 */ []}
/>
<List title="*Insert title" items={/*TODO: Task 4 */ []} />
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions lab2/src/components/List/List.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const List = ({ items = [], title }) => {

// TODO: Task 8: Set up filtering by declaring filteredItems.
// const filteredItems = ...

return (
<div className="List">
<h2 className="List-title">{title}</h2>
Expand Down
61 changes: 39 additions & 22 deletions lab3/DO_NOT_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

### Task 2

I `backgroundReducers.js`:
I `avatarSlice.js`:

```javascript
const initialState = {
Expand All @@ -14,47 +14,64 @@ const initialState = {

### Task 3

I `userActions.js`:
I `avatarSlice.js`:

```javascript
.then((users) => {
dispatch({
type: USERS_RECEIVED,
payload: users
})
})
const avatarSlice = createSlice({
name: "avatar",
initialState,
reducers: {
updatedAvatar: (state, action) => {
state.currentAvatar = action.payload;
},
},
});
```

### Task 4

I `userReducers.js`:
I `avatarSlice.js`:

```javascript
...
case USERS_RECEIVED:
return {
all: action.payload,
error: null
};
...
const avatarSlice = createSlice({
name: "avatar",
initialState,
reducers: {
updatedAvatar: (state, action) => {
state.currentAvatar = action.payload;
},
resetAvatar: (state, action) => {
state.currentAvatar = null;
},
},
});
...
...
export const { updatedAvatar, resetAvatar } = avatarSlice.actions;
```

### Task 5

I `Container.jsx`:
I `AvatarPicker.jsx`:

```javascript
useEffect(() => {
dispatch(getAllUsers());
}, []);
const dispatch = useDispatch();

const handleOnClick = (avatar) => {
dispatch(updatedAvatar(avatar));
};

const handleOnReset = () => {
dispatch(resetAvatar());
};
```

### Task 6

I `List.jsx`:
I `NavBar.jsx`:

```javascript
const users = useSelector((state) => state.users.all);
const avatar = useSelector(selectCurrentAvatar);
```

## Del 2
Expand Down
18 changes: 9 additions & 9 deletions lab3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@ Från projektroten: `$ cd lab3`, `$ npm install` följt av `$ npm start`. Gå se
## Del 1 - Redux-snurran

1. Ta en till på befintliga komponenter och hur Redux-snurran är implementerad för att välja bakgrund. Ladda ner och använd [Redux DevTools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) för detta.
2. Bakgrundsfärgen är satt till `lavender` från början via initialState. Byt default från `lavender` till `gold`._Hint: Detta görs i en reducer_
3. Användarna visas inte i listan just nu. Börja med att dispatcha ett action när användare har hämtats asynkront i `userActions`.
4. När vi har dispatchat en action måste vi hantera den i våra reducers. Öppna `userReducers.js` och stoppa in resultatet från din nya action i applikationens state.
5. I `Container.jsx` har vi nu möjlighet att dipatcha actions tack vare vår hooks `useDispatch()`. Vi vill här hämta alla användare när komponenten mountas i `useEffect()` med vår nyss implementerade action creator. Implementera detta och bekräfta att det fungerar med Redux Dev Tools.
6. Nu när vi har användaren i vår store vill vi kunna läsa dom i komponenten `List.jsx`. Deklarera konstanten `users` i `List.jsx` med hjälp av `useSelector()`. Just nu är den bara en tom array. _Hint: Hur används `useSelector()` i `container.js`?_
2. Bakgrundsfärgen är satt till `lavender` från början via initialState. Byt default från `lavender` till `gold`._Hint: Detta görs i en slice_
3. Vår applikation har fått ny feature, en avatar-väljare. Men just nu fungererar den inte alls. Det ska vi fixa med Redux! Börja med att göra klart logien för att uppdatera vårt state i action-funktionen `updatedAvatar` i `avatarSlice.js`.
4. Lägg även till ytterligare en ny action i `avatarSlice.js` som nollställer `currentAvatar`. Glöm inte bort att exportera den tillsammans med `updatedAvatar`!
5. Nu vill vi dispatch:a våra två nya actions från `AvatarPicker.jsx`. Kontrollera att det fungerar med Redux Dev Tools. Du ska nu kunna se actions som skickas och att vårt state uppdateras.
6. Nu när vi har rätt värde i vår store kan vi läsa ut det vart vi vill. Använd `useSelector()` i `NavBar.jsx` för att välja ut vår avatar. Deklarera om konstanten `avatar`.
7. Nu ska applikationen fungera fullt ut!

## Del 2 - Egen komponent

Nu är det dags att sätta allt du lärt dig hittills på prov. Gör så långt du hinner. Uppgiften är att du ska skapa en egen komponent och visa detaljerad användarinformation i denna. I `List.jsx` finns det nu en callback, `onClick`, som kommer att skicka med ett id för användaren som klickades på. I `api.js` finns det en funktion som hämtar användardata baserat på ett id.
Nu är det dags att sätta allt du lärt dig hittills på prov. Gör så långt du hinner. Uppgiften är att du ska skapa en egen komponent och visa detaljerad användarinformation i denna när man klickat på en av användarna i listan. I `List.jsx` finns det nu en callback, `onClick`, som kommer att skicka med ett id för användaren som klickades på. I `api.js` finns det en funktion som hämtar användardata baserat på ett id.

För att lösa uppgiften behöver du:

- Skapa en ny komponent `<UserDetails>` (eller liknande namn) och använda denna i `Container.jsx`.
- `<UserDetails>` behöver rendera ut JSX för detaljerad användardata.
- Skapa en ny action creator i `userActions.js` som tar in ett id och gör ett asynkront anrop mot `api.js` för att hämta ut detaljerad användardata.
- Utöka state för `userReducers.js` till att även innehålla detaljerad användardata och hantera en ny typ av inkommande action.
- Dispatcha ett nytt action för detaljerad användardata från `onItemClick()` i `List.jsx` via `useDispatch()`.
- Skapa en ny action `userSlice.js` som tar in ett id och gör ett asynkront anrop mot `api.js` för att hämta ut detaljerad användardata för en användare.
- Utöka state i `userSlice.js` till att även innehålla detaljerad användardata.
- Dispatcha en nytt action för detaljerad användardata från `onItemClick()` i `List.jsx` via `useDispatch()`.
- Läsa in den detaljerade användardatan från applikationens state till din nya komponent.

##### _Del två finns löst i solutions-branchen om du bara vill se lösningen_ 😇
Expand Down
10 changes: 0 additions & 10 deletions lab3/src/actions/backgroundActions.js

This file was deleted.

27 changes: 0 additions & 27 deletions lab3/src/actions/userActions.js

This file was deleted.

5 changes: 1 addition & 4 deletions lab3/src/components/App/App.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import React from "react";
import Container from "../Container/Container";
import { Provider } from "react-redux";
import configureStore from "../../store";
import store from "../../store";

import "./App.css";

const preloadedState = window.__PRELOADED_STATE__;
const store = configureStore(preloadedState);

const App = () => (
<Provider store={store}>
<Container />
Expand Down
4 changes: 4 additions & 0 deletions lab3/src/components/AvatarPicker/AvatarPicker.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.buttonContainer {
display: flex;
gap: 10px;
}
42 changes: 42 additions & 0 deletions lab3/src/components/AvatarPicker/AvatarPicker.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from "react";
import { useDispatch } from "react-redux";
import {
resetAvatar,
updatedAvatar,
selectCurrentAvatar,
} from "../../features/avatar/avatarSlice";
import "./AvatarPicker.css";

const AvatarPicker = () => {
const dispatch = useDispatch();

const handleOnClick = (avatar) => {
// TODO: Task 5 - dispatch
};

const handleOnReset = () => {
// TODO: Task 5 - dispatch
};

return (
<div>
<h5>Välj avatar</h5>
<div className="buttonContainer">
<button className="btn btn-primary" onClick={() => handleOnClick("🦊")}>
Fox
</button>
<button className="btn btn-primary" onClick={() => handleOnClick("🐢")}>
Turtle
</button>
<button className="btn btn-primary" onClick={() => handleOnClick("🦩")}>
Flamingo
</button>
<button className="btn btn-primary" onClick={() => handleOnReset()}>
Reset
</button>
</div>
</div>
);
};

export default AvatarPicker;
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from "react";
import { useDispatch } from "react-redux";
import { setBackgroundColor } from "../../actions/backgroundActions";
import colors from "./colors";
import { updatedBackgroundColor } from "../../features/background/backgroundSlice";
import "./BackgroundColorPicker.css";

const BackgroundColorPicker = () => {
const dispatch = useDispatch();

const handleOnChange = (e) => {
dispatch(setBackgroundColor(e.target.value));
dispatch(updatedBackgroundColor(e.target.value));
};

return (
Expand Down
52 changes: 30 additions & 22 deletions lab3/src/components/Container/Container.jsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
import React, { useEffect } from "react";
import BackgroundColorPicker from "../BackgroundColorPicker/BackgroundColorPicker";
import List from "../List/List";
import AvatarPicker from "../AvatarPicker/AvatarPicker";
import { useDispatch, useSelector } from "react-redux";
import { getAllUsers } from "../../actions/userActions";
import { selectBackgroundColor } from "../../features/background/backgroundSlice";
import { fetchUsers } from "../../features/users/usersSlice";

import "./Container.css";
import NavBar from "../NavBar/NavBar";

const Container = () => {
const dispatch = useDispatch();
const backgroundColor = useSelector((state) => state.background.bgColor);
const backgroundColor = useSelector(selectBackgroundColor);

// TODO: Task 5 - Get all users upon mounting the component
useEffect(() => {}, []);
useEffect(() => {
dispatch(fetchUsers());
}, []);

return (
<div
className="Container container"
style={{ background: backgroundColor }}
>
<div className="Container-header">
<p>Lab 3</p>
<p className="Container-header-description">
<span role="img" aria-label="female technologist">
👩‍💻
</span>{" "}
Öppna upp README.md och följ instruktionerna{" "}
<span role="img" aria-label="male technologist">
👨‍💻
</span>
</p>
<>
<div
className="Container container"
style={{ background: backgroundColor }}
>
<NavBar />
<div className="Container-header">
<p>Lab 3</p>
<p className="Container-header-description">
<span role="img" aria-label="female technologist">
👩‍💻
</span>{" "}
Öppna upp README.md och följ instruktionerna{" "}
<span role="img" aria-label="male technologist">
👨‍💻
</span>
</p>
</div>
<BackgroundColorPicker />
<AvatarPicker />
<List title="Users" />
</div>
<BackgroundColorPicker />
<List title="Users" />
</div>
</>
);
};

Expand Down
Loading

0 comments on commit a7fa1b6

Please sign in to comment.