Research
Security News
Threat Actor Exposes Playbook for Exploiting npm to Build Blockchain-Powered Botnets
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Zustand is a state management library for React and other JavaScript applications. It provides a simple and flexible way to create and manage global state without the complexity of traditional solutions like Redux. Zustand uses a hook-based API to allow components to subscribe to state changes and define actions for updating the state.
Creating a store
This code sample demonstrates how to create a store with Zustand. The store has a state with a 'fishes' property and an 'addFish' action to increment the number of fishes.
import create from 'zustand';
const useStore = create(set => ({
fishes: 0,
addFish: () => set(state => ({ fishes: state.fishes + 1 }))
}));
Subscribing to state changes
This code sample shows how a React component can subscribe to state changes. The 'FishCounter' component uses the 'useStore' hook to access the number of fishes from the store's state.
import React from 'react';
import useStore from './store';
function FishCounter() {
const fishes = useStore(state => state.fishes);
return <div>{fishes} fishes</div>;
}
Updating the state
This code sample illustrates how to update the state using an action defined in the store. The 'AddFishButton' component gets the 'addFish' action from the store and uses it as an onClick event handler.
import React from 'react';
import useStore from './store';
function AddFishButton() {
const addFish = useStore(state => state.addFish);
return <button onClick={addFish}>Add a fish</button>;
}
Redux is a predictable state container for JavaScript apps. It is more complex than Zustand, involving actions, reducers, and middleware, making it suitable for larger applications with more complex state management needs.
MobX is a state management library that uses observable state objects and reactions to automatically track changes and update the UI. It is more opinionated than Zustand and uses a different paradigm based on observables.
Recoil is a state management library for React that provides a more granular approach to managing state with atoms and selectors. It is similar to Zustand in its simplicity but offers more advanced features for derived state and asynchronous queries.
React Context API is not a package but a built-in feature of React for managing state. It is simpler than Zustand but can lead to performance issues in larger applications due to unnecessary re-renders.
npm install zustand
Small, fast and scaleable bearbones state-management solution. Has a comfy api based on hooks, isn't that boilerplatey or opinionated, but still just enough to be explicit and flux-like, not context based (no reliance on providers, breaches reconciler boundaries), and is cross-platform to boot. Make your paws dirty with a small live demo here.
You could be in global or component scope, manage your store anywhere you want!
import create from 'zustand'
// Name your store anything you like, but remember, it's a hook!
const [useStore] = create(set => ({
// Everything in here is your state
count: 1,
// You don't have to nest your actions, but makes it easier to fetch them later on
actions: {
inc: () => set(state => ({ count: state.count + 1 })), // same semantics as setState
dec: () => set(state => ({ count: state.count - 1 })),
},
}))
Look Ma, no providers!
function Counter() {
// Will only re-render the component when "count" changes
const count = useStore(state => state.count)
return <h1>{count}</h1>
}
function Controls() {
// "actions" isn't special, we just named it like that to fetch updaters easier
const { inc, dec } = useStore(state => state.actions)
return (
<>
<button onClick={inc}>up</button>
<button onClick={dec}>down</button>
</>
)
}
You can, but remember that it will cause the component to update on every state change!
const data = useStore()
It's just like mapStateToProps in Redux. zustand will run a small shallow equal over the object you return. Of course, it won't cause re-renders if these properties aren't changed in the state model.
const { name, age } = useStore(state => ({ name: state.name, age: state.age }))
Or, if you prefer, atomic selects do the same ...
const name = useStore(state => state.name)
const age = useStore(state => state.age)
Since you can create as many stores as you like, forwarding a result into another selector is straight forward.
const currentUser = useCredentialsStore(state => state.currentUser)
const person = usePersonStore(state => state.persons[currentUser])
Just call set
when you're ready, it doesn't care if your actions are async or not.
const [useStore] = create(set => ({
result: '',
fetch: async url => {
const response = await fetch(url)
const json = await response.json()
set({ result: json })
},
}))
The set
function already allows functional update set(state => result)
but should there be cases where you need to access outside of it you have an optional get
, too.
const [useStore] = create((set, get) => ({
text: "hello",
action: () => {
const text = get().text
...
}
}))
Having to build nested structures bearhanded is one of the more tiresome aspects of reducing state. Have you tried immer? It is a tiny package that allows you to work with immutable state in a more convenient way. You can easily extend your store with it.
import produce from "immer"
const [useStore] = create(set => ({
set: fn => set(produce(fn)),
nested: {
structure: {
constains: {
a: "value"
}
}
},
}))
const set = useStore(state => state.set)
set(draft => {
draft.nested.structure.contains.a.value = false
draft.nested.structure.contains.anotherValue = true
})
const types = {
increase: "INCREASE",
decrease: "DECREASE"
}
const reducer = (state, { type, ...payload }) => {
switch (type) {
case types.increase: return { ...state, count: state.count + 1 }
case types.decrease: return { ...state, count: state.count - 1 }
}
return state
}
const [useStore] = create(set => ({
count: 0,
dispatch: args => set(state => reducer(state, args)),
}))
const dispatch = useStore(state => state.dispatch)
dispatch({ type: types.increase })
You can use it with or without React out of the box.
const [, api] = create({ n: 0 })
// Getting fresh state
const n = api.getState().n
// Listening to changes
const unsub = api.subscribe(state => console.log(state.n))
// Updating state, will trigger listeners
api.setState({ n: 1 })
// Unsubscribing handler
unsub()
// Destroying the store
api.destroy()
const logger = fn => (set, get) => fn(args => {
console.log(" applying", args)
set(args)
console.log(" new state", get())
}, get)
const [useStore] = create(logger(set => ({
text: "hello",
setText: text => set({ text })
})))
FAQs
🐻 Bear necessities for state management in React
The npm package zustand receives a total of 2,801,067 weekly downloads. As such, zustand popularity was classified as popular.
We found that zustand demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 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
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.