![Create React App Officially Deprecated Amid React 19 Compatibility Issues](https://cdn.sanity.io/images/cgdhsj6q/production/04fa08cf844d798abc0e1a6391c129363cc7e2ab-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Create React App Officially Deprecated Amid React 19 Compatibility Issues
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
create-state-machine
Advanced tools
An implementation of state pattern in JavaScript, designed to help removing state-dependent variables.
Please see the motivation and example section on when and why you should use this pattern.
const { createStateMachine } = require('create-state-machine')
createStateMachine(initialState)
Creates a state machine with the given initialState
.
It also calls initialState.enter()
if exists.
stateMachine.getState()
Returns the current state of the state machine.
stateMachine.setState(nextState)
Changes the state of the state machine.
If will call the exit()
method on the previous state if defined, and then call the enter()
method of the next state, if defined.
State pattern is very useful when your system has to exist in different states. Without the state pattern, your variables may be used by some states, but are irrelevant in other states.
For example, consider a message buffer that queues up a messages.
Here’s how it’s likely to be implemented without using state pattern.
// example/createMessageBuffer.normal.js
export function createMessageBuffer (onMove) {
let _connected = false
let _subscriber = null
let _queue = [ ]
return {
push (message) {
if (_connected) {
_subscriber(message)
} else {
_queue.push(message)
}
},
connect (subscriber) {
if (_connected) throw new Error('Already connected!')
_connected = true
_subscriber = subscriber
_queue.forEach((message) => subscriber(message))
_queue = null
},
disconnect () {
if (!_connected) throw new Error('Not connected!')
_connected = false
_subscriber = null
_queue = [ ]
},
isConnected () {
return _connected
}
}
}
export default createMessageBuffer
In this version, there are many state-dependent variables.
_queue
is only used in disconnected state._subscriber
is only used in connected state.But these variables exist under the same scope, although they are used in some states but not the others.
This is a code smell. You have to keep track of the current state and which variables are related to that state when you read/modify the code. Also, if not careful, your system may get into an inconsistent state (e.g. _connected
is false but _queue
is null).
Now, let’s see what happens if you use a state machine.
// example/createMessageBuffer.state.js
import createStateMachine from '../'
export function createMessageBuffer (onMove) {
const { getState, setState } = createStateMachine(disconnectedState())
function disconnectedState () {
const queue = [ ]
return {
connected: false,
push (message) {
queue.push(message)
},
connect (subscriber) {
queue.forEach((message) => subscriber(message))
setState(connectedState(subscriber))
},
disconnect () {
throw new Error('Not connected!')
}
}
}
function connectedState (subscriber) {
return {
connected: true,
push (message) {
subscriber(message)
},
connect () {
throw new Error('Already connected!')
},
disconnect () {
setState(disconnectedState())
}
}
}
return {
push (message) {
return getState().push(message)
},
connect (subscriber) {
return getState().connect(subscriber)
},
disconnect () {
return getState().disconnect()
},
isConnected () {
return getState().connected
}
}
}
export default createMessageBuffer
In this version, each state has its own closure.
queue
.subscriber
.const
; no need for var
or let
.This makes your code cleaner and easier to reason about.
// example/messageBufferTest.js
export default (createMessageBuffer) => {
describe('a message buffer', () => {
it('should flush messages to subscriber', () => {
const buffer = createMessageBuffer()
buffer.push(1)
buffer.push(2)
buffer.push(3)
const subscriber = createSubscriber()
assert.deepEqual(subscriber.getMessages(), [ ])
buffer.connect(subscriber)
assert.deepEqual(subscriber.getMessages(), [ 1, 2, 3 ])
buffer.push(4)
assert.deepEqual(subscriber.getMessages(), [ 1, 2, 3, 4 ])
})
it('should queue messages to the next subscriber when one disconnects', () => {
const buffer = createMessageBuffer()
buffer.push(1)
buffer.connect(createSubscriber())
buffer.push(2)
buffer.disconnect()
buffer.push(3)
const subscriber = createSubscriber()
buffer.connect(subscriber)
assert.deepEqual(subscriber.getMessages(), [ 3 ])
buffer.push(4)
assert.deepEqual(subscriber.getMessages(), [ 3, 4 ])
})
it('should not allow multiple subscribers', () => {
const buffer = createMessageBuffer()
buffer.connect(createSubscriber())
assert.throws(() => {
buffer.connect(createSubscriber())
})
})
it('should allow querying its status', () => {
const buffer = createMessageBuffer()
assert(!buffer.isConnected())
buffer.connect(createSubscriber())
assert(buffer.isConnected())
buffer.disconnect()
assert(!buffer.isConnected())
})
it('fails when disconnecting a disconnected buffer', () => {
assert.throws(() => {
createMessageBuffer().disconnect()
})
})
})
function createSubscriber () {
const messages = [ ]
function subscriber (message) {
messages.push(message)
}
subscriber.getMessages = () => messages
return subscriber
}
}
// example/createMessageBuffer.normal.test.js
import messageBufferTest from './messageBufferTest'
import createMessageBuffer from './createMessageBuffer.normal'
messageBufferTest(createMessageBuffer)
// example/createMessageBuffer.state.test.js
import messageBufferTest from './messageBufferTest'
import createMessageBuffer from './createMessageBuffer.state'
messageBufferTest(createMessageBuffer)
Here’s the entire implementation of createStateMachine
.
You see, it’s pretty simple!
// index.js
export function createStateMachine (initialState) {
let _state
function getState () {
return _state
}
function setState (nextState) {
if (nextState !== _state) {
if (_state && _state.exit) _state.exit()
_state = nextState
if (_state.enter) _state.enter()
}
}
setState(initialState)
return { getState, setState }
}
export default createStateMachine
FAQs
Implementation of the State Pattern in JavaScript.
We found that create-state-machine demonstrated a not healthy version release cadence and project activity because the last version was released 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
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.