
@airma/react-effect
This tool is used for managing the side effect state of react app.
async effect
There are two async effects currently, useQuery
and useMutation
. They can accept a Promise callback, and returns the execution result of the Promise.
useQuery
We can wrap a promise return callback to useQuery
, when the dependecies changes, it querys data for you.
import React from 'react';
import {useQuery} from '@airma/react-effect';
import {client} from '@airma/restful';
const cli = client();
const App = ()=>{
const [query, setQuery] = useState({name:'', username:''});
const [result, execute] = useQuery(
()=>
cli.rest('/api/user/list').
setParams(query).
get<User[]>(),
[query]
);
const {
data,
isFetching,
error,
isError
} = result;
......
}
If you want to execute the query manually, you can set manual:true
to the config.
import React from 'react';
import {useQuery} from '@airma/react-effect';
import {client} from '@airma/restful';
const cli = client();
const App = ()=>{
const [query, setQuery] = useState({name:'', username:''});
const [result, execute] = useQuery(
()=>
cli.rest('/api/user/list').
setParams(query).
get<User[]>(),
{manual: true}
);
const {
data,
isFetching,
error,
isError
} = result;
const handleClick = async ()=>{
const {
data,
isFetching,
error,
isError,
abandon
} = await execute();
}
......
}
The manual execution is not recommend, you may accept an abandoned result, if the execution is not the newest one, in that case, you may have a different result with the hook useQuery
result.
useMutation
To execute a mutation, you can use useMutation
. It only can be executed manually.
import React from 'react';
import {useMutation} from '@airma/react-effect';
import {client} from '@airma/restful';
const cli = client();
const App = ()=>{
const [user, setUser] = useState({name:'', username:''});
const [result, execute] = useMutation(
(u:User)=>
cli.rest('/api/user').
setBody(u).
post<User>()
);
const {
data,
isFetching,
error,
isError
} = result;
const handleClick = async ()=>{
const {
data,
isFetching,
error,
isError,
abandon
} = await execute();
}
......
}
The different with useQuery
is that the useMutation
can not be truly executed again if the last execution is not finished, it returns the last result for you.
Sometimes we need an mutation to be inexecutable when the last execution is finished successly, we can use config repeatable:false
to do this.
import React from 'react';
import {useMutation} from '@airma/react-effect';
import {client} from '@airma/restful';
const cli = client();
const App = ()=>{
const [user, setUser] = useState({name:'', username:''});
const [result, execute] = useMutation(
(u:User)=>
cli.rest('/api/user').
setBody(u).
post<User>(),
{
repeatable:false
}
);
const {
data,
isFetching,
error,
isError
} = result;
const handleClick = async ()=>{
const {
data,
isFetching,
error,
isError,
abandon
} = await execute();
}
......
}
We often execute a query after a mutation is finished, we can set after
callback into the config, and after the mutation is finished, it will execute the query.
import React from 'react';
import {useMutation, useQuery} from '@airma/react-effect';
import {client} from '@airma/restful';
const cli = client();
const App = ()=>{
......
const [queryResult, executeQuery] = useQuery(()=>..., [...]);
const [user, setUser] = useState({name:'', username:''});
const [result, execute] = useMutation(
(u:User)=>
cli.rest('/api/user').
setBody(u).
post<User>(),
{
repeatable:false,
after:({isError})=>{
if ( !isError ) {
executeQuery();
}
}
}
);
const {
data,
isFetching,
error,
isError
} = result;
const handleClick = async ()=>{
const {
data,
isFetching,
error,
isError,
abandon
} = await execute(user);
}
......
}
The after
callback can accepts a async execution result.
async execution result
The promise result is a unitary result format for both useQuery and useMutation.
export declare type PromiseResult<T> = {
data: T | undefined;
error?: any;
isError: boolean;
isFetching: boolean;
abandon: boolean;
};
useSideEffect
If you want to make a side effect state management without promise, you can use this API.
import React from 'react';
import {useSideEffect} from '@airma/react-effect';
const App = ()=>{
const [second, execute] = useSideEffect(response => {
const id = window.setInterval(() => {
response(s => s + 1);
}, 1000);
return () => clearInterval(id);
}, 0);
}
As the proto hook of useQuery
, you can also use the config and dependencies like useQuery
.
import React from 'react';
import {useSideEffect} from '@airma/react-effect';
const App = ()=>{
const [state, setState] = useState(...);
const [second, execute] = useSideEffect(response => {
const id = window.setInterval(() => {
response(s => s + 1);
}, 1000);
return () => clearInterval(id);
}, 0, [state]);
}
You can start it manually.
import React from 'react';
import {useSideEffect} from '@airma/react-effect';
const App = ()=>{
const [state, setState] = useState(...);
const [second, execute] = useSideEffect(response => {
const id = window.setInterval(() => {
response(s => s + 1);
}, 1000);
return () => clearInterval(id);
}, 0, {manual:true});
}
You can destroy it manualy. Yes, the destroy function is not exist in useQuery
result.
import React from 'react';
import {useSideEffect} from '@airma/react-effect';
const App = ()=>{
const [state, setState] = useState(...);
const [second, execute, destroy] = useSideEffect(response => {
const id = window.setInterval(() => {
response(s => s + 1);
}, 1000);
return () => clearInterval(id);
}, 0);
const handleDestroy=()=>destroy();
}
API
useQuery
To execute a query promise callback.
export declare function useQuery<T>(
callback: () => Promise<T>,
config?: { deps?: any[]; manual?: boolean } | any[]
): [PromiseResult<T>, () => Promise<PromiseResult<T>>];
parameters:
- callback - a callback returns a promise, and it should has no parameters.
- config - it is optional, if you set nothing, the query will be executed once when the hook is mounted, if you set an array dependencies for it, it querys when the hook is mounted or the dependencies element changes. Set
{ manual:true }
allows you execute it manually.
returns:
[
result,
execute
]
useMutation
To execute a mutation promise callback.
export declare function useMutation<
T,
C extends (...params: any[]) => Promise<T>
>(
callback: C,
config?: { after?: () => any; repeatable?: boolean }
): [
PromiseResult<T>,
(...params: Parameters<typeof callback>) => Promise<PromiseResult<T>>
];
parameters:
- callback - a callback returns a promise, it can accept parameters, when execute it, you need to pass paramters for it.
- config - it is optional. Set
repeatable: true
limits the execution only can work once, if the execution is successed. the after
callback will be called, when the execution is finished.
returns:
[
result,
execute
]
useSideEffect
To make a side effect state management.
export declare type ResponseParam<T> = T | ((d: T) => T);
export declare type ResponseType<T> = (data: ResponseParam<T>) => void;
export declare type SideEffectCallback<T> = (response: ResponseType<T>) => any;
export declare function useSideEffect<T, C extends SideEffectCallback<T>>(
callback: C,
defaultState: T,
config?: { deps?: any[]; manual?: boolean } | any[]
): [T, () => ReturnType<C>, { destroy: () => any }];
parameters:
- callback - a callback accept a response callback as a parameter.
- defaultState - you need to give it a defaultState.
- config - it is optional, if you set nothing, the query will be executed once when the hook is mounted, if you set an array dependencies for it, it querys when the hook is mounted or the dependencies element changes. Set
{ manual:true }
allows you execute it manually.
The response callback is like a setState from useState
. You can use it to set the side effect state.
returns:
[
result,
execute
]