@aboutbits/react-toolbox
Advanced tools
Comparing version 0.1.3 to 0.2.1
@@ -0,1 +1,6 @@ | ||
/** | ||
* @deprecated Consider directly checking data and error values instead. | ||
* Using `AsyncState` leads to unnecessary complexity and may disable type | ||
* inference. | ||
*/ | ||
declare enum AsyncState { | ||
@@ -6,3 +11,8 @@ FETCHING = 0, | ||
} | ||
/** | ||
* @deprecated Consider directly checking data and error values instead. | ||
* Using `AsyncState` leads to unnecessary complexity and may disable type | ||
* inference. | ||
*/ | ||
declare const getAsyncState: (data: unknown, error: unknown) => AsyncState; | ||
export { AsyncState, getAsyncState }; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getAsyncState = exports.AsyncState = void 0; | ||
/** | ||
* @deprecated Consider directly checking data and error values instead. | ||
* Using `AsyncState` leads to unnecessary complexity and may disable type | ||
* inference. | ||
*/ | ||
var AsyncState; | ||
@@ -11,2 +16,7 @@ (function (AsyncState) { | ||
exports.AsyncState = AsyncState; | ||
/** | ||
* @deprecated Consider directly checking data and error values instead. | ||
* Using `AsyncState` leads to unnecessary complexity and may disable type | ||
* inference. | ||
*/ | ||
var getAsyncState = function (data, error) { | ||
@@ -13,0 +23,0 @@ if (error != null && error != undefined) { |
@@ -9,17 +9,15 @@ "use strict"; | ||
var util_1 = require("../util"); | ||
var index_1 = require("../index"); | ||
var asyncState_1 = require("./asyncState"); | ||
var AsyncView = function (props) { | ||
var data = props.data, error = props.error, _a = props.renderLoading, renderLoading = _a === void 0 ? null : _a, renderSuccess = props.renderSuccess, _b = props.renderError, renderError = _b === void 0 ? null : _b; | ||
var asyncState = (0, asyncState_1.getAsyncState)(data, error); | ||
switch (asyncState) { | ||
case index_1.AsyncState.FETCHING: | ||
return (0, util_1.isFunction)(renderLoading) ? renderLoading() : react_1.default.createElement(react_1.default.Fragment, null, renderLoading); | ||
case index_1.AsyncState.FINISHED_WITH_SUCCESS: | ||
return (0, util_1.isFunction)(renderSuccess) ? (renderSuccess(data)) : (react_1.default.createElement(react_1.default.Fragment, null, renderSuccess)); | ||
case index_1.AsyncState.FINISHED_WITH_ERROR: | ||
return (0, util_1.isFunction)(renderError) ? (renderError(error)) : (react_1.default.createElement(react_1.default.Fragment, null, renderError)); | ||
if (error != null && error != undefined) { | ||
return (0, util_1.isFunction)(renderError) ? renderError(error) : react_1.default.createElement(react_1.default.Fragment, null, renderError); | ||
} | ||
else if (data != null && data != undefined) { | ||
return (0, util_1.isFunction)(renderSuccess) ? (renderSuccess(data)) : (react_1.default.createElement(react_1.default.Fragment, null, renderSuccess)); | ||
} | ||
else { | ||
return (0, util_1.isFunction)(renderLoading) ? renderLoading() : react_1.default.createElement(react_1.default.Fragment, null, renderLoading); | ||
} | ||
}; | ||
exports.AsyncView = AsyncView; | ||
//# sourceMappingURL=AsyncView.js.map |
@@ -0,1 +1,6 @@ | ||
/** | ||
* @deprecated Consider directly checking data and error values instead. | ||
* Using `AsyncState` leads to unnecessary complexity and may disable type | ||
* inference. | ||
*/ | ||
declare enum AsyncState { | ||
@@ -6,3 +11,8 @@ FETCHING = 0, | ||
} | ||
/** | ||
* @deprecated Consider directly checking data and error values instead. | ||
* Using `AsyncState` leads to unnecessary complexity and may disable type | ||
* inference. | ||
*/ | ||
declare const getAsyncState: (data: unknown, error: unknown) => AsyncState; | ||
export { AsyncState, getAsyncState }; |
@@ -0,1 +1,6 @@ | ||
/** | ||
* @deprecated Consider directly checking data and error values instead. | ||
* Using `AsyncState` leads to unnecessary complexity and may disable type | ||
* inference. | ||
*/ | ||
var AsyncState; | ||
@@ -7,2 +12,7 @@ (function (AsyncState) { | ||
})(AsyncState || (AsyncState = {})); | ||
/** | ||
* @deprecated Consider directly checking data and error values instead. | ||
* Using `AsyncState` leads to unnecessary complexity and may disable type | ||
* inference. | ||
*/ | ||
var getAsyncState = function (data, error) { | ||
@@ -9,0 +19,0 @@ if (error != null && error != undefined) { |
import React from 'react'; | ||
import { isFunction } from '../util'; | ||
import { AsyncState } from '../index'; | ||
import { getAsyncState } from './asyncState'; | ||
var AsyncView = function (props) { | ||
var data = props.data, error = props.error, _a = props.renderLoading, renderLoading = _a === void 0 ? null : _a, renderSuccess = props.renderSuccess, _b = props.renderError, renderError = _b === void 0 ? null : _b; | ||
var asyncState = getAsyncState(data, error); | ||
switch (asyncState) { | ||
case AsyncState.FETCHING: | ||
return isFunction(renderLoading) ? renderLoading() : React.createElement(React.Fragment, null, renderLoading); | ||
case AsyncState.FINISHED_WITH_SUCCESS: | ||
return isFunction(renderSuccess) ? (renderSuccess(data)) : (React.createElement(React.Fragment, null, renderSuccess)); | ||
case AsyncState.FINISHED_WITH_ERROR: | ||
return isFunction(renderError) ? (renderError(error)) : (React.createElement(React.Fragment, null, renderError)); | ||
if (error != null && error != undefined) { | ||
return isFunction(renderError) ? renderError(error) : React.createElement(React.Fragment, null, renderError); | ||
} | ||
else if (data != null && data != undefined) { | ||
return isFunction(renderSuccess) ? (renderSuccess(data)) : (React.createElement(React.Fragment, null, renderSuccess)); | ||
} | ||
else { | ||
return isFunction(renderLoading) ? renderLoading() : React.createElement(React.Fragment, null, renderLoading); | ||
} | ||
}; | ||
export { AsyncView }; |
@@ -1,6 +0,7 @@ | ||
import { useInterval } from './useInterval/useInterval'; | ||
import { AsyncState, getAsyncState } from './async-data/asyncState'; | ||
import { AsyncView } from './async-data/AsyncView'; | ||
import { LocationProvider, LocationContext, LocationContextValue } from './location-provider/LocationProvider'; | ||
import { useMatchMediaQuery } from './useMatchMediaQuery/useMatchMediaQuery'; | ||
export { useInterval, AsyncState, getAsyncState, AsyncView, LocationProvider, LocationContext, LocationContextValue, useMatchMediaQuery, }; | ||
export * from './useInterval/useInterval'; | ||
export * from './async-data/asyncState'; | ||
export * from './async-data/AsyncView'; | ||
export * from './location-provider/LocationProvider'; | ||
export * from './useMatchMediaQuery/useMatchMediaQuery'; | ||
export * from './useDebounce/useDebounce'; | ||
export * from './useIsMounted/useIsMounted'; |
@@ -1,6 +0,7 @@ | ||
import { useInterval } from './useInterval/useInterval'; | ||
import { AsyncState, getAsyncState } from './async-data/asyncState'; | ||
import { AsyncView } from './async-data/AsyncView'; | ||
import { LocationProvider, LocationContext, } from './location-provider/LocationProvider'; | ||
import { useMatchMediaQuery } from './useMatchMediaQuery/useMatchMediaQuery'; | ||
export { useInterval, AsyncState, getAsyncState, AsyncView, LocationProvider, LocationContext, useMatchMediaQuery, }; | ||
export * from './useInterval/useInterval'; | ||
export * from './async-data/asyncState'; | ||
export * from './async-data/AsyncView'; | ||
export * from './location-provider/LocationProvider'; | ||
export * from './useMatchMediaQuery/useMatchMediaQuery'; | ||
export * from './useDebounce/useDebounce'; | ||
export * from './useIsMounted/useIsMounted'; |
@@ -1,6 +0,7 @@ | ||
import { useInterval } from './useInterval/useInterval'; | ||
import { AsyncState, getAsyncState } from './async-data/asyncState'; | ||
import { AsyncView } from './async-data/AsyncView'; | ||
import { LocationProvider, LocationContext, LocationContextValue } from './location-provider/LocationProvider'; | ||
import { useMatchMediaQuery } from './useMatchMediaQuery/useMatchMediaQuery'; | ||
export { useInterval, AsyncState, getAsyncState, AsyncView, LocationProvider, LocationContext, LocationContextValue, useMatchMediaQuery, }; | ||
export * from './useInterval/useInterval'; | ||
export * from './async-data/asyncState'; | ||
export * from './async-data/AsyncView'; | ||
export * from './location-provider/LocationProvider'; | ||
export * from './useMatchMediaQuery/useMatchMediaQuery'; | ||
export * from './useDebounce/useDebounce'; | ||
export * from './useIsMounted/useIsMounted'; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.useMatchMediaQuery = exports.LocationContext = exports.LocationProvider = exports.AsyncView = exports.getAsyncState = exports.AsyncState = exports.useInterval = void 0; | ||
var useInterval_1 = require("./useInterval/useInterval"); | ||
Object.defineProperty(exports, "useInterval", { enumerable: true, get: function () { return useInterval_1.useInterval; } }); | ||
var asyncState_1 = require("./async-data/asyncState"); | ||
Object.defineProperty(exports, "AsyncState", { enumerable: true, get: function () { return asyncState_1.AsyncState; } }); | ||
Object.defineProperty(exports, "getAsyncState", { enumerable: true, get: function () { return asyncState_1.getAsyncState; } }); | ||
var AsyncView_1 = require("./async-data/AsyncView"); | ||
Object.defineProperty(exports, "AsyncView", { enumerable: true, get: function () { return AsyncView_1.AsyncView; } }); | ||
var LocationProvider_1 = require("./location-provider/LocationProvider"); | ||
Object.defineProperty(exports, "LocationProvider", { enumerable: true, get: function () { return LocationProvider_1.LocationProvider; } }); | ||
Object.defineProperty(exports, "LocationContext", { enumerable: true, get: function () { return LocationProvider_1.LocationContext; } }); | ||
var useMatchMediaQuery_1 = require("./useMatchMediaQuery/useMatchMediaQuery"); | ||
Object.defineProperty(exports, "useMatchMediaQuery", { enumerable: true, get: function () { return useMatchMediaQuery_1.useMatchMediaQuery; } }); | ||
__exportStar(require("./useInterval/useInterval"), exports); | ||
__exportStar(require("./async-data/asyncState"), exports); | ||
__exportStar(require("./async-data/AsyncView"), exports); | ||
__exportStar(require("./location-provider/LocationProvider"), exports); | ||
__exportStar(require("./useMatchMediaQuery/useMatchMediaQuery"), exports); | ||
__exportStar(require("./useDebounce/useDebounce"), exports); | ||
__exportStar(require("./useIsMounted/useIsMounted"), exports); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@aboutbits/react-toolbox", | ||
"version": "0.1.3", | ||
"version": "0.2.1", | ||
"description": "Tools for React", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
164
readme.md
@@ -1,3 +0,2 @@ | ||
React Toolbox | ||
============= | ||
# React Toolbox | ||
@@ -16,2 +15,4 @@ [](https://badge.fury.io/js/%40aboutbits%2Freact-toolbox) | ||
- [useMatchMediaQuery](#usematchmediaquery) | ||
- [useDebounce](#usedebounce) | ||
- [useIsMounted](#useismounted) | ||
- [Build & Publish](#build--publish) | ||
@@ -45,10 +46,13 @@ - [Information](#information) | ||
const [step, setStep] = useState(10) | ||
useInterval(() => { | ||
setStep(step - 1) | ||
}, step === 0 ? null : 1000) | ||
useInterval( | ||
() => { | ||
setStep(step - 1) | ||
}, | ||
step === 0 ? null : 1000 | ||
) | ||
return <p>Countdown: {step}</p> | ||
} | ||
``` | ||
``` | ||
@@ -64,27 +68,28 @@ ### Async Data | ||
type Data = { | ||
greeting: string | ||
greeting: string | ||
} | ||
type Error = { | ||
message: string | ||
message: string | ||
} | ||
const MyCommponent = () => { | ||
const [data, setData] = useState<Data | undefined>() | ||
const [error, setError] = useState<Error | undefined>() | ||
const [data, setData] = useState<Data | undefined>() | ||
const [error, setError] = useState<Error | undefined>() | ||
useEffect(() => { | ||
fetch('https://jsonplaceholder.typicode.com/todos/1') | ||
.then(response => setData(response.json())) | ||
.catch(error => setError(error)) | ||
}) | ||
useEffect(() => { | ||
fetch('https://jsonplaceholder.typicode.com/todos/1') | ||
.then((response) => setData(response.json())) | ||
.catch((error) => setError(error)) | ||
}) | ||
return ( | ||
<AsyncView | ||
data={data} | ||
error={error} | ||
renderLoading={<div>Loading</div>} | ||
renderSuccess={(data) => <div>{data.greeting}</div>} | ||
renderError={(error) => <div>{error.message}</div>} /> | ||
); | ||
return ( | ||
<AsyncView | ||
data={data} | ||
error={error} | ||
renderLoading={<div>Loading</div>} | ||
renderSuccess={(data) => <div>{data.greeting}</div>} | ||
renderError={(error) => <div>{error.message}</div>} | ||
/> | ||
) | ||
} | ||
@@ -101,22 +106,23 @@ ``` | ||
type Data = { | ||
greeting: string | ||
greeting: string | ||
} | ||
type Error = { | ||
message: string | ||
message: string | ||
} | ||
const MyCommponent = () => { | ||
const { data, error } = useSWR('https://jsonplaceholder.typicode.com/todos/1') | ||
return ( | ||
<AsyncView | ||
data={data} | ||
error={error} | ||
renderLoading={'Loading'} | ||
renderSuccess={'Success'} | ||
renderError={'Error'} /> | ||
); | ||
const { data, error } = useSWR('https://jsonplaceholder.typicode.com/todos/1') | ||
return ( | ||
<AsyncView | ||
data={data} | ||
error={error} | ||
renderLoading={'Loading'} | ||
renderSuccess={'Success'} | ||
renderError={'Error'} | ||
/> | ||
) | ||
} | ||
``` | ||
``` | ||
@@ -131,3 +137,2 @@ ### LocationProvider | ||
const MyApp = () => { | ||
return ( | ||
@@ -142,2 +147,3 @@ <LocationProvider highAccuracy={true} delay={20000}> | ||
The context provider takes two props: | ||
- `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). | ||
@@ -152,6 +158,10 @@ - `delay`: the delay in milliseconds between each fetch | ||
const { location } = useContext(LocationContext) | ||
return location | ||
? <div>Your location is: {location.coords.latitude}, {location.coords.longitude}</div> | ||
: <div>Unable to get your location</div> | ||
return location ? ( | ||
<div> | ||
Your location is: {location.coords.latitude}, {location.coords.longitude} | ||
</div> | ||
) : ( | ||
<div>Unable to get your location</div> | ||
) | ||
} | ||
@@ -174,2 +184,72 @@ ``` | ||
### useDebounce | ||
Use this hook to prevent the component from re-rendering too many times. Useful to avoid making unnecessary API calls. | ||
```tsx | ||
export default function TestComponent() { | ||
const [value, setValue] = useState('') | ||
const debouncedValue = useDebounce(value, 500) | ||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => { | ||
setValue(event.target.value) | ||
} | ||
// Fetch API (optional) | ||
useEffect(() => { | ||
// Do fetch here... | ||
// Triggers when "debouncedValue" changes | ||
}, [debouncedValue]) | ||
return ( | ||
<div> | ||
<p>Value real-time: {value}</p> | ||
<p>Debounced value: {debouncedValue}</p> | ||
<input type="text" value={value} onChange={handleChange} /> | ||
</div> | ||
) | ||
} | ||
``` | ||
### useIsMounted | ||
In React, a component is deleted from memory once unmounted. Changing the state in an unmounted component will result in an error. | ||
This is preferrably solved passing a cleanup function to [useEffect](https://react.dev/reference/react/useEffect#useeffect). | ||
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. | ||
This hook returns a function that can be used to verify at the resolve time whether the component is still mounted. | ||
```tsx | ||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) | ||
function Child() { | ||
const [data, setData] = useState('loading') | ||
const isMounted = useIsMounted() | ||
// simulate an api call and update state | ||
useEffect(() => { | ||
void delay(3000).then(() => { | ||
if (isMounted()) { | ||
setData('OK') | ||
} | ||
}) | ||
}, [isMounted]) | ||
return <p>{data}</p> | ||
} | ||
export default function TestComponent() { | ||
const [isVisible, setVisible] = useState<boolean>(false) | ||
const toggleVisibility = () => setVisible((state) => !state) | ||
return ( | ||
<> | ||
<button onClick={toggleVisibility}>{isVisible ? 'Hide' : 'Show'}</button> | ||
{isVisible && <Child />} | ||
</> | ||
) | ||
} | ||
``` | ||
## Build & Publish | ||
@@ -176,0 +256,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
37419
53
532
274