Security News
Opengrep Emerges as Open Source Alternative Amid Semgrep Licensing Controversy
Opengrep forks Semgrep to preserve open source SAST in response to controversial licensing changes.
@airma/react-state
Advanced tools
Simple reducer-like
state-management with method action dispatch mode for react components.
Create reducer-like
function:
export function counting(state:number){
return {
// reproduced state for render
count: `mount: ${state}`,
// action method
increase:()=>count + 1,
// action method
decrease:()=>count - 1,
// action method, define parameters freely.
add(...additions: number[]){
return additions.reduce((result, current)=>{
return result + current;
}, count);
}
};
}
Use reducer-like
function:
import {counting} from './model';
import {useModel} from '@airma/react-state';
......
// give it an initialState can make it fly.
const {count, increase, decrease, add} = useModel(counting, 0); // initialState `0`
// call method `increase\decrease\add` can change `count` and make component rerender
......
The reducer-like
function has a simple name model
. Use API model
can make it more simple.
import {model} from '@airma/react-state';
// api model returns a wrap function for your model function.
// it keeps a same type of parameters and return data with the wrapped function.
const counting = model(function counting(state:number){
return {
count: `mount: ${state}`,
increase:()=>count + 1,
decrease:()=>count - 1,
add(...additions: number[]){
return additions.reduce((result, current)=>{
return result + current;
}, count);
}
};
});
......
// you can get useModel from the model wrapped function.
const {count, increase, decrease, add} = counting.useModel(0);
......
Though, the basic function about model
is enhancing React.useReducer
to manage a local state, it also supports store usage with or without React.Context
to manage a global state.
import {memo} from 'react';
import {model} from '@airma/react-state';
const countingStore = model(function counting(state:number){
return {
count: `mount: ${state}`,
increase:()=>count + 1,
decrease:()=>count - 1,
add(...additions: number[]){
return additions.reduce((result, current)=>{
return result + current;
}, count);
}
};
}).createStore(0);
......
const Increase = memo(()=>{
// use store.useSelector can share state changes from store,
// when the selected result is changed it rerender component.
const increase = countingStore.useSelector(i => i.increase);
return <button onClick={increase}>+</button>;
});
const Count = memo(()=>{
// use store.useModel can share state changes from store.
const {count} = countingStore.useModel();
return <span>{count}</span>;
});
const Decrease = memo(()=>{
const decrease = countingStore.useSelector(i => i.decrease);
return <button onClick={decrease}>-</button>;
});
// provide store to component for a React.Context usage.
const Component = countingStore.provideTo(function Comp() {
return (
<div>
<Increase/>
<Count/>
<Decrease/>
</div>
);
});
......
Using model(xxx).createStore().asGlobal()
can build a global store.
import {model} from '@airma/react-state';
const countingStore = model(function counting(state:number){
return {
count: `mount: ${state}`,
increase:()=>count + 1,
decrease:()=>count - 1,
add(...additions: number[]){
return additions.reduce((result, current)=>{
return result + current;
}, count);
}
};
}).createStore(0).asGlobal();
// `createStore(0).static()` is same with `createStore(0).asGlobal()`.
......
const Increase = memo(()=>{
const increase = countingStore.useSelector(i => i.increase);
return <button onClick={increase}>+</button>;
});
const Count = memo(()=>{
const {count} = countingStore.useModel();
return <span>{count}</span>;
});
const Decrease = memo(()=>{
const decrease = countingStore.useSelector(i => i.decrease);
return <button onClick={decrease}>-</button>;
});
// use global store without provider.
const Component = function Comp() {
return (
<div>
<Increase/>
<Count/>
<Decrease/>
</div>
);
};
The useSelector
API is helpful for reducing render frequency, only when the selected result is changed, it make its owner component rerender.
In @airma/react-state@18.4.0
, a more simple and higher performance API useSignal
is provided.
import {model} from '@airma/react-state';
const counting = model(function countingModel(state:number){
return {
count: `mount: ${state}`,
increase:()=>count + 1,
decrease:()=>count - 1,
add(...additions: number[]){
return additions.reduce((result, current)=>{
return result + current;
}, count);
}
};
}).createStore().static();
// Give initialized state later in component render time.
......
const Increase = memo(()=>{
// API `useSignal` returns a signal function,
// which can be called to get the newest instance from store.
// Only the render usage fields of this instance change makes component rerender.
// Here, only the action method `increase` from instance is required, and as the action method is stable with no change, that makes component never rerender.
const signal = counting.useSignal();
return <button onClick={signal().increase}>+</button>;
});
const Count = memo(()=>{
const signal = counting.useSignal();
return <span>{signal().count}</span>;
});
const Decrease = memo(()=>{
const signal = counting.useSignal();
return <button onClick={signal().decrease}>-</button>;
});
const Component = function Comp({defaultCount}:{defaultCount:number}) {
// API `useSignal` can initialize store state in render too.
// The difference with `useModel` is that `useSignal` only rerenders component when the render usage fields of instance changes.
counting.useSignal(defaultCount);
return (
<div>
<Increase/>
<Count/>
<Decrease/>
</div>
);
};
The useSignal
API is even better than API useSelector
, it computes out when to rerender component by the fields getting from instance automatically. And by using the signal
function, it always provides a newest instance in usage point, so it can avoid stale data and zombie-children problems more effectively.
In @airma/react-state
, store is dynamic, every provider
copies a working instance for a context usage.
That means:
provider
component unmount.The store provider system in @airma/react-state
is designed with a tree structure. The nearest provider
finds store one-by-one from itself to its root parent provider
, and links the nearest matched provider
store to the subscriber useModel/useSelector
.
No, only the hooks subscribing this store
may rerender their owners. Every store change is notified to its subscriber like useModel
and useSelector
, and then the subscriber rerenders its owner by useState
.
Async action often makes the problem about stale data and zombie-children. So, a special tool to resolve this problem is necessary, you can try @airma/react-effect with it.
There are more examples, concepts and APIs in the documents of @airma/react-state
.
chrome: '>=91',
edge: '>=91',
firefox: '=>90',
safari: '>=15'
FAQs
the purpose of this project is make useReducer more simplify
The npm package @airma/react-state receives a total of 33 weekly downloads. As such, @airma/react-state popularity was classified as not popular.
We found that @airma/react-state demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Opengrep forks Semgrep to preserve open source SAST in response to controversial licensing changes.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.