Update snippets

Resolves #112
This commit is contained in:
Isabelle Viktoria Maciohsek
2020-11-26 23:57:34 +02:00
parent 83dfa1f227
commit 94f42ee17d
3 changed files with 64 additions and 81 deletions

View File

@ -5,71 +5,51 @@ tags: components,state,advanced
Renders a countdown timer that prints a message when it reaches zero. Renders a countdown timer that prints a message when it reaches zero.
- Use object destructuring to set defaults for the `hours`, `minutes` and `seconds` props. - Use the `useState()` hook to create a state variable to hold the time value, initialize it from the props and destructure it into its components.
- Use the `React.useState()` hook to create the `time`, `paused` and `over` state variables and set their values to the values of the passed props, `false` and `false` respectively. - Use the `useState()` hook to create the `paused` and `over` state variables, used to prevent the timer from ticking if it's paused or the time has run out.
- Create a method `tick`, that updates the value of `time` based on the current value (i.e. decreasing the time by one second). - Create a method `tick`, that updates the time values based on the current value (i.e. decreasing the time by one second).
- If `paused` or `over` is `true`, `tick` will return immediately.
- Create a method `reset`, that resets all state variables to their initial states. - Create a method `reset`, that resets all state variables to their initial states.
- Use the the `React.useEffect()` hook to call the `tick` method every second via the use of `setInterval()` and use `clearInterval()` to cleanup when the component is unmounted. - Use the the `useEffect()` hook to call the `tick` method every second via the use of `setInterval()` and use `clearInterval()` to clean up when the component is unmounted.
- Use a `<div>` to wrap a `<p>` element with the textual representation of the components `time` state variable, as well as two `<button>` elements that will pause/unpause and restart the timer respectively. - Use `String.prototype.padStart()` to pad each part of the time array to two characters to create the visual representation of the timer.
- If `over` is `true`, the timer will display a message instead of the value of `time`.
```jsx ```jsx
const CountDown = ({ hours = 0, minutes = 0, seconds = 0 }) => { const CountDown = ({ hours = 0, minutes = 0, seconds = 0 }) => {
const [paused, setPaused] = React.useState(false); const [paused, setPaused] = React.useState(false);
const [over, setOver] = React.useState(false); const [over, setOver] = React.useState(false);
const [time, setTime] = React.useState({ const [[h, m, s], setTime] = React.useState([hours, minutes, seconds]);
hours: parseInt(hours),
minutes: parseInt(minutes),
seconds: parseInt(seconds)
});
const tick = () => { const tick = () => {
if (paused || over) return; if (paused || over) return;
if (time.hours == 0 && time.minutes == 0 && time.seconds == 0) setOver(true); if (h === 0 && m === 0 && s === 0) setOver(true);
else if (time.minutes == 0 && time.seconds == 0) { else if (m === 0 && s === 0) {
setTime({ setTime([h - 1, 59, 59]);
hours: time.hours - 1, } else if (s == 0) {
minutes: 59, setTime([h, m - 1, 59]);
seconds: 59
});
} else if (time.seconds == 0) {
setTime({
hours: time.hours,
minutes: time.minutes - 1,
seconds: 59
});
} else { } else {
setTime({ setTime([h, m, s - 1]);
hours: time.hours,
minutes: time.minutes,
seconds: time.seconds - 1
});
} }
}; };
const reset = () => { const reset = () => {
setTime({ setTime([parseInt(hours), parseInt(minutes), parseInt(seconds)]);
hours: parseInt(hours),
minutes: parseInt(minutes),
seconds: parseInt(seconds)
});
setPaused(false); setPaused(false);
setOver(false); setOver(false);
}; };
React.useEffect(() => { React.useEffect(() => {
let timerID = setInterval(() => tick(), 1000); const timerID = setInterval(() => tick(), 1000);
return () => clearInterval(timerID); return () => clearInterval(timerID);
}); });
return ( return (
<div> <div>
<p>{`${time.hours.toString().padStart(2, '0')}:${time.minutes <p>{`${h.toString().padStart(2, '0')}:${m
.toString() .toString()
.padStart(2, '0')}:${time.seconds.toString().padStart(2, '0')}`}</p> .padStart(2, '0')}:${s.toString().padStart(2, '0')}`}</p>
<div>{over ? "Time's up!" : ''}</div> <div>{over ? "Time's up!" : ''}</div>
<button onClick={() => setPaused(!paused)}>{paused ? 'Resume' : 'Pause'}</button> <button onClick={() => setPaused(!paused)}>
{paused ? 'Resume' : 'Pause'}
</button>
<button onClick={() => reset()}>Restart</button> <button onClick={() => reset()}>Restart</button>
</div> </div>
); );
@ -77,5 +57,8 @@ const CountDown = ({ hours = 0, minutes = 0, seconds = 0 }) => {
``` ```
```jsx ```jsx
ReactDOM.render(<CountDown hours="1" minutes="45" />, document.getElementById('root')); ReactDOM.render(
<CountDown hours={1} minutes={45} />,
document.getElementById('root')
);
``` ```

View File

@ -5,45 +5,38 @@ tags: components,input,state,array,intermediate
Renders a checkbox list that uses a callback function to pass its selected value/values to the parent component. Renders a checkbox list that uses a callback function to pass its selected value/values to the parent component.
- Use `React.useState()` to create a `data` state variable and set its initial value equal to the `options` prop. - Use the `useState()` hook to create the `data` state variable and use the `options` prop to initialize its value.
- Create a function `toggle` that is used to toggle the `checked` to update the `data` state variable and call the `onChange` callback passed via the component's props. - Create a `toggle` function that uses the spread operator (`...`) and `Array.prototype.splice()` to update the `data` state variable and call the `onChange` callback with any `checked` options.
- Render a `<ul>` element and use `Array.prototype.map()` to map the `data` state variable to individual `<li>` elements with `<input>` elements as their children. - Use `Array.prototype.map()` to map the `data` state variable to individual `<input type="checkbox">` elements, each one wrapped in a `<label>`, binding the `onClick` handler to the `toggle` function.
- Each `<input>` element has the `type='checkbox'` attribute and is marked as `readOnly`, as its click events are handled by the parent `<li>` element's `onClick` handler.
```jsx ```jsx
const style = {
listContainer: {
listStyle: 'none',
paddingLeft: 0
},
itemStyle: {
cursor: 'pointer',
padding: 5
}
};
const MultiselectCheckbox = ({ options, onChange }) => { const MultiselectCheckbox = ({ options, onChange }) => {
const [data, setData] = React.useState(options); const [data, setData] = React.useState(options);
const toggle = item => { const toggle = index => {
data.forEach((_, key) => { const newData = [...data];
if (data[key].label === item.label) data[key].checked = !item.checked; newData.splice(index, 1, {
label: data[index].label,
checked: !data[index].checked
}); });
setData([...data]); setData(newData);
onChange(data); onChange(newData.filter(x => x.checked));
}; };
return ( return (
<ul style={style.listContainer}> <>
{data.map(item => { {data.map((item, index) => (
return ( <label key={item.label}>
<li key={item.label} style={style.itemStyle} onClick={() => toggle(item)}> <input
<input readOnly type="checkbox" checked={item.checked || false} /> readOnly
{item.label} type="checkbox"
</li> checked={item.checked || false}
); onClick={() => toggle(index)}
})} />
</ul> {item.label}
</label>
))}
</>
); );
}; };
``` ```

View File

@ -6,39 +6,47 @@ tags: components,children,input,state,intermediate
Renders a star rating component. Renders a star rating component.
- Define a component, called `Star` that will render each individual star with the appropriate appearance, based on the parent component's state. - Define a component, called `Star` that will render each individual star with the appropriate appearance, based on the parent component's state.
- In the `StarRating` component, use the `React.useState()` hook to define the `rating` and `selection` state variables with the initial values of `value` (or `0` if invalid or not supplied) and `0`. - In the `StarRating` component, use the `useState()` hook to define the `rating` and `selection` state variables with the appropriate initial values.
- Create a method, `hoverOver`, that updates `selected` and `rating` according to the provided `event`. - Create a method, `hoverOver`, that updates `selected` according to the provided `event`, using the .`data-star-id` attribute of the event's target or resets it to `0` if called with a `null` argument.
- Create a `<div>` to wrap the `<Star>` components, which are created using `Array.prototype.map()` on an array of 5 elements, created using `Array.from()`, and handle the `onMouseLeave` event to set `selection` to `0`, the `onClick` event to set the `rating` and the `onMouseOver` event to set `selection` to the `star-id` attribute of the `event.target` respectively. - Use `Array.from()` to create an array of `5` elements and `Array.prototype.map()` to create individual `<Star>` components.
- Finally, pass the appropriate values to each `<Star>` component (`starId` and `marked`). - Handle the `onMouseOver` and `onMouseLeave` events of the wrapping element using `hoverOver` and the `onClick` event using `setRating`.
```css
.star {
color: #ff9933;
cursor: pointer;
}
```
```jsx ```jsx
const Star = ({ marked, starId }) => { const Star = ({ marked, starId }) => {
return ( return (
<span star-id={starId} style={{ color: '#ff9933' }} role="button"> <span data-star-id={starId} className="star" role="button">
{marked ? '\u2605' : '\u2606'} {marked ? '\u2605' : '\u2606'}
</span> </span>
); );
}; };
const StarRating = ({ value }) => { const StarRating = ({ value }) => {
const [rating, setRating] = React.useState(typeof value == 'number' ? value : 0); const [rating, setRating] = React.useState(parseInt(value) || 0);
const [selection, setSelection] = React.useState(0); const [selection, setSelection] = React.useState(0);
const hoverOver = event => { const hoverOver = event => {
let val = 0; let val = 0;
if (event && event.target && event.target.getAttribute('star-id')) if (event && event.target && event.target.getAttribute('data-star-id'))
val = event.target.getAttribute('star-id'); val = event.target.getAttribute('data-star-id');
setSelection(val); setSelection(val);
}; };
return ( return (
<div <div
onMouseOut={() => hoverOver(null)} onMouseOut={() => hoverOver(null)}
onClick={event => setRating(event.target.getAttribute('star-id') || rating)} onClick={e => setRating(e.target.getAttribute('data-star-id') || rating)}
onMouseOver={hoverOver} onMouseOver={hoverOver}
> >
{Array.from({ length: 5 }, (v, i) => ( {Array.from({ length: 5 }, (v, i) => (
<Star <Star
starId={i + 1} starId={i + 1}
key={`star_${i + 1} `} key={`star_${i + 1}`}
marked={selection ? selection >= i + 1 : rating >= i + 1} marked={selection ? selection >= i + 1 : rating >= i + 1}
/> />
))} ))}
@ -48,6 +56,5 @@ const StarRating = ({ value }) => {
``` ```
```jsx ```jsx
ReactDOM.render(<StarRating />, document.getElementById('root'));
ReactDOM.render(<StarRating value={2} />, document.getElementById('root')); ReactDOM.render(<StarRating value={2} />, document.getElementById('root'));
``` ```