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.
xxxxxxxxxx
1
// Note: Uncomment import lines during working with JSX Compiler.
2
// import React from 'react';
3
// import ReactDOM from 'react-dom';
4
5
const reactionsStyle = {
6
margin: '20px 0px',
7
position: 'sticky',
8
top: '60px',
9
width: '36px',
10
};
11
12
const iconStyle = {
13
margin: '16px 8px',
14
background: 'white',
15
width: '20px',
16
height: '20px',
17
display: 'block',
18
cursor: 'pointer'
19
};
20
21
const defaultIconStyle = {
22
iconStyle,
23
color: 'silver'
24
};
25
26
const selectedIconStyle = {
27
iconStyle,
28
color: 'blue'
29
};
30
31
const LikeIcon = (props) => (
32
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" {props}>
33
<g fill="currentColor">
34
<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" />
35
</g>
36
</svg>
37
);
38
39
const StarIcon = (props) => (
40
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" {props}>
41
<g fill="currentColor">
42
<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" />
43
</g>
44
</svg>
45
);
46
47
const Reactions = ({ reactions, onClick }) => {
48
const [state, setState] = React.useState(() => (reactions ?? {})); // only to store state locally
49
React.useEffect(() => setState(reactions ?? {}), [reactions]); // only to store state locally
50
const createHandleClick = (name) => {
51
return () => {
52
const checked = !state[name];
53
setState({ state, [name]: checked });
54
if (onClick) {
55
onClick(name, checked);
56
}
57
};
58
};
59
return (
60
<div style={reactionsStyle}>
61
<LikeIcon
62
style={state.like ? selectedIconStyle : defaultIconStyle}
63
onClick={createHandleClick('like')}
64
/>
65
<StarIcon
66
style={state.star ? selectedIconStyle : defaultIconStyle}
67
onClick={createHandleClick('star')}
68
/>
69
</div>
70
);
71
};
72
73
// Usage example:
74
75
const bannerStyle = {
76
height: '150px',
77
background: 'gold'
78
};
79
80
const pageStyle = {
81
margin: '10px auto',
82
maxWidth: '500px',
83
display: 'flex'
84
};
85
86
const textStyle = {
87
margin: '0 0 0 20px',
88
background: '#f1f1f1',
89
flex: '1'
90
};
91
92
const App = () => {
93
const [reactions, setReactions] = React.useState({});
94
const handleReactionClick = (name, checked) => {
95
console.log(`${name} is ${checked ? 'checked' : 'unchecked'}`);
96
//TODO: request to backend
97
setReactions({ reactions, [name]: checked });
98
};
99
return (
100
<>
101
<div style={bannerStyle}>
102
Some banner here ...
103
</div>
104
<div style={pageStyle}>
105
<div>
106
<Reactions reactions={reactions} onClick={handleReactionClick} />
107
</div>
108
<div style={textStyle}>
109
{Array(50).fill().map((v, i) => <div key={i}>Some text here ...</div>)}
110
</div>
111
</div>
112
</>
113
);
114
}
115
116
const root = document.querySelector('#root');
117
ReactDOM.render(<App />, root);