Unit-6 answers
Accessing the Unit-6 answers​
Clone the unit-6-answers, branch to get the answers to unit-6.
Answer​
Task 1​
The first thing we need to do is import our useSelector and useDispatch into our <Toast /> component, we need to import useSelector as we will need to pass in our current toast store as an payload into our useDispatch.
import React from 'react';
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux'; // Added
import {
FiInfo, FiCheck, FiX, FiAlertOctagon,
} from 'react-icons/fi';
import styles from './toast.module.scss';
Now we just need to add our dispatch to our handleClick with the 'HIDE_TOAST' action and the current toast store as our payload. We need to do this as all we want to do change is the display state.
const toastStore = useSelector((state) => state.toast);
const dispatch = useDispatch();
const handleClick = () => {
dispatch({ type: 'HIDE_TOAST', payload: toastStore.toast });
};
This is what our final component should look like.
import React from 'react';
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';
import {
FiInfo, FiCheck, FiX, FiAlertOctagon,
} from 'react-icons/fi';
import styles from './toast.module.scss';
const Toast = ({
className,
error,
success,
message,
show,
hide,
}) => {
const toastStore = useSelector((state) => state.toast);
const dispatch = useDispatch();
const handleClick = () => {
dispatch({ type: 'HIDE_TOAST', payload: toastStore.toast });
};
const showOrHideToast = () => {
if (show) return `${styles['toast--show']}`;
if (!hide && hide !== null) return `${styles['toast--hide']}`;
return '';
};
if (error) {
return (
<div className={`${className} ${styles.toast} ${styles['toast--error']} ${showOrHideToast()}`}>
<div className={styles.toast__container}>
<FiAlertOctagon className={styles.toast__icon} />
<p className={styles.toast__para}>{message}</p>
<button
type="button"
className={styles.toast__button}
onClick={handleClick}
>
<FiX className={styles.toast__icon} />
</button>
</div>
</div>
);
}
if (success) {
return (
<div className={`${className} ${styles.toast} ${styles['toast--success']} ${showOrHideToast()}`}>
<div className={styles.toast__container}>
<FiCheck className={styles.toast__icon} />
<p className={styles.toast__para}>{message}</p>
<button
type="button"
className={styles.toast__button}
onClick={handleClick}
>
<FiX className={styles.toast__icon} />
</button>
</div>
</div>
);
}
return (
<div className={`${className} ${styles.toast} ${showOrHideToast()}`}>
<div className={styles.toast__container}>
<FiInfo className={styles.toast__icon} />
<p className={styles.toast__para}>{message}</p>
<button
type="button"
className={styles.toast__button}
onClick={handleClick}
>
<FiX className={styles.toast__icon} />
</button>
</div>
</div>
);
};
Toast.propTypes = {
className: PropTypes.string,
error: PropTypes.bool,
success: PropTypes.bool,
show: PropTypes.bool,
hide: PropTypes.bool,
message: PropTypes.string,
};
Toast.defaultProps = {
className: '',
error: false,
success: false,
show: false,
hide: false,
message: 'Add a toast massage as a prop',
};
export default Toast;
Task 2​
As always we will need to start by importing our useSelector and useDispatch into our <Layout /> component.
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux'; // Added
import styles from './layout.module.scss';
import Header from '../../organisms/header/header';
import Search from '../../organisms/search/search';
import Nav from '../../organisms/nav/nav';
import Toast from '../../molecules/toast/toast';
Next all we need to do is add another useEffect to our <Layout /> component that checks if the toastStore.toast.display is true and after 2 seconds (using a setTimeout) then fires a dispatch with the 'HIDE_TOAST' action and the current toast store payload. However, we will need to clear the setTimeout in the useEffect otherwise this may lead to performance issues.
// This will hide the toast after 2 seconds if its showing
const dispatch = useDispatch();
useEffect(() => {
let timer;
if (toastStore.toast.display) {
timer = setTimeout(() => {
dispatch({ type: 'HIDE_TOAST', payload: toastStore.toast });
}, 2000);
}
return () => clearTimeout(timer);
}, [toastStore]);
This is what our completed layout component should look like.
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';
import styles from './layout.module.scss';
import Header from '../../organisms/header/header';
import Search from '../../organisms/search/search';
import Nav from '../../organisms/nav/nav';
import Toast from '../../molecules/toast/toast';
const Layout = ({ children }) => {
const [showMobileNav, setShowMobileNav] = useState(false);
const [toastState, setToastState] = useState('');
const toastStore = useSelector((state) => state.toast);
useEffect(() => {
setToastState(toastStore.toast);
}, [toastStore]);
// This will hide the toast after 2 seconds if its showing
const dispatch = useDispatch();
useEffect(() => {
let timer;
if (toastStore.toast.display) {
timer = setTimeout(() => {
dispatch({ type: 'HIDE_TOAST', payload: toastStore.toast });
}, 2000);
}
return () => clearTimeout(timer);
}, [toastStore]);
return (
<div className={styles.layout}>
<Header
className={styles.layout__header}
showMobileNav={showMobileNav}
setShowMobileNav={setShowMobileNav}
/>
<Search className={styles.layout__search} />
<Nav className={styles.layout__nav} showMobileNav={showMobileNav} />
<main className={styles.layout__main}>
<div className={styles.layout__wrapper}>
{children}
</div>
</main>
<Toast
show={toastState.display}
hide={toastState.display}
message={toastState.message}
error={toastState.type === 'error'}
success={toastState.type === 'success'}
/>
</div>
);
};
Layout.propTypes = {
children: PropTypes.node.isRequired,
};
export default Layout;