Skip to content

Commit c36f112

Browse files
author
devgioele
committed
add examples for useDebounce and useIsMounted
1 parent 6f9048e commit c36f112

1 file changed

Lines changed: 122 additions & 42 deletions

File tree

readme.md

Lines changed: 122 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
React Toolbox
2-
=============
1+
# React Toolbox
32

43
[![npm package](https://badge.fury.io/js/%40aboutbits%2Freact-toolbox.svg)](https://badge.fury.io/js/%40aboutbits%2Freact-toolbox)
54
[![license](https://img.shields.io/github/license/aboutbits/react-toolbox)](https://github.com/aboutbits/react-toolbox/blob/main/license.md)
@@ -13,6 +12,8 @@ This package includes different tools that support you with common tasks.
1312
- [Async Data](#async-data)
1413
- [LocationProvider](#locationprovider)
1514
- [useMatchMediaQuery](#usematchmediaquery)
15+
- [useDebounce](#usedebounce)
16+
- [useIsMounted](#useismounted)
1617
- [Build & Publish](#build--publish)
1718
- [Information](#information)
1819

@@ -41,14 +42,17 @@ import { useInterval } from '@aboutbits/react-toolbox'
4142

4243
const MyCommponent = () => {
4344
const [step, setStep] = useState(10)
44-
45-
useInterval(() => {
46-
setStep(step - 1)
47-
}, step === 0 ? null : 1000)
45+
46+
useInterval(
47+
() => {
48+
setStep(step - 1)
49+
},
50+
step === 0 ? null : 1000
51+
)
4852

4953
return <p>Countdown: {step}</p>
5054
}
51-
```
55+
```
5256

5357
### Async Data
5458

@@ -59,31 +63,32 @@ import React, { useEffect } from 'react'
5963
import { AsyncView } from '@aboutbits/react-toolbox'
6064

6165
type Data = {
62-
greeting: string
66+
greeting: string
6367
}
6468

6569
type Error = {
66-
message: string
70+
message: string
6771
}
6872

6973
const MyCommponent = () => {
70-
const [data, setData] = useState<Data | undefined>()
71-
const [error, setError] = useState<Error | undefined>()
74+
const [data, setData] = useState<Data | undefined>()
75+
const [error, setError] = useState<Error | undefined>()
7276

73-
useEffect(() => {
74-
fetch('https://jsonplaceholder.typicode.com/todos/1')
75-
.then(response => setData(response.json()))
76-
.catch(error => setError(error))
77-
})
77+
useEffect(() => {
78+
fetch('https://jsonplaceholder.typicode.com/todos/1')
79+
.then((response) => setData(response.json()))
80+
.catch((error) => setError(error))
81+
})
7882

79-
return (
80-
<AsyncView
81-
data={data}
82-
error={error}
83-
renderLoading={<div>Loading</div>}
84-
renderSuccess={(data) => <div>{data.greeting}</div>}
85-
renderError={(error) => <div>{error.message}</div>} />
86-
);
83+
return (
84+
<AsyncView
85+
data={data}
86+
error={error}
87+
renderLoading={<div>Loading</div>}
88+
renderSuccess={(data) => <div>{data.greeting}</div>}
89+
renderError={(error) => <div>{error.message}</div>}
90+
/>
91+
)
8792
}
8893
```
8994

@@ -95,26 +100,27 @@ import { useSWR } from 'swr'
95100
import { AsyncView } from '@aboutbits/react-toolbox'
96101

97102
type Data = {
98-
greeting: string
103+
greeting: string
99104
}
100105

101106
type Error = {
102-
message: string
107+
message: string
103108
}
104109

105110
const MyCommponent = () => {
106-
const { data, error } = useSWR('https://jsonplaceholder.typicode.com/todos/1')
107-
108-
return (
109-
<AsyncView
110-
data={data}
111-
error={error}
112-
renderLoading={'Loading'}
113-
renderSuccess={'Success'}
114-
renderError={'Error'} />
115-
);
111+
const { data, error } = useSWR('https://jsonplaceholder.typicode.com/todos/1')
112+
113+
return (
114+
<AsyncView
115+
data={data}
116+
error={error}
117+
renderLoading={'Loading'}
118+
renderSuccess={'Success'}
119+
renderError={'Error'}
120+
/>
121+
)
116122
}
117-
```
123+
```
118124

119125
### LocationProvider
120126

@@ -124,7 +130,6 @@ This part includes a React context that fetches the geolocation at a given inter
124130
import { LocationProvider } from '@aboutbits/react-toolbox'
125131

126132
const MyApp = () => {
127-
128133
return (
129134
<LocationProvider highAccuracy={true} delay={20000}>
130135
{children}
@@ -134,6 +139,7 @@ const MyApp = () => {
134139
```
135140

136141
The context provider takes two props:
142+
137143
- `highAccuracy`: defines if the location should be fetched with high accuracy. Read more on the [Geolocation API doc](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API).
138144
- `delay`: the delay in milliseconds between each fetch
139145

@@ -143,10 +149,14 @@ import { LocationContext } from '@aboutbits/react-toolbox'
143149

144150
const MyComponent = () => {
145151
const { location } = useContext(LocationContext)
146-
147-
return location
148-
? <div>Your location is: {location.coords.latitude}, {location.coords.longitude}</div>
149-
: <div>Unable to get your location</div>
152+
153+
return location ? (
154+
<div>
155+
Your location is: {location.coords.latitude}, {location.coords.longitude}
156+
</div>
157+
) : (
158+
<div>Unable to get your location</div>
159+
)
150160
}
151161
```
152162

@@ -164,6 +174,76 @@ const TestComponent = () => {
164174
}
165175
```
166176

177+
### useDebounce
178+
179+
Use this hook to prevent the component from re-rendering too many times. Useful to avoid making unnecessary API calls.
180+
181+
```tsx
182+
export default function TestComponent() {
183+
const [value, setValue] = useState('')
184+
const debouncedValue = useDebounce(value, 500)
185+
186+
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
187+
setValue(event.target.value)
188+
}
189+
190+
// Fetch API (optional)
191+
useEffect(() => {
192+
// Do fetch here...
193+
// Triggers when "debouncedValue" changes
194+
}, [debouncedValue])
195+
196+
return (
197+
<div>
198+
<p>Value real-time: {value}</p>
199+
<p>Debounced value: {debouncedValue}</p>
200+
<input type="text" value={value} onChange={handleChange} />
201+
</div>
202+
)
203+
}
204+
```
205+
206+
### useIsMounted
207+
208+
In React, a component is deleted from memory once unmounted. Changing the state in an unmounted component will result in an error.
209+
This is preferrably solved passing a cleanup function to [useEffect](https://react.dev/reference/react/useEffect#useeffect).
210+
However, there are some cases like Promise or API calls where it's impossible to know if the component is still mounted at the resolve time.
211+
This hook returns a function that can be used to verify at the resolve time whether the component is still mounted.
212+
213+
```tsx
214+
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
215+
216+
function Child() {
217+
const [data, setData] = useState('loading')
218+
const isMounted = useIsMounted()
219+
220+
// simulate an api call and update state
221+
useEffect(() => {
222+
void delay(3000).then(() => {
223+
if (isMounted()) {
224+
setData('OK')
225+
}
226+
})
227+
}, [isMounted])
228+
229+
return <p>{data}</p>
230+
}
231+
232+
export default function TestComponent() {
233+
const [isVisible, setVisible] = useState<boolean>(false)
234+
235+
const toggleVisibility = () => setVisible((state) => !state)
236+
237+
return (
238+
<>
239+
<button onClick={toggleVisibility}>{isVisible ? 'Hide' : 'Show'}</button>
240+
241+
{isVisible && <Child />}
242+
</>
243+
)
244+
}
245+
```
246+
167247
## Build & Publish
168248

169249
To publish the package commit all changes and push them to main. Then run one of the following commands locally:

0 commit comments

Comments
 (0)