⭐ Please star this project if you find it useful!
Common functions, and hooks for React.
We are using hooks, so you need to work with React ^16.8.0.
> npm i uno-react
In this section, we present the different hooks/functions that are available in the uno-react library. Please keep in mind that everything in the library is opt-in. uno-react is completely opt-in. It won't force you to use any of its hooks, classes or functions.
This hook allows to call a given function when a click event occurs outside the component.
component
functionComponent The component to be wrapped.callback
function The function that will be called when the click event occurs outside the component.
const myComponent = () => {
const [color, setColor] = React.useState('green');
const onClick = () => setColor('green');
const toBeEnhanced = () => (
<div
style={{ backgroundColor: color }}
onClick={onClick}
/>
);
const functionToApply = () => setColor('red');
const Enhanced = useClickOutside(toBeEnhanced, functionToApply);
return (
<div
style={{
height: '80px',
width: '80px',
}}
>
<Enhanced />
</div>
);
};
This hooks run an effect with a debounce. Each time any input change, it will be registered; when happens the debounce time whitout changes, the effect will be run. (This function does not return anything).
effect
function The function that will be run.debounce
number Time that have to happend to run the effect.inputs
Array<string | Object | number | boolean> an array of variables that the effect depends on.
const MyComponent = () => {
const [searchText, handleChange, setSearchText] = useStateForField('');
const debounceTime = 2000; // 2 Seconds
const searchUsers = () => console.log(`searching: ${searchText}`);
useEffectWithDebounce(searchUsers, debounceTime, [searchText]);
return (
<>
<h1>Input: </h1>
<input
value={searchText}
onChange={handleChange}
/>
<p> Open the console </p>
</>
);
};
This hook handles the process of getting a external resource like a fetch or reading a file, and prevent updating the react state if the component is unmounted before the resource is loaded.
-
effect
Function the function that will get the data. -
initialValue
Object initial value or initial model. -
inputs
Array<string | Object | number | boolean> an array of variables that the effect depends on.
note: The effect
function that is given as a parameter will be run when the component has been mounted and when any inputs
item change.
- getter: Object the value that is returned by the
effect
function when the data has been loaded, otherwise the initialValue. - isLoading: boolean a flag that indicates if the data has been fetched or not.
const myComponent = ({ myId }) => {
const myDefault = '';
const inputs = [];
const [ myData, isLoading ] = useEffectWithLoading(getMyData(myId), myDefault, inputs);
return (
<div>
{isLoading ?
<div class='loader'>Loading ...</div>
:
<form>
<label>
<h1>Data loaded</h1>
{myData}
</label>
<form>}
</div>
);
};
This hook keep the current Date object updated. The value
will be updated each second.
note: the time value is a javascript Date instance, you can manipulate it as any other javascript Date object.
- now: Date the current date.
const myComponent = () => {
const [now] = useNow();
return (
<div>
Seconds: {now.getSeconds()}
</div>
);
};
This hook allows us to set
and get
values from the localStorage
.
-
defaultValue
string the default values, this value will be added to thelocalStorage
and returned if the key is not found. -
keyName
string the key-id to save the value on thelocalStorage
.
note: the defaultValue just will be setted and returned if the keyName is not on the localStorage
, otherwise the value found will be returned.
- getter: string the current value
- setter: Function the function to set the value. note: This Function expects an Object as a parameter.
const myComponent = () => {
const key = 'exampleToken';
const defaultValue = 'unosquareToken';
const [token, setToken] = usePersistedState(defaultValue, key);
const changeValue = () => setToken('1928238475');
return(
<div>
<h1>{token}</h1>
<button onClick={changeValue}>Change value</button>
</div>
);
};
This hook listen to the resize window event and keep the isResolution
flag updated.
-
outerWidth
number Size limit (px). defaultValue: 1000 -
timeout
number Debounder timeout, the variable will change after this debounder time (ms). defaultValue: 500
- size: boolean true when window outerSize is smaller than the outerWith passed as a parameter.
const myComponent = () => {
const outerWidth = 500;
const timeout = 1000;
const [size] = useResolutionSwitch(outerWidth, timeout);
return (<h1>{size ? 'mobile' : 'desktop'}</h1>);
};
Similar to useStateForModel
this hook helps us to keep the value of a variable that is related to an input, but in this case useStateForField
works just with one value.
initialValue
Object initial value or initial model.
Note: In contrast with useStateForModel
in this hook the function handleChange
can not be called with an object as a param, to handle a change manually we have the setField function.
- getField: Object the current value, that keeps the information updated.
- handleChange: Function this function should be called on the onChange event.
- setField: Function this function helps us to update the value manually.
const myComponent = () => {
const [ myValue, handleChange, setMyValue ] = useStateForField('Unosquare');
const reset = () => setMyValue('Unosquare');
return (
<div>
<h1>{myValue}</h1>
<input
value={myValue}
onChange={handleChange}
/>
<button onClick={reset}>Reset value</button>
</div>
);
};
This hook allows us to keep updated the values of a model that are related to an input, handling the input's onChange
calls. During the first render the model will have the initialValue.
initialValue
Object initial value or initial model.
Note: the handleChange
method will update the model by the target.name event property if it is found, otherwise it will be added to the model.
Note: calling the handleChange
method with an object as a param instead of an event, the object will be merged with the current model.
- model: Object the current model, that keeps the information updated.
- handleChange: Function this function should be called on the onChange event.
const myComponent = () => {
const [ model, handleChange ] = useStateForModel({
id: 1,
name: 'Mario',
lastName: 'Di Vece',
});
const changeName = () => handleChange({name: 'Mario'});
return (
<div>
<h1>{model.id} - {model.name} - {model.lastName}</h1>
<input
name="name"
onChange={handleChange}
value={model.name}
/>
<input
name="lastName"
onChange={handleChange}
value={model.lastName}
/>
<button onClick={changeName}>Reset Name</button>
</div>
);
};
This hook allows us to keep updated the values of a model that are related to an input, handling the input's onChange
calls like useStateForModel
does, but in additino this hook allows us to load the data from an external resource.
This hook is a mix between useStateForModel
and useEffectWithLoading
, you can use it just as useStateForModel
and handle the loading with the extra variable returned isLoading
.
-
effect
Function the function that will get the data. -
initialValue
Object initial value or initial model. -
inputs
Array<string | Object | number | boolean> an array of variables that the effect depends on.
note: The effect
function that is given as a parameter will be run when the component has been mounted and when any inputs
item change.
- getter: Object the value that is returned by the
effect
function when the data has been loaded, otherwise the initialValue. - isLoading: boolean a flag that indicates if the data has been fetched or not.
- handleChange: Function this function should be called on the onChange event.
const myComponent = () => {
const myModel = {
name: 'my test name',
city: 'my test city'
};
const [mySearchString, handleChangeSearchString] = useStateForField('');
const [ data, isLoading, handleChange ] = useStateForModelWithLoading(getMyData(mySearchString), myModel, [mySearchString]);
return (
<div>
<input
onChange={handleChangeSearchString}
value={mySearchString}>
</input>
{isLoading ?
<div class='loader'>Loading ...</div>
:
<form>
<input
value={data.name}
onChange={handleChange}
/>
<input
value={data.city}
onChange={handleChange}
/>
</form>}
</div>
);
};
This hook handles the switch on boolean values
. The value will be toggled each time the function toggle is called.
defaultValue
boolean default or initial value.
const myComponent = () => {
const defaultValue = false;
const [ myValue, toggle ] = useToggleStateForField(defaultValue);
return (
<div>
<h1> {myValue ? 'true' : 'false'}</h1 >
<button
onClick={toggle}
>
Toggle
</button>
</div >
);
};
This component extends the original ValidatorForm rules. This component works for wrap TextValidator component(s) and for register any other custom rules, this rules can be used in the wrapped components.
Rules:
- isNotAllBlanks: Validates that the input is not empty, white spaces are ignored.
- maxNaturalNumber: Validates that the input number si not greather than the given.
- validateEndDate: Validates than endDate is later than startDate.
- startDateGreaterThanEndDate: Validates that a date is bigger than other.
- isImage: Verify that the input correspond to a image name with image file extension.
- atLeastOneLowerAndUpperCase: Verify that the input has at least one letter in lower case and one in upper case.
- atLeastOneNumber: Verify that the input has at least one number.
- atLeastOneSpecialCharacter: Verify that the input has at least one special character (e.g. * # $ &).
- pincodeValidator: Verify the input contains only numeric values and has a length of 6 characters.
- password: Validated that the input has at least a length of 8 characteres and contains especial characters, lower case & upper case characters.
- isPasswordMatch: Verify that the input is equal to another value.(e.g. when validated password & password verfication fields).
const form = () => {
const [fields, handleChange] = useStateForModel({
atLeastOneLowerAndUpperCase: '',
atLeastOneNumber: '',
atLeastOneSpecialCharacter: '',
isImage: '',
isNotAllBlanks: '',
isPasswordMatch: '',
maxNaturalNumber: '',
password: '',
pincodeValidator: '',
startDateGreaterThanEndDate: '',
validateEndDate: '',
});
return (
<ValidatorForm
autoComplete='off'
instantValidate={true}
>
<TextValidator
id='isNotAllBlanks'
value={fields.isNotAllBlanks}
onChange={handleChange}
validators={['required', 'isNotAllBlanks:5']}
errorMessages={[
'This field is required',
'The minimum length is 5 characters, blank spaces are ignored',
]}
/>
<TextValidator
id='maxNaturalNumber'
value={fields.maxNaturalNumber}
onChange={handleChange}
validators={['required', 'maxNaturalNumber:100']}
errorMessages={[
'This field is required',
'The input should not be greater than 100',
]}
/>
<TextValidator
id='validateEndDate'
value={fields.validateEndDate}
onChange={handleChange}
validators={['required', 'validateEndDate: 2019:07:29']}
errorMessages={[
'This field is required',
'The date should be earlier than 2019:07:29',
]}
/>
<TextValidator
id='startDateGreaterThanEndDate'
value={fields.startDateGreaterThanEndDate}
onChange={handleChange}
validators={['required', 'startDateGreaterThanEndDate: 2019:07:29']}
errorMessages={[
'This field is required',
'The start date should be greater than 2019:07:29',
]}
/>
<TextValidator
id='isImage'
value={fields.isImage}
onChange={handleChange}
validators={['required', 'isImage: .jpg']}
errorMessages={[
'This field is required',
'The file extension should be .jpg',
]}
/>
<TextValidator
id='atLeastOneLowerAndUpperCase'
value={fields.atLeastOneLowerAndUpperCase}
onChange={handleChange}
validators={['required', 'atLeastOneLowerAndUpperCase']}
errorMessages={[
'This field is required',
'Should have at least one upper case and one lower case character',
]}
/>
<TextValidator
id='atLeastOneNumber'
value={fields.atLeastOneNumber}
onChange={handleChange}
validators={['required', 'atLeastOneNumber']}
errorMessages={[
'This field is required',
'Should contain at least one number',
]}
/>
<TextValidator
id='atLeastOneSpecialCharacter'
value={fields.atLeastOneSpecialCharacter}
onChange={handleChange}
validators={['required', 'atLeastOneSpecialCharacter']}
errorMessages={[
'This field is required',
'Should contain at least one special character',
]}
/>
<TextValidator
id='pincodeValidator'
value={fields.pincodeValidator}
onChange={handleChange}
validators={['required', 'pincodeValidator']}
errorMessages={[
'This field is required',
'should not contain white spaces and a length of 6 characters',
]}
/>
<TextValidator
id='password'
value={fields.password}
onChange={handleChange}
validators={['required', 'password']}
errorMessages={[
'This field is required',
'Should have at least 1 upper case, 1 lower case, 1 special character and a min length of 8 characters',
]}
/>
<TextValidator
id='isPasswordMatch'
value={fields.isPasswordMatch}
onChange={handleChange}
validators={['required', `isPasswordMatch:${fields.Password}`]}
errorMessages={[
'This field is required',
'Must be the same as the password field',
]}
/>
</ValidatorForm>
);
};