The type of the atom's value.
ReadonlyAtomSetter is the tep of the set
function passed to the start
function provided to a ReadonlyAtom.
The type of the atom's value.
ReadonlyAtomStarter is a function that initiates the value setting for a ReadonlyAtom, this method is called when the first subscriber to a ReadonlyAtom subscribes and is expected to return a stop function that will cleanup any intervals or timeouts, etc... that the start function created. This stop function is called when the last subscriber unsubscribes from the ReadonlyAtom so that anything that is running is only going to run while being listened to.
It's good practice to always seed with an updated value (if applicable) when the start function is called, for example consider this ReadonlyAtom that represents the current time:
const clock = readonlyAtom(new Date().toLocaleString(), set => {
set(new Date().toLocaleString());
const interval = setInterval(() => {
set(new Date().toLocaleString());
}, 1000);
return () => {
clearInterval(interval);
};
});
Despite providing an initial value we also set an updated value as the first line in the start function so that after a period of no subscribers we can ensure that we have an updated value instead of a stale value. This does not apply to all use cases though, in some cases there may not be an updated value you can set, perhaps if you're ReadonlyAtom is representing the current user or something that would require a network request for fresh data.
The type of the atom's value.
The atom is the core of @nuka/sate. It represents a piece of data that can be set or udpated anywhere in an application and provides the capability for a user to subscribe and listen for the changes. This allows your data to be used in a variety of places around your application while also allowing the consumers that need to respond to changes the capability of knowing when the value has been modified. Examples can range from user authentication tokens, application objects, counts, or any other data where you may need access to it in more than one place but wish to be notified when it's value has changed.
const counter = atom(0);
const countDisplay = document.getElementById("display-counter");
counter.subscribe((atom) => {
countDisplay.textContent = `Current count: ${atom.value}`;
});
const incrementButton = document.getElementById("increment-counter");
incrementButton.addEventListener("click", () => counter.update((n) => n + 1));
See it on CodePen.
The type of the atom's value.
The initial value of the atom.
A new atom containing the initial value ready for use.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
Create a new projector, which will take in atom-like objects as input and a function that combines their values into a new value. Commonly this is referred to as a "computed value." Projectors can be used to many purposes, if the new data is just a unique combination of existing values then it's better to use a Projector which will automatically subscribe to the passed in atom-like objects and update when they update. Coordinating this without a projector is possible but why go through all that extra work?
Since ReadonlyAtom's don't "start" when they don't have subscribers, Projector tries to play smart and mimic this. If it detects that it received a ReadonlyAtom as an input atom it will not subscribe to it unless the Projector itself has a subscriber. If the ReadonlyAtom is live and running then the Projector will be out of sync with it's current value. To fix this, provide a no-op subscriber to the projector or subscribe to it to receive reactive updates.
Probably the simpleist example of a projector is summing up multiple count atoms.
const counter1 = atom(0);
const counter2 = atom(0);
const display1 = document.getElementById("display-counter-1");
counter1.subscribe((count) => {
display1.textContent = `Current count: ${count.value}`;
});
const incr1 = document.getElementById("increment-counter-1");
incr1.addEventListener("click", () => counter1.update((n) => n + 1));
const display2 = document.getElementById("display-counter-2");
counter2.subscribe((count) => {
display2.textContent = `Current count: ${count.value}`;
});
const incr2 = document.getElementById("increment-counter-2");
incr2.addEventListener("click", () => counter2.update((n) => n + 1));
const sum = projector(counter1, counter2, (a, b) => a + b);
const sumDisplay = document.getElementById("display-sum");
sum.subscribe((sum) => {
sumDisplay.textContent = `Total count: ${sum.value}`;
});
See it on CodePen.
Projectors don't always have to be used with multiple atoms, somtimes you just want to be able to have and update data from a single atom in a different way. Like showing the full name for a user.
const user = atom({
firstName: 'Peter',
lastName: 'Programmer',
});
const fullName = projector(user, u => `${u.firstName} ${u.lastName}`);
const firstNameInput = document.getElementById('first-name');
firstNameInput.value = user.value.firstName;
firstNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, firstName: event.target.value }));
});
const lastNameInput = document.getElementById('last-name');
lastNameInput.value = user.value.lastName;
lastNameInput.addEventListener('input', event => {
user.update(oldUser => ({ ...oldUser, lastName: event.target.value }));
});
const fullNameDisplay = document.getElementById('display-full-name');
fullNameDisplay.textContent = fullName.value;
fullName.subscribe(name => {
fullNameDisplay.textContent = name.value;
});
See it on CodePen
A simple and clean way to control how data is rendered, just modify fullName
's
projection function to, say, change the computed value to last, first
instead.
A new projector that will act like an atom (has a value, subscribe, and unsubscribe function). This projector's projection function will be executed when any of the atoms provided are updated.
readonlyAtom will create a new ReadonlyAtom instance with the provided initial value and start function. Readonly atoms are atoms that do not allow users to set or modify values, just read; however, this does not mean their value has to be static. If only an initialValue is provided then the returned readonly atom will have a static value, however if you also pass in a start function, this will receive a set function as an argument and from here you can do whatever you might need, such as running a timeout or interval or any other mechanism you need to periodically update the atoms value.
A really common example case is a clock:
const clock = readonlyAtom(new Date(), (set) => {
set(new Date());
const interval = setInterval(() => {
set(new Date());
}, 1000);
return () => {
clearInterval(interval);
};
});
const dateTimeDisplay = document.getElementById("date-time");
clock.subscribe((atom) => {
dateTimeDisplay.textContent = atom.value.toLocaleString();
});
See it on CodePen.
Another possible example would be to handle other values set by something else, such as the window scroll event, which can be throttled to prevent unnecessary spam.
const scrollContainer = document.body;
const scrollTop = readonlyAtom(scrollContainer.scrollTop, (set) => {
set(scrollContainer.scrollTop);
const onScroll = throttle(
() => {
set(scrollContainer.scrollTop);
},
200,
true
);
scrollContainer.addEventListener("scroll", onScroll);
() => {
scrollContainer.removeEventListener("scroll", onScroll);
};
});
const display = document.getElementById("scroll-value");
scrollTop.subscribe((atom) => {
display.textContent = Math.round(atom.value);
});
See it on CodePen.
The type of the atom's value.
The initial value of the ReadonlyAtom.
The start function that should run if the ReadonlyAtom is live or has subscribers.
The ReadonlyAtom instance that can be used as readonly storage.
Generated using TypeDoc
An atom updater is either a new value or a function that will generate the next value for the atom.