This commit is contained in:
BIN
05_react/unterricht/tag55/react-app-advanced.zip
Normal file
BIN
05_react/unterricht/tag55/react-app-advanced.zip
Normal file
Binary file not shown.
@@ -1,3 +1,4 @@
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import FooterMain from './components/footers/FooterMain';
|
||||
import HeaderMain from './components/headers/HeaderMain';
|
||||
import NavMain from './components/navs/NavMain';
|
||||
@@ -5,10 +6,12 @@ import Router from './routes/Router';
|
||||
|
||||
function App(props) {
|
||||
// const { } = props;
|
||||
const { pathname: path } = useLocation();
|
||||
|
||||
console.log(path);
|
||||
return (
|
||||
<>
|
||||
<HeaderMain />
|
||||
{path === '/' && <HeaderMain />}
|
||||
<NavMain />
|
||||
<main id="main">
|
||||
<Router />
|
||||
|
||||
@@ -1,82 +1,21 @@
|
||||
import { useCallback, useMemo, useReducer, useState } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import RowProduct from './content/RowProduct';
|
||||
import { ProductsProvider, useProductsState } from '../../stores/products';
|
||||
|
||||
// Reducer (bei größerer Applikaitonsstuktur ausgelagert)
|
||||
const initialState = (props) => {
|
||||
// Validierung und Error Checks
|
||||
return { items: props.items || [] };
|
||||
};
|
||||
const TableProductsView = (props) => {
|
||||
const { items } = useProductsState();
|
||||
// const dispatch = useProductsDispatch()
|
||||
|
||||
const reducer = (state, action) => {
|
||||
const { type, payload } = action;
|
||||
switch (type) {
|
||||
case 'UPDATE_AMOUNT':
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id
|
||||
? { ...item, stock: payload.amount } //
|
||||
: item,
|
||||
),
|
||||
};
|
||||
case 'UPDATE_PRICE':
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id
|
||||
? { ...item, price: payload.price } //
|
||||
: item,
|
||||
),
|
||||
};
|
||||
default:
|
||||
console.warn('no action found');
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const TableProducts = (props) => {
|
||||
// const {
|
||||
// items = [
|
||||
// {
|
||||
// _id: '1',
|
||||
// title: 'Example Product 1',
|
||||
// sku: 'ABC1234',
|
||||
// stock: 2,
|
||||
// price: 15.2,
|
||||
// },
|
||||
// ],
|
||||
// } = props;
|
||||
|
||||
const [{ items }, dispatch] = useReducer(reducer, initialState(props));
|
||||
|
||||
// const [items, setItems] = useState(
|
||||
// props.items || [
|
||||
// {
|
||||
// _id: '1',
|
||||
// title: 'Example Product 1',
|
||||
// sku: 'ABC1234',
|
||||
// stock: 2,
|
||||
// price: 15.2,
|
||||
// },
|
||||
// ],
|
||||
// );
|
||||
//const [{ items }, dispatch] = useReducer(reducer, initialState(props));
|
||||
|
||||
// EventHandler ============
|
||||
const handleAmount = useCallback((amount, id) => {
|
||||
dispatch({ type: 'UPDATE_AMOUNT', payload: { amount, id } });
|
||||
// const handleAmount = useCallback((amount, id) => {
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_AMOUNT, payload: { amount, id } });
|
||||
// }, []);
|
||||
|
||||
// setItems((prevItems) => {
|
||||
// return prevItems.map((item) => (item._id === id ? { ...item, stock: amount } : item));
|
||||
// });
|
||||
}, []);
|
||||
|
||||
const handlePrice = useCallback((price, id) => {
|
||||
dispatch({ type: 'UPDATE_PRICE', payload: { price, id } });
|
||||
|
||||
// setItems((prevItems) => {
|
||||
// return prevItems.map((item) => (item._id === id ? { ...item, price: price } : item));
|
||||
// });
|
||||
}, []);
|
||||
// const handlePrice = useCallback((price, id) => {
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_PRICE, payload: { price, id } });
|
||||
// }, []);
|
||||
|
||||
// Functions ===============
|
||||
const totalPrice = useMemo(() => {
|
||||
@@ -91,13 +30,6 @@ const TableProducts = (props) => {
|
||||
if (el) console.log(el);
|
||||
}, []);
|
||||
|
||||
// const getTotalPrice = () => {
|
||||
// // [0, {stock: 2, price, 15.2}, {...}]
|
||||
// return items.reduce((sum, obj) => {
|
||||
// return sum + Number(obj.stock) * Number(obj.price);
|
||||
// }, 0);
|
||||
// };
|
||||
|
||||
return (
|
||||
<div className="m-table-products table-products">
|
||||
<div className="container py-2">
|
||||
@@ -117,8 +49,8 @@ const TableProducts = (props) => {
|
||||
<RowProduct
|
||||
key={`row-product-${idx}`}
|
||||
{...product}
|
||||
onHandleAmount={handleAmount}
|
||||
onHandlePrice={handlePrice}
|
||||
// onHandleAmount={handleAmount}
|
||||
// onHandlePrice={handlePrice}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -133,4 +65,14 @@ const TableProducts = (props) => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TableProducts = (props) => {
|
||||
// const { } = props;
|
||||
|
||||
return (
|
||||
<ProductsProvider items={props.items}>
|
||||
<TableProductsView />
|
||||
</ProductsProvider>
|
||||
);
|
||||
};
|
||||
export default TableProducts;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
// import { useState } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useProductsActions } from '../../../stores/products'; // /index.js muss nicht angegeben werden (wg. Bundler)
|
||||
// import { useProductsDispatch } from '../../../stores/products';
|
||||
// import { PRODUCTS_ACTIONS } from '../../../stores/products';
|
||||
|
||||
import InputAmount from '../../inputs/InputAmount';
|
||||
import InputPrice from '../../inputs/InputPrice';
|
||||
|
||||
@@ -6,19 +10,35 @@ const RowProduct = (props) => {
|
||||
const { _id, sku = '', stock: amount = 0, price = 0, title = '' } = props;
|
||||
//const { sku = '', title = '' } = props;
|
||||
|
||||
// const [amount, setAmount] = useState(props.stock || 0);
|
||||
// const [price, setPrice] = useState(props.price || 0);
|
||||
const { updateAmount, updatePrice } = useProductsActions();
|
||||
// const dispatch = useProductsDispatch();
|
||||
|
||||
// Eventhandler
|
||||
const handleAmount = (val) => {
|
||||
// setAmount(val);
|
||||
props.onHandleAmount(val, _id);
|
||||
};
|
||||
// const handleAmount = useCallback((val) => {
|
||||
// // setAmount(val);
|
||||
// // props.onHandleAmount(val, _id);
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_AMOUNT, payload: { amount: val, id: _id } });
|
||||
// }, []);
|
||||
|
||||
const handlePrice = (val) => {
|
||||
// setPrice(val);
|
||||
props.onHandlePrice(val, _id);
|
||||
};
|
||||
const handleAmount = useCallback(
|
||||
(val) => {
|
||||
updateAmount(val, _id);
|
||||
},
|
||||
[updateAmount, _id],
|
||||
);
|
||||
|
||||
// const handlePrice = (val) => {
|
||||
// // setPrice(val);
|
||||
// // props.onHandlePrice(val, _id);
|
||||
// dispatch({ type: PRODUCTS_ACTIONS.UPDATE_PRICE, payload: { price: val, id: _id } });
|
||||
// };
|
||||
|
||||
const handlePrice = useCallback(
|
||||
(val) => {
|
||||
updatePrice(val, _id);
|
||||
},
|
||||
[updatePrice, _id],
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className="row-product">
|
||||
@@ -34,4 +54,4 @@ const RowProduct = (props) => {
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
export default RowProduct;
|
||||
export default memo(RowProduct);
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { createContext, useCallback, useContext, useReducer } from 'react';
|
||||
import { PRODUCTS_ACTIONS, productsReducer } from './reducer';
|
||||
import { createInitialState } from './initialState';
|
||||
|
||||
const ProductsStateContext = createContext(null);
|
||||
const ProductsDispatchContext = createContext(null);
|
||||
|
||||
// const ProductsContext = createContext(null);
|
||||
|
||||
export const ProductsProvider = (props) => {
|
||||
const { children, items = [] } = props;
|
||||
|
||||
const [state, dispatch] = useReducer(productsReducer, items, createInitialState);
|
||||
|
||||
return (
|
||||
// <ProductsContext.Provider value={{state, dispatch}}>
|
||||
// {children}
|
||||
// </ProductsContext.Provider>
|
||||
|
||||
<ProductsStateContext.Provider value={state}>
|
||||
<ProductsDispatchContext.Provider value={dispatch}>{children}</ProductsDispatchContext.Provider>
|
||||
</ProductsStateContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// eigene Hooks mit ErrorHandler
|
||||
export const useProductsState = () => {
|
||||
const state = useContext(ProductsStateContext);
|
||||
|
||||
if (state == null) {
|
||||
throw Error('useProductsState muss innerhalb von ProductsProvider verwendet werden.');
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
export const useProductsDispatch = () => {
|
||||
const dispatch = useContext(ProductsDispatchContext);
|
||||
|
||||
if (dispatch == null) {
|
||||
throw Error('useProductsDispatch muss innerhalb von ProductsProvider verwendet werden.');
|
||||
}
|
||||
|
||||
return dispatch;
|
||||
};
|
||||
|
||||
export const useProductsActions = () => {
|
||||
const dispatch = useProductsDispatch();
|
||||
|
||||
const updateAmount = useCallback(
|
||||
(amount, id) => {
|
||||
dispatch({ type: PRODUCTS_ACTIONS.UPDATE_AMOUNT, payload: { id, amount } });
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const updatePrice = useCallback(
|
||||
(price, id) => {
|
||||
dispatch({ type: PRODUCTS_ACTIONS.UPDATE_PRICE, payload: { id, price } });
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
return {
|
||||
updateAmount,
|
||||
updatePrice,
|
||||
};
|
||||
};
|
||||
3
05_react/unterricht/tag55/react-app-advanced/src/stores/products/index.js
vendored
Normal file
3
05_react/unterricht/tag55/react-app-advanced/src/stores/products/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export { createInitialState } from './initialState';
|
||||
export { PRODUCTS_ACTIONS, productsReducer } from './reducer';
|
||||
export { ProductsProvider, useProductsActions, useProductsDispatch, useProductsState } from './ProductsStore';
|
||||
7
05_react/unterricht/tag55/react-app-advanced/src/stores/products/initialState.js
vendored
Normal file
7
05_react/unterricht/tag55/react-app-advanced/src/stores/products/initialState.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// import mit {}
|
||||
export const createInitialState = (items) => {
|
||||
// validation and sanitizing
|
||||
return { items: items || [] };
|
||||
};
|
||||
|
||||
export default createInitialState; // import mit eigener Benennung möglich
|
||||
36
05_react/unterricht/tag55/react-app-advanced/src/stores/products/reducer.js
vendored
Normal file
36
05_react/unterricht/tag55/react-app-advanced/src/stores/products/reducer.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// in ts enum
|
||||
export const PRODUCTS_ACTIONS = {
|
||||
UPDATE_AMOUNT: 'UPDATE_AMOUNT',
|
||||
UPDATE_PRICE: 'UPDATE_PRICE',
|
||||
};
|
||||
|
||||
export const productsReducer = (state, action) => {
|
||||
const { type, payload } = action;
|
||||
|
||||
console.log(state);
|
||||
|
||||
switch (type) {
|
||||
case PRODUCTS_ACTIONS.UPDATE_AMOUNT:
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id //
|
||||
? { ...item, stock: payload.amount }
|
||||
: item,
|
||||
),
|
||||
};
|
||||
|
||||
case PRODUCTS_ACTIONS.UPDATE_PRICE:
|
||||
return {
|
||||
...state,
|
||||
items: state.items.map((item) =>
|
||||
item._id === payload.id //
|
||||
? { ...item, price: payload.price }
|
||||
: item,
|
||||
),
|
||||
};
|
||||
default:
|
||||
console.warn('no action found');
|
||||
return state;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user