EN
React - sticky reactions component
0
points
In this article, we would like to show you how to create a custom sticky reactions component in React.
// ONLINE-RUNNER:browser;
// Note: Uncomment import lines during working with JSX Compiler.
// import React from 'react';
// import ReactDOM from 'react-dom';
const reactionsStyle = {
margin: '20px 0px',
position: 'sticky',
top: '60px',
width: '36px',
};
const iconStyle = {
margin: '16px 8px',
background: 'white',
width: '20px',
height: '20px',
display: 'block',
cursor: 'pointer'
};
const defaultIconStyle = {
...iconStyle,
color: 'silver'
};
const selectedIconStyle = {
...iconStyle,
color: 'blue'
};
const LikeIcon = (props) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" {...props}>
<g fill="currentColor">
<path d="M466.27 286.69C475.04 271.84 480 256 480 236.85c0-44.015-37.218-85.58-85.82-85.58H357.7c4.92-12.81 8.85-28.13 8.85-46.54C366.55 31.936 328.86 0 271.28 0c-61.607 0-58.093 94.933-71.76 108.6-22.747 22.747-49.615 66.447-68.76 83.4H32c-17.673 0-32 14.327-32 32v240c0 17.673 14.327 32 32 32h64c14.893 0 27.408-10.174 30.978-23.95 44.509 1.001 75.06 39.94 177.802 39.94 7.22 0 15.22.01 22.22.01 77.117 0 111.986-39.423 112.94-95.33 13.319-18.425 20.299-43.122 17.34-66.99 9.854-18.452 13.664-40.343 8.99-62.99zm-61.75 53.83c12.56 21.13 1.26 49.41-13.94 57.57 7.7 48.78-17.608 65.9-53.12 65.9h-37.82c-71.639 0-118.029-37.82-171.64-37.82V240h10.92c28.36 0 67.98-70.89 94.54-97.46 28.36-28.36 18.91-75.63 37.82-94.54 47.27 0 47.27 32.98 47.27 56.73 0 39.17-28.36 56.72-28.36 94.54h103.99c21.11 0 37.73 18.91 37.82 37.82.09 18.9-12.82 37.81-22.27 37.81 13.489 14.555 16.371 45.236-5.21 65.62zM88 432c0 13.255-10.745 24-24 24s-24-10.745-24-24 10.745-24 24-24 24 10.745 24 24z" />
</g>
</svg>
);
const StarIcon = (props) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" {...props}>
<g fill="currentColor">
<path fill="currentColor" d="M528.1 171.5L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6zM388.6 312.3l23.7 138.4L288 385.4l-124.3 65.3 23.7-138.4-100.6-98 139-20.2 62.2-126 62.2 126 139 20.2-100.6 98z" />
</g>
</svg>
);
const Reactions = ({ reactions, onClick }) => {
const [state, setState] = React.useState(() => (reactions ?? {})); // only to store state locally
React.useEffect(() => setState(reactions ?? {}), [reactions]); // only to store state locally
const createHandleClick = (name) => {
return () => {
const checked = !state[name];
setState({ ...state, [name]: checked });
if (onClick) {
onClick(name, checked);
}
};
};
return (
<div style={reactionsStyle}>
<LikeIcon
style={state.like ? selectedIconStyle : defaultIconStyle}
onClick={createHandleClick('like')}
/>
<StarIcon
style={state.star ? selectedIconStyle : defaultIconStyle}
onClick={createHandleClick('star')}
/>
</div>
);
};
// Usage example:
const bannerStyle = {
height: '150px',
background: 'gold'
};
const pageStyle = {
margin: '10px auto',
maxWidth: '500px',
display: 'flex'
};
const textStyle = {
margin: '0 0 0 20px',
background: '#f1f1f1',
flex: '1'
};
const App = () => {
const [reactions, setReactions] = React.useState({});
const handleReactionClick = (name, checked) => {
console.log(`${name} is ${checked ? 'checked' : 'unchecked'}`);
//TODO: request to backend
setReactions({ ...reactions, [name]: checked });
};
return (
<>
<div style={bannerStyle}>
Some banner here ...
</div>
<div style={pageStyle}>
<div>
<Reactions reactions={reactions} onClick={handleReactionClick} />
</div>
<div style={textStyle}>
{Array(50).fill().map((v, i) => <div key={i}>Some text here ...</div>)}
</div>
</div>
</>
);
}
const root = document.querySelector('#root');
ReactDOM.render(<App />, root);