Security News
The Unpaid Backbone of Open Source: Solo Maintainers Face Increasing Security Demands
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
@phnq/state
Advanced tools
The @phnq/state
library is a flexible, efficient, easy-to-use state management solution for React and React Native applications. Built on top of React's Context API, it provides a great way to isolate an application's business logic from its UI, while at the same time allowing convenient access to it from any component.
Getting a few key ideas down will go a long way towards maximizing the usefulness of @phnq/state
.
Similar to React's Context API, @phnq/state
has providers and consumers. A provider is a component where the state's data is kept; a provider provides its services to its descendents in the component tree. A consumer is a React hook that uses some ancestor provider's state.
The consumer/provider relationship is not entirely unlike the client/server relationship. They are similar in the sense that providers/servers are the source of truth, and consumers/clients may access this truth.
A state provider also exposes an API to its consumers; this API is in the form of void-returning functions called actions
. Action functions are basically one-way messages from the consumer to the provider, instructions on how to affect the state. Resulting state changes trickle down to consumers, triggering renders in the context where they are used.
This one-way data flow pattern is known as Flux
, and is ubiquitous in React.
Creating a state provider involves the following:
Here's a trivial example of a state provider that manages a single value, accentColor
. It also provides a single action, setAccentColor
, which updates the accentColor value.
import { createState } from '@phnq/state';
interface State {
accentColor: string;
}
interface Actions {
setAccentColor(accentColor: string): void;
}
export default createState<State, Actions>(
'Theme', // state's name
{
accentColor: "blue", // initial state
},
({ setState }) => ({
setAccentColor(accentColor: string) {
setState({ accentColor });
},
}),
);
The state provider is a HOC (higher-order component) that wraps the component that needs access to the state.
import theme from './theme';
import Box from './Box';
const App = () => (
<div>
<h1>My App</h1>
<Box>I'm in a box!</Box>
</div>
);
// Wrap the App component with the theme provider.
export default theme.provider(App);
Any component that is a descendent of the App
component can consume the the theme
state.
The Box
component is a consumer of the theme state. It's defined in the next section.
The state's useState() hook is used to access some provider's data and actions. This example takes the accentColor
value from the theme state and uses it to set the border color of the box.
import { ReactNode } from 'react';
import theme from './theme';
const Box = ({ children }: { children: ReactNode }) => {
const { accentColor } = theme.useState();
return <div style={{ border: `1px solid ${accentColor}` }}>{children}</div>;
};
export default Box;
The state's same useState() hook is used to access the provider's actions. This example adds a button that, when clicked, invokes the setAccentColor
action.
import { ReactNode } from 'react';
import theme from './theme';
const Box = ({ children }: { children: ReactNode }) => {
const { accentColor, setAccentColor } = theme.useState();
return (
<div style={{ border: `1px solid ${accentColor}` }}>
{children}
<button onClick={() => setAccentColor('red')}>Make red</button>
<button onClick={() => setAccentColor('green')}>Make green</button>
</div>
);
};
Adding async
behaviour to actions is easy thanks to the one-way (Flux) nature of actions. You just need to add the async
keyword.
This example uses a pretend function getRandomColor() which returns a color asynchronously.
import { createState } from '@phnq/state';
import { getRandomColor } from 'some-color-api';
interface State {
accentColor: string;
}
interface Actions {
setAccentColor(accentColor: string): void;
randomizeAccentColor(): void;
}
export default createState<State, Actions>(
'Theme', // state's name
{
accentColor: "blue", // initial state
},
({ setState }) => ({
setAccentColor(accentColor: string) {
setState({ accentColor });
},
async randomizeAccentColor() {
setState({ accentColor: await getRandomColor() });
},
}),
);
The single/monolithic data store approach used by some popular state management libraries is unnecessarily restrictive. The @phnq/state
philosophy is to be flexible and allow for multiple state providers. In addition to providing a natural way to make state more modular, it also provides:
State providers are just components, so since components can be descendents of other components, state providers can be consumers of other state providers.
(examples TBD)
There are a few implicitly available lifecycle actions:
FAQs
State management for React
The npm package @phnq/state receives a total of 32 weekly downloads. As such, @phnq/state popularity was classified as not popular.
We found that @phnq/state demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer 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
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
Security News
License exceptions modify the terms of open source licenses, impacting how software can be used, modified, and distributed. Developers should be aware of the legal implications of these exceptions.
Security News
A developer is accusing Tencent of violating the GPL by modifying a Python utility and changing its license to BSD, highlighting the importance of copyleft compliance.