@ -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')
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|||||||
@ -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>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|||||||
@ -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'));
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user