Skip to content

Commit cc6d102

Browse files
zachsaZach Smith
andauthored
Added example using a controlled React component and hooks. #735 (#1531)
* Added example using a controlled React component and hooks. #735 * Updated in response to feedback on #1531 * Fixed state-management bug where old state values were set instead of new state values Co-authored-by: Zach Smith <zach@saeon.ac.za>
1 parent 7014975 commit cc6d102

File tree

3 files changed

+191
-1
lines changed

3 files changed

+191
-1
lines changed

demo/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ <h1>Demos</h1>
1515
<li><a href="nested.html">Nested grids</a></li>
1616
<li><a href="responsive.html">Responsive</a></li>
1717
<li><a href="react.html">ReactJS</a></li>
18+
<li><a href="react-hooks.html">ReactJS (Hooks)</a></li>
1819
<li><a href="right-to-left(rtl).html">Right-To-Left (RTL)</a></li>
1920
<li><a href="serialization.html">Serialization</a></li>
2021
<li><a href="static.html">Static</a></li>

demo/react-hooks.html

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset="UTF-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Gridstack.js React integration example</title>
8+
<link rel="stylesheet" href="demo.css" />
9+
<script src="../dist/gridstack-h5.js"></script>
10+
11+
<!-- Scripts to use react inside html -->
12+
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
13+
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
14+
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
15+
</head>
16+
17+
<body>
18+
<div>
19+
<h1>Using GridStack.js with React hooks</h1>
20+
<p>
21+
As with any virtualDOM-based framework, you need to check if Reacthas rendered the DOM (or any updates to it)
22+
<strong>before</strong> you initialize GridStack or call its methods. This example shows how to make rendered
23+
components widgets:
24+
</p>
25+
<ol>
26+
<li>Render items, each with a reference</li>
27+
<li>Convert each rendered item to a widget using the reference and the <a
28+
href="https://github.com/gridstack/gridstack.js/tree/develop/doc#makewidgetel">
29+
makeWidget</a> function</li>
30+
</ol>
31+
</div>
32+
<div>
33+
<h2>Controlled stack</h2>
34+
<div id="controlled-stack"></div>
35+
</div>
36+
<div>
37+
<h2>Uncontrolled stack</h2>
38+
<div id="uncontrolled-stack"></div>
39+
</div>
40+
</body>
41+
42+
<script type="text/babel">
43+
const { useState, useEffect, createRef, useRef } = React
44+
45+
const Item = ({ id }) => <div>I am item: {id}</div>
46+
47+
//
48+
// Controlled example
49+
//
50+
51+
const ControlledStack = ({ items, addItem }) => {
52+
const refs = useRef({})
53+
const gridRef = useRef()
54+
55+
if (Object.keys(refs.current).length !== items.length) {
56+
items.forEach(({ id }) => {
57+
refs.current[id] = refs.current[id] || createRef()
58+
})
59+
}
60+
61+
useEffect(() => {
62+
gridRef.current =
63+
gridRef.current ||
64+
GridStack.init(
65+
{
66+
float: true,
67+
},
68+
'.controlled'
69+
)
70+
const grid = gridRef.current
71+
grid.batchUpdate()
72+
grid.removeAll(false)
73+
items.forEach(({ id }) => grid.makeWidget(refs.current[id].current))
74+
grid.commit()
75+
}, [items])
76+
77+
return (
78+
<div>
79+
<button onClick={addItem}>Add new widget</button>
80+
<div className={`grid-stack controlled`}>
81+
{items.map((item, i) => {
82+
return (
83+
<div ref={refs.current[item.id]} key={item.id} className={'grid-stack-item'}>
84+
<div className="grid-stack-item-content">
85+
<Item {...item} />
86+
</div>
87+
</div>
88+
)
89+
})}
90+
</div>
91+
</div>
92+
)
93+
}
94+
95+
const ControlledExample = () => {
96+
const [items, setItems] = useState([{ id: 'item-1' }, { id: 'item-2' }])
97+
98+
return (
99+
<ControlledStack
100+
items={items}
101+
addItem={() => setItems([...items, { id: `item-${items.length + 1}` }])}
102+
/>
103+
)
104+
}
105+
106+
//
107+
// Uncontrolled example
108+
//
109+
110+
const UncontrolledExample = () => {
111+
const gridRef = useRef()
112+
113+
const [state, setState] = useState({
114+
count: 0,
115+
info: '',
116+
items: [
117+
{ x: 2, y: 1, h: 2 },
118+
{ x: 2, y: 4, w: 3 },
119+
{ x: 4, y: 2 },
120+
{ x: 3, y: 1, h: 2 },
121+
{ x: 0, y: 6, w: 2, h: 2 },
122+
],
123+
})
124+
125+
useEffect(() => {
126+
gridRef.current =
127+
gridRef.current ||
128+
GridStack.init(
129+
{
130+
float: true,
131+
cellHeight: '70px',
132+
minRow: 1,
133+
},
134+
'.uncontrolled'
135+
)
136+
137+
const grid = gridRef.current
138+
139+
grid.on('dragstop', (event, element) => {
140+
const node = element.gridstackNode
141+
setState(prevState => ({
142+
...prevState,
143+
info: `you just dragged node #${node.id} to ${node.x},${node.y} – good job!`,
144+
}))
145+
146+
let timerId
147+
window.clearTimeout(timerId)
148+
timerId = window.setTimeout(() => {
149+
setState(prevState => ({
150+
...prevState,
151+
info: '',
152+
}))
153+
}, 2000)
154+
})
155+
}, [])
156+
157+
return (
158+
<div>
159+
<button
160+
onClick={() => {
161+
const grid = gridRef.current
162+
const node = state.items[state.count] || {
163+
x: Math.round(12 * Math.random()),
164+
y: Math.round(5 * Math.random()),
165+
w: Math.round(1 + 3 * Math.random()),
166+
h: Math.round(1 + 3 * Math.random()),
167+
}
168+
node.id = node.content = String(state.count)
169+
setState(prevState => ({
170+
...prevState,
171+
count: prevState.count + 1,
172+
}))
173+
grid.addWidget(node)
174+
}}
175+
>
176+
Add Widget
177+
</button>
178+
<div>{JSON.stringify(state)}</div>
179+
<section class="grid-stack uncontrolled"></section>
180+
</div>
181+
)
182+
}
183+
184+
ReactDOM.render(<ControlledExample />, document.getElementById('controlled-stack'))
185+
ReactDOM.render(<UncontrolledExample />, document.getElementById('uncontrolled-stack'))
186+
187+
</script>
188+
189+
</html>

doc/CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Change log
55
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
66
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*
77

8-
- [3.1.2 (2020-12-7)](#311-2020-12-7)
8+
- [3.1.2 (2020-12-7)](#312-2020-12-7)
99
- [3.1.0 (2020-12-4)](#310-2020-12-4)
1010
- [3.0.0 (2020-11-29)](#300-2020-11-29)
1111
- [2.2.0 (2020-11-7)](#220-2020-11-7)

0 commit comments

Comments
 (0)