Hydroxide
Reactive core of the Hydroxide Framework
reactive
Creating State with creates a "reactive" value. Whenever it is updated using any of the updator methods, it automatically updates anything that uses it.
reactive value is a function that when called returns the current value it
const count = reactive(0)
count() // 0
JSX where you use the reactive; gets updated whenever the reactive is updated
function Counter() {
const count = reactive(0)
setInterval(() => {
count.set(count() + 1)
})
return <p> count is {count()} </p>
}
Updating State
Reactive.set
sets a new value for the reactive
count.set(10)
Reactive.do
Reactive.do
takes a transformer function as argument. It is used when you want to assign new value using the previous current value of reactive.
count.do(v => v + 1)
reactive(...path)
to perform a deep update
if you want to update a value deep in a nested object, call the reactive with the path to the value and use the reactive methods to update it.
const user = reactive({
name: 'John Doe',
address: {
street: 'Main St',
city: 'New York'
},
todos: [
{ task: 'Buy milk', done: true },
{ task: 'Buy Groceries', done: false }
]
})
// update street address of the user
user('address', 'street').set('Broadway')
// toggle first task of the user
user('todos', 0, 'done').do(v => !v)
Special State Management APIs for Arrays
Take this state for example:
const todos = reactive([
{ task: 'Buy milk', done: true },
{ task: 'Buy Groceries', done: false },
{ task: 'Grab some snacks', done: false }
])
Here is the list of array methods to perform all kinds of updates
Reactive.push
push the item at the end of array
todos.push({ task: 'Eat Pizza', done: false })
Reactive.insert
insert the item at the specified index
todos.insert(1, { task: 'Write Code', done: true })
Reactive.remove
remove the item at given index, optional second argument is the number of items to remove (default is 1)
// remove 1 todo at index 2
todos.remove(2)
// remove 2 todo at index 3
todos.remove(2, 3)
Reactive.swap
swap the items at given indices
// swap the items at index 2 and 3
todos.swap(2, 3)
Reactive.pop
removes the last item from the array
optional second argument is the number of items to remove (default is 1)
// remove 1 item at the end of array
todos.pop()
// remove 3 items at the end of array
todos.pop(3)
Reactive.pushList
& Reactive.insertList
If you want to insert or push more an entire list instead of an item, use the insertList
and pushList
methods
todos.insertList(3, [
{ task: 'Write Tests', done: true },
{ task: 'Publish Package', done: false }
])
todos.pushList([
{ task: 'Write Tests', done: true },
{ task: 'Publish Package', done: false }
])
Updating Array nested inside an object
call the reactive with path you want to target and use the update methods
const xyz = reactive({
foo: {
bar: {
bazz: [1, 2, 3]
}
}
})
xyz('foo', 'bar', 'bazz').push(4)
effect
Create side effects using effect(() => {
console.log('count is', count())
})
effect takes a function as argument, this function is executed whenever any reactives that are read inside it are updated.
Create a computed value
Creating a computed value is just as simple as wrapping the expression with a function. So It's basically a helper function that calculates and returns value.
function App() {
const count = reactive(0)
const double = () => count() * 2
return (
<div>
<p> count is {count()} </p>
<p> double is {count() * 2} </p>
<p> double is {double()} </p>
</div>
)
}
memo
Create a memoized value using If a value is calculated as a result of a heavy computation, it is not wise to calculate it everytime like this:
function App() {
const count = reactive(0)
const val = () => heavyComputation(count())
return (
<div>
<p> {val()} </p>
<p> {val()} </p>
<p> {val()} </p>
</div>
)
}
Instead it should be memoized using memo
const val = memo(() => heavyComputation(count()))
With this approach, no matter how many times you read the memoized value - val()
, it's value will only be recalculated when any reactive's used for calculating the value isi updated. - count
Lifecycle Hooks
onConnect
, onDisconnect
When a component is connected, the function passed to onConnect
hook is called. When the component is disconnected, the function passed to onDisconnect
hook is called.
function Foo() {
onConnect(() => {
console.log('component connected')
})
onDisconnect(() => {
console.log('component disconnected')
})
return <p> Hello world </p>
}
You can use these hooks multiple times too:
function Foo() {
onConnect(() => {
console.log('component connected 1')
})
onConnect(() => {
console.log('component connected 2')
})
return <p> Hello world </p>
}
Custom Hooks
Using effect
, onConnect
and onDisconnect
you can create custom hooks