This commit is contained in:
3899
05_react/unterricht/tag52/01_react-app-performance/package-lock.json
generated
Normal file
3899
05_react/unterricht/tag52/01_react-app-performance/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,12 @@
|
|||||||
import Button from './components/buttons/Button';
|
import Button from './components/buttons/Button';
|
||||||
import ExampleComponent from './components/examples/ExampleComponent';
|
import ExampleComponent from './components/examples/ExampleComponent';
|
||||||
import ExampleCounter from './components/examples/ExampleCounter';
|
import ExampleCounter from './components/examples/ExampleCounter';
|
||||||
|
import ExampleLazy from './components/examples/ExampleLazy';
|
||||||
|
import ExampleMemoParent from './components/examples/ExampleMemoParent';
|
||||||
|
import ExampleUseCallback from './components/examples/ExampleUseCallback';
|
||||||
|
import ExampleUseCallbackRef from './components/examples/ExampleUseCallbackRef';
|
||||||
|
import ExampleUseMemo from './components/examples/ExampleUseMemo';
|
||||||
|
import ExampleUseRef from './components/examples/ExampleUseRef';
|
||||||
import InputAmount from './components/inputs/InputAmount';
|
import InputAmount from './components/inputs/InputAmount';
|
||||||
|
|
||||||
// import FormContact from './components/forms/FormContact';
|
// import FormContact from './components/forms/FormContact';
|
||||||
@@ -12,6 +18,18 @@ function App(props) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="container py-5">
|
<div className="container py-5">
|
||||||
|
<ExampleLazy />
|
||||||
|
<hr />
|
||||||
|
<ExampleUseCallbackRef />
|
||||||
|
{/* <hr />
|
||||||
|
<ExampleUseRef /> */}
|
||||||
|
<hr />
|
||||||
|
<ExampleUseCallback />
|
||||||
|
<hr />
|
||||||
|
<ExampleMemoParent />
|
||||||
|
<hr />
|
||||||
|
<ExampleUseMemo />
|
||||||
|
<hr />
|
||||||
<ExampleCounter />
|
<ExampleCounter />
|
||||||
<hr />
|
<hr />
|
||||||
<InputAmount />
|
<InputAmount />
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import LazyComponent from './LazyComponent';
|
||||||
|
|
||||||
|
const ExampleLazy = (props) => {
|
||||||
|
// const { } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="example-lazy">
|
||||||
|
<p>The content below will only be loaded when the component is needed</p>
|
||||||
|
<LazyComponent />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ExampleLazy;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
const ExampleMemo = (props) => {
|
||||||
|
const { name } = props;
|
||||||
|
|
||||||
|
console.log('ExampleMemo is rendered');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="example-memo">
|
||||||
|
<p>Hello, {name}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default memo(ExampleMemo);
|
||||||
|
// rendert nur neu, wenn sich props (hier: name) verändert
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import ExampleMemo from './ExampleMemo';
|
||||||
|
|
||||||
|
const ExampleMemoParent = (props) => {
|
||||||
|
// const { } = props;
|
||||||
|
const [name, setName] = useState('World');
|
||||||
|
const [counter, setCounter] = useState(0);
|
||||||
|
|
||||||
|
const names = ['Kahleel', 'Andreas', 'Ersin', 'Adel', 'Philippe'];
|
||||||
|
|
||||||
|
const handleClickCounter = (e) => {
|
||||||
|
setCounter((prevState) => prevState + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickName = (e) => {
|
||||||
|
setName(names[Math.floor(Math.random() * names.length)]);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="example-memo-parent">
|
||||||
|
<ExampleMemo name={name} />
|
||||||
|
|
||||||
|
<p>Parent component is rendering: {counter}</p>
|
||||||
|
|
||||||
|
<button className="btn btn-dark mx-2 button-counter" onClick={handleClickCounter}>
|
||||||
|
Click to render and count up
|
||||||
|
</button>
|
||||||
|
<button className="btn btn-dark mx-2 button-name" onClick={handleClickName}>
|
||||||
|
Change name randomized
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ExampleMemoParent;
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import ListItemProduct from './ListItemProduct';
|
||||||
|
|
||||||
|
const ExampleUseCallback = (props) => {
|
||||||
|
// const { } = props;
|
||||||
|
const [products, setProducts] = useState(
|
||||||
|
props.products || [
|
||||||
|
{ id: 1, title: 'Product 1', description: 'lorem ipsum', price: 10 },
|
||||||
|
{ id: 2, title: 'Product 2', description: 'ipsum lorem', price: 20 },
|
||||||
|
{ id: 3, title: 'Product 3', description: 'lorem dolor', price: 30 },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleClick = useCallback((e, productId) => {
|
||||||
|
setProducts((prevProducts) => {
|
||||||
|
return prevProducts.map((product) => {
|
||||||
|
if (product.id === productId) {
|
||||||
|
return { ...product, price: parseFloat(product.price + 1) };
|
||||||
|
} else {
|
||||||
|
return product;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, []); // <-- leere dependency- Array sorgt dafür, dass die callback funktion und somit der Event-Handler nur einmalig ausgeführt/angelegt wird.
|
||||||
|
|
||||||
|
// EventHandler =================
|
||||||
|
// const handleClick = (e, productId) => {
|
||||||
|
// console.log('Product clicked:', productId);
|
||||||
|
|
||||||
|
// setProducts((prevProducts) => {
|
||||||
|
// return prevProducts.map((product) => {
|
||||||
|
// if (product.id === productId) {
|
||||||
|
// return { ...product, price: parseFloat(product.price + 1) };
|
||||||
|
// } else {
|
||||||
|
// return product;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// show me the render stuff.
|
||||||
|
console.log(JSON.stringify(products));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="example-use-callback">
|
||||||
|
{products && products.length > 0 ? (
|
||||||
|
<ul className="list-group list-group-flush list-products">
|
||||||
|
{products.map((product) => (
|
||||||
|
<ListItemProduct
|
||||||
|
key={`product-${product.id}`}
|
||||||
|
{...product}
|
||||||
|
onClick={(e) => {
|
||||||
|
handleClick(e, product.id);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
) : (
|
||||||
|
<p>no products</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ExampleUseCallback;
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import { FaPen } from 'react-icons/fa6';
|
||||||
|
|
||||||
|
const ExampleUseCallbackRef = (props) => {
|
||||||
|
// const { } = props;
|
||||||
|
|
||||||
|
const [title, setTitle] = useState('');
|
||||||
|
const [editMode, setEditMode] = useState(true);
|
||||||
|
|
||||||
|
// const inputRef = useRef(null); // Rückgabewert ist ein Objekt mit Eigenschaft current { current: HTMLElement}
|
||||||
|
|
||||||
|
const inputRef = useCallback((input) => {
|
||||||
|
input && input.focus();
|
||||||
|
console.log(input);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleChangeTitle = (e) => {
|
||||||
|
setTitle(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickEditMode = (e) => {
|
||||||
|
setEditMode((prevState) => !prevState);
|
||||||
|
console.log(inputRef);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="example-use-ref">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-11">
|
||||||
|
{editMode ? (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="title"
|
||||||
|
className="form-control input-title"
|
||||||
|
value={title}
|
||||||
|
onChange={handleChangeTitle}
|
||||||
|
ref={inputRef}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span style={{ padding: '6px 12px', display: 'inline-block' }}>{title}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="col">
|
||||||
|
<button className="btn btn-dark button-edit-mode" onClick={handleClickEditMode}>
|
||||||
|
<FaPen />
|
||||||
|
<span className="visually-hidden">Edit Mode</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ExampleUseCallbackRef;
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
const ExampleUseMemo = (props) => {
|
||||||
|
// const { } = props;
|
||||||
|
const [products, setProducts] = useState([
|
||||||
|
{ id: 1, name: 'Product 1', price: 10 },
|
||||||
|
{ id: 2, name: 'Product 2', price: 20 },
|
||||||
|
{ id: 3, name: 'Product 3', price: 30 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [text, setText] = useState('');
|
||||||
|
|
||||||
|
const productsAmount = useMemo(() => {
|
||||||
|
console.log('Calculating the number of products');
|
||||||
|
return products.length;
|
||||||
|
}, [products]);
|
||||||
|
|
||||||
|
// EventHandler
|
||||||
|
const handleChangeText = (e) => {
|
||||||
|
setText(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
// const getNumberProducts = () => {
|
||||||
|
// console.log('Calculating the number of products');
|
||||||
|
// return products.length;
|
||||||
|
// };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="example-use-memo">
|
||||||
|
{products && products.length > 0 ? (
|
||||||
|
<ul className="list list-group mb-3">
|
||||||
|
{products.map((product, idx) => (
|
||||||
|
<li key={`list-item-product-${idx}`} className="list-group-item list-item-product">
|
||||||
|
{product.name} - ${product.price.toFixed(2)}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
) : (
|
||||||
|
<p>Loading...</p>
|
||||||
|
)}
|
||||||
|
<p>Number of products in the list: {productsAmount}</p>
|
||||||
|
|
||||||
|
<h4>Input to rerender component:</h4>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="text"
|
||||||
|
className="form-control input-text my-3"
|
||||||
|
placeholder="Input text to rerender"
|
||||||
|
value={text}
|
||||||
|
onChange={handleChangeText}
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
<strong>Text:</strong> {text}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ExampleUseMemo;
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { FaPen } from 'react-icons/fa6';
|
||||||
|
|
||||||
|
const ExampleUseRef = (props) => {
|
||||||
|
// const { } = props;
|
||||||
|
|
||||||
|
const [title, setTitle] = useState('');
|
||||||
|
const [editMode, setEditMode] = useState(true);
|
||||||
|
|
||||||
|
const inputRef = useRef(null); // Rückgabewert ist ein Objekt mit Eigenschaft current { current: HTMLElement}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('Full component rendered');
|
||||||
|
|
||||||
|
if (inputRef.current) {
|
||||||
|
console.log('ref: ', inputRef.current);
|
||||||
|
inputRef.current.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, [editMode]);
|
||||||
|
|
||||||
|
const handleChangeTitle = (e) => {
|
||||||
|
setTitle(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickEditMode = (e) => {
|
||||||
|
setEditMode((prevState) => !prevState);
|
||||||
|
console.log(inputRef);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="example-use-ref">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-11">
|
||||||
|
{editMode ? (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="title"
|
||||||
|
className="form-control input-title"
|
||||||
|
value={title}
|
||||||
|
onChange={handleChangeTitle}
|
||||||
|
ref={inputRef}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span style={{ padding: '6px 12px', display: 'inline-block' }}>{title}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="col">
|
||||||
|
<button className="btn btn-dark button-edit-mode" onClick={handleClickEditMode}>
|
||||||
|
<FaPen />
|
||||||
|
<span className="visually-hidden">Edit Mode</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ExampleUseRef;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
const LazyComponent = (props) => {
|
||||||
|
// const { } = props;
|
||||||
|
|
||||||
|
// Simulate a slow network connection
|
||||||
|
const wait = (delay) => new Promise((resolve) => setTimeout(resolve, delay));
|
||||||
|
wait(3000);
|
||||||
|
return (
|
||||||
|
<div className="lazy alert alert-info">
|
||||||
|
<h4>I was loaded late!</h4>
|
||||||
|
<p>This text only appears after the code for this component has been loaded.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default LazyComponent;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
const ListItemProduct = (props) => {
|
||||||
|
const { title, description, price, children } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li onClick={props.onClick} className="list-item-product list-group-item">
|
||||||
|
<h3>{title}</h3>
|
||||||
|
<p>{children || description}</p>
|
||||||
|
<p>
|
||||||
|
Price: <strong>${price.toFixed(2)}</strong>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ListItemProduct;
|
||||||
Reference in New Issue
Block a user