It is a method calling useReducer. It is simple for usage with more easier typescript support.
Installations
npm install @airma/react-effect
Developer Guide
Typescript
No
Module System
CommonJS
Node Version
16.14.0
NPM Version
8.3.1
Score
70.2
Supply Chain
97.7
Quality
91.2
Maintenance
100
Vulnerability
100
License
Releases
Unable to fetch releases
Contributors
Unable to fetch Contributors
Languages
TypeScript (82.73%)
JavaScript (14.65%)
HTML (2.62%)
Love this project? Help keep it running — sponsor us today! 🚀
Developer
Download Statistics
Total Downloads
12,094
Last Day
10
Last Week
24
Last Month
266
Last Year
4,073
GitHub Statistics
MIT License
5 Stars
373 Commits
1 Watchers
26 Branches
2 Contributors
Updated on Jan 22, 2025
Bundle Size
73.95 kB
Minified
20.81 kB
Minified + Gzipped
Package Meta Information
Latest Version
18.5.11
Package Id
@airma/react-effect@18.5.11
Unpacked Size
72.76 kB
Size
18.58 kB
File Count
4
NPM Version
8.3.1
Node Version
16.14.0
Published on
Jan 18, 2025
Total Downloads
Cumulative downloads
Total Downloads
12,094
Last Day
11.1%
10
Compared to previous day
Last Week
-61.3%
24
Compared to previous week
Last Month
-28.9%
266
Compared to previous month
Last Year
-48.9%
4,073
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
@airma/react-effect
@airma/react-effect
is an asynchronous state-management tool for react.
Document
Code first
useQuery
API useQuery
can query data, and set it as a state.
1import React from 'react'; 2import {useQuery} from '@airma/react-effect'; 3import {User} from './type'; 4 5type UserQuery = { 6 name: string; 7 username: string; 8} 9// Prepare a query promise callback. 10const fetchUsers = (query: UserQuery):Promise<User[]> => 11 Promise.resolve([]); 12 13const App = ()=>{ 14 const [query, setQuery] = useState({name:'', username:''}); 15 const [state, trigger, executeWithParams] = useQuery( 16 // Use query callback 17 fetchUsers, 18 // Set parameters for query callback 19 [query] 20 ); 21 const { 22 // User[] | undefined 23 data, 24 // boolean 25 isFetching, 26 // any 27 error, 28 // boolean 29 isError, 30 // boolean 31 loaded 32 } = state; 33 34 ...... 35}
When useQuery
is mounted, or the dependency parameters change, it calls the promise callback.
UseMutation
API useMutation
is similar with useQuery
. The difference is that it should be triggered manually to work.
1import React from 'react'; 2import {useMutation} from '@airma/react-effect'; 3import {User} from './type'; 4 5const saveUser = (user: User): Promise<User> => 6 Promise.resolve(user); 7 8const App = ()=>{ 9 const [user, setUser] = useState<User>({...}); 10 const [ 11 state, 12 trigger, 13 executeWithParams 14 ] = useMutation( 15 // Set mutation callback, 16 // it is a promise callback. 17 saveUser, 18 // Set mutation parameters. 19 [ user ] 20 ); 21 const { 22 // User | undefined 23 data, 24 // boolean 25 isFetching, 26 // any 27 error, 28 // boolean 29 isError 30 } = result; 31 32 const handleClick = ()=>{ 33 trigger(); 34 } 35 36 ...... 37}
The state of useMutation has same fields with useQuery state.
Session
Both of useQuery and useMutation need a promise callback for working, the mission of promise callback is called session.
Use a simplified API session to make coding fly.
1import React from 'react'; 2import {session} from '@airma/react-effect'; 3import {User} from './type'; 4 5type UserQuery = { 6 name: string; 7 username: string; 8} 9 10// use `session` API to declare a query session 11const userQuerySession = session( 12 (query: UserQuery):Promise<User[]> => 13 Promise.resolve([]), 14 'query' 15); 16 17const App = ()=>{ 18 const [query, setQuery] = useState({name:'', username:''}); 19 const [ 20 state, 21 trigger, 22 executeWithParams 23 // call session.useQuery 24 ] = userQuerySession.useQuery( 25 // Set parameters for query callback 26 [query] 27 ); 28 const { 29 // User[] | undefined 30 data, 31 // boolean 32 isFetching, 33 // any 34 error, 35 // boolean 36 isError, 37 // boolean 38 loaded 39 } = state; 40 41 ...... 42}
The state of useQuery/useMutation is a local state. There are two different store state-managements: use dynamic React.Context store or use static global store.
React.Context dynamic store state-management
1import React from 'react'; 2import {session} from '@airma/react-effect'; 3import {User} from './type'; 4 5type UserQuery = { 6 name: string; 7 username: string; 8} 9 10// declare a query session dynamic store 11const userQueryStore = session( 12 (query: UserQuery):Promise<User[]> => 13 Promise.resolve([]), 14 'query' 15).createStore(); 16 17const SearchButton = ()=>{ 18 // useSession subscribes state change from session store 19 const [ 20 // state from session store 21 {isFetching}, 22 // call trigger function can trigger useQuery work manually 23 triggerQuery 24 ] = userQueryStore.useSession(); 25 return ( 26 <button 27 disabled={isFetching} 28 onClick={triggerQuery} 29 > 30 query 31 </button> 32 ); 33} 34 35// provide dynamic store is very important 36const App = userQueryStore.provideTo(()=>{ 37 const [query, setQuery] = useState({name:'', username:''}); 38 const [ 39 state, 40 // Write every query state change to store 41 ] = userQueryStore.useQuery( 42 [query] 43 ); 44 45 ...... 46 47 return ( 48 <> 49 <SearchButton /> 50 ...... 51 </> 52 ); 53})
Why support React.Context store? Refer to @airma/react-state explain.
The dynamic store is a special session key collection not a real store. It persist an actual store in Provider component.
When a Provider is mounting in, it creates store, and when the provider has been unmounted, it destroys this store.
Global static store state-management
1import React from 'react'; 2import {session} from '@airma/react-effect'; 3import {User} from './type'; 4 5type UserQuery = { 6 name: string; 7 username: string; 8} 9 10// declare a query session global static store 11const userQueryStore = session( 12 (query: UserQuery):Promise<User[]> => 13 Promise.resolve([]), 14 'query' 15).createStore().asGlobal(); 16 17const SearchButton = ()=>{ 18 const [ 19 { 20 isFetching, 21 // User[] | undefined 22 data 23 }, 24 triggerQuery 25 ] = userQueryStore.useSession(); 26 return ( 27 <button 28 disabled={isFetching} 29 onClick={triggerQuery} 30 > 31 query 32 </button> 33 ); 34} 35 36// global static store needs no Provider. 37const App = ()=>{ 38 const [query, setQuery] = useState({name:'', username:''}); 39 const [ 40 state 41 ] = userQueryStore.useQuery( 42 [query] 43 ); 44 45 ...... 46 47 return ( 48 <> 49 <SearchButton /> 50 ...... 51 </> 52 ); 53}
The state data
from useSession is always has a undefined
union type. API useLoadedSession can be helpful if the session state.data
is not empty from initializing time.
1import React from 'react'; 2import {session} from '@airma/react-effect'; 3import {User} from './type'; 4 5type UserQuery = { 6 name: string; 7 username: string; 8} 9 10const userQueryStore = session( 11 (query: UserQuery):Promise<User[]> => 12 Promise.resolve([]), 13 'query' 14).createStore().asGlobal(); 15 16const SearchButton = ()=>{ 17 // store.useLoadedSession can give out the promise resolve type without `empty`. 18 const [ 19 { 20 isFetching, 21 // User[] 22 data 23 }, 24 triggerQuery 25 ] = userQueryStore.useLoadedSession(); 26 return ( 27 <button 28 disabled={isFetching} 29 onClick={triggerQuery} 30 > 31 query 32 </button> 33 ); 34} 35 36const App = ()=>{ 37 const [query, setQuery] = useState({name:'', username:''}); 38 const [ 39 state 40 ] = userQueryStore.useQuery( 41 // use object config to set default data 42 { 43 variables: [query], 44 // To make `state.data` not empty, 45 // a default data is needed. 46 defaultData: [] 47 } 48 ); 49 50 ...... 51 52 return ( 53 <> 54 <SearchButton /> 55 ...... 56 </> 57 ); 58}
Want to do something when query or mutation responses?
1import React from 'react'; 2import {session, useResponse} from '@airma/react-effect'; 3import {User} from './type'; 4 5type UserQuery = { 6 name: string; 7 username: string; 8} 9 10const userQuerySession = session( 11 (query: UserQuery):Promise<User[]> => 12 Promise.resolve([]), 13 'query' 14); 15 16const App = ()=>{ 17 const [query, setQuery] = useState({name:'', username:''}); 18 const [ 19 state 20 ] = userQuerySession.useQuery( 21 [query] 22 ); 23 24 // When useQuery/useMutation responses, 25 // useResponse calls the response callback. 26 useResponse( 27 // response callback 28 (sessionState)=>{ 29 // accept a newest session state. 30 const { 31 data, 32 isError, 33 error, 34 ...... 35 } = sessionState; 36 doSomething(sessionState); 37 }, 38 // listen to the session state of useQuery 39 state 40 ); 41 42 // When useQuery/useMutation responses successfully, 43 // useResponse.useSuccess calls the response callback. 44 useResponse.useSuccess( 45 (data, sessionState)=>{ 46 // accept a newst session state data. 47 // accept a newest session state. 48 doSomething(data); 49 }, 50 // listen to the session state of useQuery 51 state 52 ); 53 54 // When useQuery/useMutation responses unsuccessfully, 55 // useResponse.useFailure calls the response callback. 56 useResponse.useFailure( 57 (error, sessionState)=>{ 58 // accept a newst session state error. 59 // accept a newest session state. 60 doSomething(error); 61 }, 62 // listen to the session state of useQuery 63 state 64 ); 65 ...... 66}
Want to run useQuery or useMutation with some features like debounce?
Strategy
1import React from 'react';
2import {session, Strategy} from '@airma/react-effect';
3import {User} from './type';
4
5type UserQuery = {
6 name: string;
7 username: string;
8}
9
10const userQuerySession = session(
11 (query: UserQuery):Promise<User[]> =>
12 Promise.resolve([]),
13 'query'
14);
15
16const App = ()=>{
17 const [query, setQuery] = useState({name:'', username:''});
18 const [
19 state,
20 trigger,
21 executeWithParams
22 ] = userQuerySession.useQuery(
23 {
24 variables: [query],
25 // set a debouce strategy to take debounce query feature.
26 strategy: Strategy.debounce(300)
27 }
28 );
29
30 ......
31}
The Strategy API contains some useful strategies for useQuery and useMutation. Compose some strategies together can make the session of useQuery/useMutation performance wonderfully.
1import React from 'react';
2import {session, Strategy} from '@airma/react-effect';
3import {User} from './type';
4
5type UserQuery = {
6 name: string;
7 username: string;
8}
9
10const userQuerySession = session(
11 (query: UserQuery):Promise<User[]> =>
12 Promise.resolve([]),
13 'query'
14);
15
16const App = ()=>{
17 const [query, setQuery] = useState({name:'', username:''});
18 const [
19 state,
20 trigger,
21 executeWithParams
22 ] = userQuerySession.useQuery(
23 {
24 variables: [query],
25 // compose different strategies.
26 strategy: [
27 // Validate query.name is not empty,
28 // if it is empty, then stop execute query
29 Strategy.validate(()=>!!query.name),
30 // Query with debounce feature
31 Strategy.debounce(300),
32 // If the response data equals current state.data,
33 // keeps current state.data.
34 Strategy.memo()
35 ]
36 }
37 );
38
39 ......
40}
Want to use SWR(stale-while-revalidate)?
1import React from 'react'; 2import {session, Strategy} from '@airma/react-effect'; 3import {User} from './type'; 4 5type UserQuery = { 6 name: string; 7 username: string; 8} 9 10const userQuerySession = session( 11 (query: UserQuery):Promise<User[]> => 12 Promise.resolve([]), 13 'query' 14); 15 16const App = ()=>{ 17 const [query, setQuery] = useState({name:'', username:''}); 18 const [ 19 state, 20 trigger, 21 executeWithParams 22 ] = userQuerySession.useQuery( 23 { 24 variables: [query], 25 strategy: [ 26 // use swr strategy 27 Strategy.cache({ 28 capacity:10, 29 staleTime:5*60*1000 30 }) 31 ] 32 } 33 ); 34 35 ...... 36}
Introduce
@airma/react-effect
is an asynchronous state-management tool for react. It dependents @airma/react-state, and there are some similar apis between both packages, so, use a common package @airma/react-hooks is a better choice.
Why not use setState in asynchronous callback?
Setting state in asynchronous callback is more easy to take a stale state usage bug in code. And it often makes zombie-children problem too.
When useQuery works?
API useQuery works when it is mounted, or the dependency parameters change, just like React.useEffect performance. It also can be triggered manually.
Install and Support
The package lives in npm. To install the latest stable version, run the following command:
Install command
npm i @airma/react-effect
Browser support
chrome: '>=91',
edge: '>=91',
firefox: '=>90',
safari: '>=15'

No vulnerabilities found.

No security vulnerabilities found.
Gathering detailed insights and metrics for @airma/react-effect