XSta
is an ultra-lightweight (<200 lines) React state management solution that provides an intuitive useState
Hook-like interface, offering a seamless state management experience with zero learning curve and migration cost.
- 🐦 Tiny yet Powerful Less than 200 lines of code, a full-fledged React state management solution, battle-tested for production.
- 🧩 Zero Learning and Migration Costs Just replace
useState
withuseXState
, and the local component state becomes instantly shareable across other components - it's that easy! - 💪 Performance Optimized Only re-render when component's subscribed state changes, effortlessly optimizing complex page performance.
# With npm
npm install xsta
# With pnpm
pnpm install xsta
# With Yarn
yarn add xsta
Simply replace useState
with useXState
and provide a unique key
to turn your local component state into a globally shareable state.
👉 Example
import { useXState } from 'xsta';
export default function Counter() {
const [count, setCount] = useXState('count', 0); // It's that easy!
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
<p>You pressed me {count} times</p>
</button>
);
}
You can also directly access and modify specific state from anywhere outside components using XSta
.
When the external state changes, dependent components will automatically update.
👉 Example
import { useXState, XSta } from 'xsta';
function externalFunction() {
const count = XSta.get('count');
XSta.set('count', count + 1);
}
export default function Counter() {
const [count, setCount] = useXState('count', 0);
return (
<button onClick={externalFunction}>
<p>You pressed me {count} times</p>
</button>
);
}
To better manage state during development, it's common to encapsulate state-related operations by module.
XStaManager
provides a basic state management interface for this purpose. Here's a simple example of createXStaManager
.
👉 Example
// counter.state.ts
import { createXStaManager } from 'xsta';
export const CounterState = createXStaManager({
key: 'count',
initialState: 0,
});
// Counter.ts
import { CounterState } from 'counter.state';
function externalFunction() {
CounterState.setState(count => count + 1);
}
export default function Counter() {
const [count] = CounterState.useState();
return (
<button onClick={externalFunction}>
<p>You pressed me {count} times</p>
</button>
);
}
Furthermore, you can extend XStaManager
and provide a unified state management interface. (Recommended)
👉 Example
// counter.state.ts
import { XStaManager } from 'xsta';
class _CounterState extends XStaManager<number> {
key = 'count';
initialState = 0;
get oddOrEven() {
return this.getState() & 1 ? 'odd' : 'even';
}
increase = () => {
this.setState(count => count + 1);
};
decrease = () => {
this.setState(count => count - 1);
};
}
export const CounterState = new _CounterState();
// Counter.ts
import { CounterState } from 'counter.state';
export default function Counter() {
const [count] = CounterState.useState();
return (
<>
<p>You pressed me {count} times</p>
<p>Count is {CounterState.oddOrEven}</p>
<button onClick={CounterState.increase}>Increase</button>
<button onClick={CounterState.decrease}>Decrease</button>
</>
);
}
If a component is computationally expensive to build, or if your state is a complex object with multiple components depending on different properties, you can wrap it with XConsumer
and use a state selector to control when the child components should re-render.
👉 Example
import { useXState, XConsumer } from 'xsta';
export default function UserProfile() {
const [profile, setProfile] = useXState('profile', {
avatar: 'https://github.com/fluidicon.png',
age: 18,
bio: 'hello world!',
});
console.log('UserProfile rebuild', profile);
return (
<>
<XConsumer provider="profile" selector={s => s.avatar}>
<UserAvatar /> {/* UserAvatar will only re-render when avatar changes */}
</XConsumer>
<XConsumer provider="profile" selector={s => [s.age, s.bio]}>
{profile => {
// You can also directly access the current state value
return <UserInfo age={profile.age} bio={profile.bio} />;
}}
</XConsumer>
</>
);
}
useXConsumer
is an alias for useXState
that allows for more convenient subscription to state updates.
👉 Example
import { useXConsumer } from 'xsta';
function WatchText() {
// This component will automatically re-render when myState.text changes
const [state] = useXConsumer('myState', s => s.text);
return <p>Current text: {state.text}</p>;
}
XSta
provides a few more utilities for advanced use cases:
useXProvider(key, initialState)
: Initializes a global state value.XSta.delete(key)
: Deletes a global state value.XSta.clear(key)
: Clears all global state values.
👉 Example
import { useXState, useXProvider, XSta } from 'xsta';
const initialState = 0;
export default function APP() {
// Initialize state
useXProvider('count', initialState);
return (
<>
<CountViewer />
<Increase />
<Clear />
</>
);
}
function Clear() {
return (
<button
onClick={() => {
// Delete the "count" state
XSta.delete('count');
// Clear all states
XSta.clear();
}}
>
Clear
</button>
);
}
function CountViewer() {
const [count] = useXState('count');
return <p>You pressed me {count ?? initialState} times</p>;
}
function Increase() {
return (
<button
onClick={() => {
XSta.set('count', XSta.get('count', initialState) + 1);
}}
>
Increase
</button>
);
}
Note: By default, XSta
does not automatically initialize or clean up global states. Instead, developers decide when to initialize and destroy state values. Therefore, please be careful when using it to prevent issues like using an uninitialized state or memory leaks.