Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@creatdevsolutions/cs-react-global-stores
Advanced tools
Generic Store Provider to attach data to React Components using the react context api
With this library, we want to provide a lightweigt, dynamic global store using the react context api. The idea is to combine partial stores into one global store and pass the global store (or only parts of it) down to react components using decorators.
Start with the definition of your partial stores. A partial store should store any variables that belong to the same topic. Partial Stores can be implemented via js objects or in the more common way via es6 classes.
Partially stores are defined as interfaces for the types and a js object defining the default value. These partial stores have to extend the interface PartialStore. Additionally, you have to create a default value for this store.
interface UserStore extends PartialStore {
userName: string;
}
const userStore: UserStore = {
userName: "InitialValue",
};
After defining all your partial stores, create one global store interface, which has all partial stores as members. This interface has to be exported to use it for the attached components, see later.
export interface MyStore extends Store {
userStore: UserStore;
}
const store: MyStore = {
userStore: userStore
};
To improve the code qualitiy and the implementation of stores, we provide the possibility to implement a partial store via es6 classes. To do so, just extend the abstract class PartialStoreClass.
export class UserStore extends PartialStoreClass {
userName?: string;
}
To fill up your global store with a es6 class partial store, just call the constructor of your class to create a new instance of your partial store.
export interface MyStore extends Store {
userStore: UserStore;
}
const store: MyStore = {
userStore: new UserStore()
};
If you finished defining all your partial stores and your global store, simply put it into the StoreProvider component.
class MyComponent extends React.Component {
render() {
return (
<StoreProvider value={store}>
<SampleComponent/>
<SampleComponent2/>
</StoreProvider>
);
}
}
We provide 2 ways to attach the global store to react components. You can fully attach the global store to your component and it will receive the whole store object as prop or you can partially attach it to your component and device manually which parts of the store you want to have (analogue to react redux).
Important is the generic argument to our decorators. You have to pass the type of the props that your Component should receive in the tree (not injected by the global store). Consequently, we divided the Props of our Components into the Props that it gets from outside (Props) and the injected store props (StoreProps).
To fully attach a component to your global store, simply decorate it with the AttachStore decorator.
import * as React from "react";
import {MyStore} from "./StoreTest";
import {AttachStore} from "..";
interface Props {
test: string; // Obviously, any other properties are supported
}
interface StoreProps {
store: MyStore;
}
class SampleComponent extends React.Component<Props & StoreProps> {
render() {
return (
<p>
{this.props.store.userStore.userName}
</p>
);
}
}
// Calling the AttachStore decorator and your component will receive the
// global store
//
// By using the generic argument, only the prop test has to be passed
// to SampleComponent
export default AttachStore<Props>(SampleComponent);
If you want to have only parts of your global store available in your component, you can decorate it with the AttachPartsOfStore decorator and pass a function into it, which maps the store down to your props. This is quite similar to react redux, but is easier to use with typescript.
import * as React from "react";
import {PartialStore} from "..";
import {MyStore} from "./StoreTest";
import {AttachPartsOfStore} from "../Provider/Provider";
interface Props {
}
interface StoreProps {
userName: string;
}
class SampleComponent2 extends React.Component<Props & StoreProps> {
render() {
return (
<button>
{this.props.userName}
</button>
);
}
}
// In this case, only the username is required
const mapStoreToProps: any = (store: MyStore) => {
return {
userName: store.userStore.userName
};
};
export default AttachPartsOfStore<Props>(mapStoreToProps)(SampleComponent2);
Updating can also be done in 2 ways, regarding the attachment of your components. You can either call "setState" on a partial store in a fully attached component, or map the setState function to a prop in a partially attached component.
Since each PartialStore provides a setState Method, you can simply call it on the partial store and it will trigger the state update in the global store.
import * as React from "react";
import {MyStore} from "./StoreTest";
import {AttachStore} from "..";
interface Props {
test: string; // Obviously, any other properties are supported
}
interface StoreProps {
store: MyStore;
}
class SampleComponent extends React.Component<Props & StoreProps> {
render() {
return (
<button
onClick={() =>
this.props.store.userStore.setState({userName: "NewUser"})}
>
{this.props.store.userStore.userName}
</button>
);
}
}
export default AttachStore<Props>(SampleComponent);
The second way is to map the setState function of a store to a new prop, which is beneficial if not the whole partial store is required in a component. We recomment highly to use the following type for mapped setState function: "(store: Partial) => void;", since other types may result in typescript errors
import * as React from "react";
import {PartialStore} from "..";
import {MyStore} from "./StoreTest";
import {AttachPartsOfStore} from "../Provider/Provider";
interface Props {
}
interface StoreProps {
userName: string;
setUserStoreState: (store: Partial<PartialStore>) => void;
}
class SampleComponent2 extends React.Component<Props & StoreProps> {
render() {
console.log("render Sample Component");
return (
<button
onClick={() =>
this.props.setUserStoreState({userName: "NewUser"})}
>
{this.props.userName}
</button>
);
}
}
const mapStoreToProps: any = (store: MyStore) => {
return {
userName: store.userStore.test,
setUserStoreState: store.userStore.setState
};
};
export default AttachPartsOfStore<Props>(mapStoreToProps)(SampleComponent2);
We define two signatures for custom store functions. You can either have a function that returns parts of your partial store that will be merged into it or return a promise and change the store internally. For the second approach, implementation via es6 classes is required.
We allow you to define custom functions on your partial stores to combine complex logic with store updates. The return value of the function will be merged into the partial store after the function is executed. This should be our alternative solution to actions and reducers of redux.
The signature for a custom function that updates the store with the return value looks like this:
func: (any) => Partial<PartialStore> // Insert your partial store type here
Example:
export interface UserStore extends PartialStore {
login: (userName: string, password: string) => Partial<UserStore>;
clientUser?: object;
}
const login: (userName: string, password: string) => Partial<UserStore> = (userName: string, password: string) => {
// Do login here...
return {
clientUser: {
userName,
password
}
};
};
const userStore: UserStore = {
login: login,
};
Partial stores implemented via es6 classes can change the state in custom functions simply calling this.setState. This is analogue to calling dispatch in redux, but we do not support changing the state of another partial store.
In the following example, we implemented a login method that returns a promise and internally updates the userStore and also waits until the update is finished before resolving:
export class UserStore extends PartialStoreClass {
clientUser?: UserType;
login(user: IUser, password: string): Promise<UserType> {
return new Promise ((resolve, reject) => {
service.login(user, password)
.then((result: any) => {
logger.info("User logged in");
this.setState({
clientUser: result.user
},
// Passing a callback as second parameter to setState
// To wait until state update finished
() => {
resolve(clientUser)
});
})
.catch((error: any[]) => {
logger.warn('User session closed.', error);
reject(error);
});
});
}
}
FAQs
Generic Store Provider to attach data to React Components using the react context api
The npm package @creatdevsolutions/cs-react-global-stores receives a total of 0 weekly downloads. As such, @creatdevsolutions/cs-react-global-stores popularity was classified as not popular.
We found that @creatdevsolutions/cs-react-global-stores demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 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.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.