recoil#atomFamily TypeScript Examples
The following examples show how to use
recoil#atomFamily.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: groups.ts From abrechnung with GNU Affero General Public License v3.0 | 6 votes |
groupById = atomFamily({
key: "groupById",
default: selectorFamily({
key: "groupById/default",
get:
(groupID) =>
async ({ get }) => {
const groups = get(groupList);
return groups.find((group) => group.id === groupID);
},
}),
})
Example #2
Source File: groups.ts From abrechnung with GNU Affero General Public License v3.0 | 6 votes |
groupMembers = atomFamily<Array<GroupMember>, number>({
key: "groupMembers",
effects_UNSTABLE: (groupID) => [
({ setSelf }) => {
setSelf(
fetchMembers({ groupID: groupID })
.then((members) => sortMembers(members))
.catch((err) => toast.error(`error when fetching group members: ${err}`))
);
ws.subscribe("group_member", groupID, (subscription_type, { user_id, element_id }) => {
if (element_id === groupID) {
fetchMembers({ groupID: element_id })
.then((result) => setSelf(sortMembers(result)))
.catch((err) => toast.error(`error when updating group members: ${err}`));
}
});
// TODO: handle registration errors
return () => {
ws.unsubscribe("group_member", groupID);
};
},
],
})
Example #3
Source File: groups.ts From abrechnung with GNU Affero General Public License v3.0 | 6 votes |
groupInvites = atomFamily<Array<GroupInvite>, number>({
key: "groupInvites",
effects_UNSTABLE: (groupID) => [
({ setSelf }) => {
setSelf(
fetchInvites({ groupID: groupID }).catch((err) =>
toast.error(`error when fetching group invites: ${err}`)
)
);
ws.subscribe("group_invite", groupID, (subscription_type, { invite_id, element_id }) => {
if (element_id === groupID) {
fetchInvites({ groupID: element_id }).then((result) => setSelf(result));
}
});
// TODO: handle registration errors
return () => {
ws.unsubscribe("group_invite", groupID);
};
},
],
})
Example #4
Source File: groups.ts From abrechnung with GNU Affero General Public License v3.0 | 6 votes |
groupLog = atomFamily<Array<GroupLog>, number>({
key: "groupLog",
effects_UNSTABLE: (groupID) => [
({ setSelf }) => {
setSelf(
fetchLog({ groupID: groupID }).catch((err) => toast.error(`error when fetching group log: ${err}`))
);
ws.subscribe("group_log", groupID, (subscription_type, { log_id, element_id }) => {
if (element_id === groupID) {
fetchLog({ groupID: element_id }).then((result) => setSelf(result));
}
});
// TODO: handle registration errors
return () => {
ws.unsubscribe("group_log", groupID);
};
},
],
})
Example #5
Source File: transactions.ts From abrechnung with GNU Affero General Public License v3.0 | 6 votes |
pendingTransactionPositionChanges = atomFamily<LocalPositionChanges, number>({
// transaction id -> pending changes
key: "pendingTransactionPositionChanges",
default: {
modified: {}, // map of positions with server given ids
added: {}, // map of positions with local id to content
empty: {
id: -1,
name: "",
price: 0,
communist_shares: 0,
usages: {},
deleted: false,
},
},
effects_UNSTABLE: (transactionID) => [localStorageEffect(`localTransactionPositionChanges-${transactionID}`)],
})
Example #6
Source File: customHooks.ts From frames with Mozilla Public License 2.0 | 5 votes |
hookChangeAtomFamily = atomFamily<any, string>({
key: 'hookChangeAtomFamily',
default: undefined
})
Example #7
Source File: mod-progress-state.ts From ow-mod-manager with MIT License | 5 votes |
modProgressState = atomFamily<number, string | undefined>({
key: 'ModProgress',
default: 0,
})
Example #8
Source File: mod-progress-state.ts From ow-mod-manager with MIT License | 5 votes |
modIsLoadingState = atomFamily<boolean, string | undefined>({
key: 'ModIsLoading',
default: false,
})
Example #9
Source File: accounts.ts From abrechnung with GNU Affero General Public License v3.0 | 5 votes |
groupAccounts = atomFamily<Array<Account>, number>({
key: "groupAccounts",
effects_UNSTABLE: (groupID) => [
({ setSelf, getPromise, node }) => {
// TODO: handle fetch error
setSelf(
fetchAccounts({ groupID: groupID }).catch((err) => toast.error(`error when fetching accounts: ${err}`))
);
const fetchAndUpdateAccount = (currAccounts: Array<Account>, accountID: number, isNew: boolean) => {
fetchAccount({ accountID: accountID })
.then((account) => {
if (isNew) {
// new account
setSelf([...currAccounts, account]);
} else {
setSelf(currAccounts.map((t) => (t.id === account.id ? account : t)));
}
})
.catch((err) => toast.error(`error when fetching account: ${err}`));
};
ws.subscribe(
"account",
groupID,
(subscription_type, { account_id, element_id, revision_committed, revision_version }) => {
if (element_id === groupID) {
getPromise(node).then((currAccounts) => {
const currAccount = currAccounts.find((a) => a.id === account_id);
if (
currAccount === undefined ||
(revision_committed === null && revision_version > currAccount.version) ||
(revision_committed !== null &&
(currAccount.last_changed === null ||
DateTime.fromISO(revision_committed) >
DateTime.fromISO(currAccount.last_changed)))
) {
fetchAndUpdateAccount(currAccounts, account_id, currAccount === undefined);
}
});
}
}
);
// TODO: handle registration errors
return () => {
ws.unsubscribe("account", groupID);
};
},
],
})
Example #10
Source File: transactions.ts From abrechnung with GNU Affero General Public License v3.0 | 5 votes |
groupTransactions = atomFamily<Array<TransactionBackend>, number>({
key: "groupTransactions",
effects_UNSTABLE: (groupID) => [
({ setSelf, node, getPromise }) => {
const fullFetchPromise = () => {
return fetchTransactions({ groupID: groupID })
.then((result) => {
return result;
})
.catch((err) => {
toast.error(`error when fetching transactions: ${err}`);
return [];
});
};
// TODO: handle fetch error more properly than just showing error, e.g. through a retry or something
setSelf(fullFetchPromise());
const fetchAndUpdateTransaction = (
currTransactions: Array<TransactionBackend>,
transactionID: number,
isNew: boolean
) => {
fetchTransaction({ transactionID: transactionID })
.then((transaction) => {
if (isNew) {
setSelf([...currTransactions, transaction]);
} else {
setSelf(currTransactions.map((t) => (t.id === transaction.id ? transaction : t)));
}
})
.catch((err) => toast.error(`error when fetching transaction: ${err}`));
};
ws.subscribe(
"transaction",
groupID,
(
subscription_type,
{ element_id, transaction_id, revision_started, revision_committed, revision_version }
) => {
if (element_id === groupID) {
getPromise(node).then((currTransactions) => {
const currTransaction = currTransactions.find((t) => t.id === transaction_id);
if (
currTransaction === undefined ||
(revision_committed === null && revision_version > currTransaction.version) ||
(revision_committed !== null &&
(currTransaction.last_changed === null ||
DateTime.fromISO(revision_committed) >
DateTime.fromISO(currTransaction.last_changed)))
) {
fetchAndUpdateTransaction(
currTransactions,
transaction_id,
currTransaction === undefined
);
}
});
}
}
);
// TODO: handle registration errors
return () => {
ws.unsubscribe("transaction", groupID);
};
},
],
})
Example #11
Source File: transactions.ts From abrechnung with GNU Affero General Public License v3.0 | 5 votes |
pendingTransactionDetailChanges = atomFamily<LocalTransactionDetailChanges, number>({
// transaction id -> pending changes
key: "pendingTransactionDetailChanges",
default: {},
effects_UNSTABLE: (transactionID) => [localStorageEffect(`localTransactionChanges-${transactionID}`)],
})
Example #12
Source File: results.state.ts From nextclade with MIT License | 5 votes |
analysisResultInternalAtom = atomFamily<NextcladeResult, string>({
key: 'analysisResultSingle',
})
Example #13
Source File: index.spec.tsx From recoil-persist with MIT License | 4 votes |
function testPersistWith(storage: TestableStorage) {
describe(`Storage: ${storage.name}`, () => {
const testKey = 'test-key'
const { persistAtom } = recoilPersist({ key: testKey, storage })
const getStateValue = () => {
const value = storage.getState()[testKey]
if (value == undefined) {
return {}
}
return JSON.parse(value)
}
const getAtomKey = (key: string) => {
return `${storage.name}_${key}`
}
const counterState = atom({
key: getAtomKey('count'),
default: 0,
effects_UNSTABLE: [persistAtom],
})
const counterFamily = atomFamily({
key: getAtomKey('countFamily'),
default: 0,
effects_UNSTABLE: [persistAtom],
})
const counterState4 = atom({
key: getAtomKey('count4'),
default: 0,
})
function Demo() {
const [count, setCount] = useRecoilState(counterState)
const [count2, setCount2] = useRecoilState(counterFamily('2'))
const [count3, setCount3] = useRecoilState(counterFamily('3'))
const [count4, setCount4] = useRecoilState(counterState4)
const resetCounter3 = useResetRecoilState(counterFamily('3'))
const updateMultiple = useRecoilCallback(({ set }) => () => {
set(counterState, 10)
set(counterFamily('2'), 10)
})
return (
<div>
<p data-testid="count-value">{count}</p>
<p data-testid="count2-value">{count2}</p>
<p data-testid="count3-value">{count3}</p>
<p data-testid="count4-value">{count4}</p>
<button
data-testid="count-increase"
onClick={() => setCount(count + 1)}
>
Increase
</button>
<button
data-testid="count2-increase"
onClick={() => setCount2(count2 + 1)}
>
Increase 2
</button>
<button
data-testid="count3-increase"
onClick={() => setCount3(count3 + 1)}
>
Increase 3
</button>
<button
data-testid="count4-increase"
onClick={() => setCount4(count4 + 1)}
>
Increase 4
</button>
<button
data-testid="count3-null-value"
onClick={() => setCount3(null)}
>
Set value to null
</button>
<button
data-testid="count3-undefined-value"
onClick={() => setCount3(undefined)}
>
Set value to undefined
</button>
<button data-testid="count3-reset" onClick={() => resetCounter3()}>
Reset count 3
</button>
<button
data-testid="update-multiple"
onClick={() => updateMultiple()}
>
Update multiple
</button>
</div>
)
}
beforeEach(() => {
console.error = jest.fn()
})
afterEach(() => {
storage.clear()
jest.restoreAllMocks()
})
it('should be removed from storage on reset', async () => {
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('count3-increase'))
await waitFor(() =>
expect(getByTestId('count3-value').innerHTML).toBe('1'),
)
expect(getStateValue()).toStrictEqual({
[getAtomKey('countFamily__"3"')]: 1,
})
fireEvent.click(getByTestId('count3-reset'))
await waitFor(() =>
expect(getByTestId('count3-value').innerHTML).toBe('0'),
)
expect(getStateValue()).toStrictEqual({})
})
it('should handle reset atom with default value', async () => {
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('count3-reset'))
await waitFor(() =>
expect(getByTestId('count3-value').innerHTML).toBe('0'),
)
expect(getStateValue()).toStrictEqual({})
})
it('should update storage with null', async () => {
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('count3-null-value'))
await waitFor(() =>
expect(getByTestId('count3-value').innerHTML).toBe(''),
)
expect(getStateValue()).toStrictEqual({
[getAtomKey('countFamily__"3"')]: null,
})
})
it('should update storage with undefined', async () => {
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('count3-undefined-value'))
await waitFor(() =>
expect(getByTestId('count3-value').innerHTML).toBe(''),
)
expect(getStateValue()).toStrictEqual({})
})
it('should update storage', async () => {
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('count-increase'))
await waitFor(() =>
expect(getByTestId('count-value').innerHTML).toBe('1'),
)
expect(getStateValue()).toStrictEqual({
[getAtomKey('count')]: 1,
})
})
it('should update storage if using atomFamily', async () => {
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('count2-increase'))
await waitFor(() =>
expect(getByTestId('count2-value').innerHTML).toBe('1'),
)
fireEvent.click(getByTestId('count3-increase'))
await waitFor(() =>
expect(getByTestId('count3-value').innerHTML).toBe('1'),
)
expect(getStateValue()).toStrictEqual({
[getAtomKey('countFamily__"2"')]: 1,
[getAtomKey('countFamily__"3"')]: 1,
})
})
it('should not persist atom with no effect', async () => {
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('count4-increase'))
await waitFor(() =>
expect(getByTestId('count4-value').innerHTML).toBe('1'),
)
expect(storage.getState()[testKey]).toBeUndefined()
})
it('should read state from storage', async () => {
await storage.setItem(
testKey,
JSON.stringify({
[getAtomKey('count')]: 1,
[getAtomKey('countFamily__"2"')]: 1,
}),
)
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
await waitFor(() =>
expect(getByTestId('count-value').innerHTML).toBe('1'),
)
await waitFor(() =>
expect(getByTestId('count2-value').innerHTML).toBe('1'),
)
})
it('should use default value if not in storage', async () => {
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
expect(getByTestId('count3-value').innerHTML).toBe('0')
})
it('should handle non jsonable object in storage', async () => {
storage.setItem(testKey, 'test string')
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('count-increase'))
await waitFor(() =>
expect(getByTestId('count-value').innerHTML).toBe('1'),
)
expect(getStateValue()).toStrictEqual({
[getAtomKey('count')]: 1,
})
})
it('should handle non jsonable object in state', async () => {
let mock = jest.spyOn(JSON, 'stringify').mockImplementation(() => {
throw Error('mock error')
})
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('count-increase'))
await waitFor(() =>
expect(getByTestId('count-value').innerHTML).toBe('1'),
)
expect(mock).toHaveBeenCalledTimes(1)
expect(console.error).toHaveBeenCalledTimes(1)
})
it('should handle non-existent atom name stored in storage', async () => {
storage.setItem(
testKey,
JSON.stringify({
notExist: 'test value',
}),
)
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
await waitFor(() =>
expect(getByTestId('count-value').innerHTML).toBe('0'),
)
})
it.skip('should handle updating multiple atomes', async () => {
const { getByTestId } = render(
<RecoilRoot>
<Demo />
</RecoilRoot>,
)
fireEvent.click(getByTestId('update-multiple'))
await waitFor(() =>
expect(getByTestId('count-value').innerHTML).toBe('10'),
)
await waitFor(() =>
expect(getByTestId('count2-value').innerHTML).toBe('10'),
)
expect(getStateValue()).toStrictEqual({
[getAtomKey('count')]: 10,
[getAtomKey('countFamily__"2"')]: 10,
})
})
})
}