import { useActionState } from "react";
async function addToCart(itemId) {
'use server'
if (db.add(itemId)) {
return "success"
[ | |
{ | |
"key": "ctrl+k", | |
"command": "editor.action.moveLinesUpAction", | |
"when": "editorTextFocus && !editorReadonly" | |
}, | |
{ | |
"key": "alt+up", | |
"command": "-editor.action.moveLinesUpAction", | |
"when": "editorTextFocus && !editorReadonly" |
{ | |
"diffEditor.renderSideBySide": true, | |
"editor.fontSize": 14, | |
"editor.lineHeight": 22, | |
"editor.tabSize": 2, | |
"editor.matchBrackets": "never", | |
"editor.cursorBlinking": "solid", | |
"editor.selectionHighlight": false, | |
"editor.occurrencesHighlight": "off", | |
"editor.scrollbar.horizontal": "hidden", |
diff --git a/app/components/entry-form.tsx b/app/components/entry-form.tsx | |
index 50e5aeb..84c64fc 100644 | |
--- a/app/components/entry-form.tsx | |
+++ b/app/components/entry-form.tsx | |
@@ -1,6 +1,6 @@ | |
-import { useFetcher } from "@remix-run/react"; | |
+import { Form, useSubmit } from "@remix-run/react"; | |
import { format } from "date-fns"; | |
-import { useEffect, useRef } from "react"; | |
+import { useRef } from "react"; |
{ | |
"workbench.colorCustomizations": { | |
"editor.background": "#0f172a", | |
"menu.background": "#0f172a", | |
"sideBar.background": "#0b111e", | |
"banner.background": "#0f172a", | |
"tab.inactiveBackground": "#0b111e", | |
"tab.activeBackground": "#0f172a", | |
"titleBar.activeBackground": "#0b111e", | |
"editor.lineHighlightBorder": "#ff000000" |
import { motion } from "framer-motion"; | |
import { FormEvent, useState } from "react"; | |
import { createGlobalState } from "react-hooks-global-state"; | |
const { useGlobalState } = createGlobalState({ | |
enabled: false, | |
delay: 1000, | |
}); |
{ | |
"Use state": { | |
"scope": "javascriptreact,typescriptreact", | |
"prefix": "ush", | |
"body": [ | |
"let [${1}, set${1/(.*)/${1:/capitalize}/}] = useState($2);", | |
], | |
"description": "useState()" | |
} | |
} |
{ | |
"Range of numbers": { | |
"scope": "javascriptreact,typescriptreact", | |
"prefix": "range", | |
"body": [ | |
"{[...Array($1).keys()].map((i) => (", | |
" <$2 key={i}>", | |
" $3", | |
" </$2>", | |
"))}", |
Remix's useFetcher
doesn't return a Promise for any of its methods (like fetcher.submit()
) because Remix doesn't want you to explicitly await
anything so they can handle things like cancellation for you. Instead, they recommend adding a useEffect
and performing whatever logic you need to after the fetcher is in a particular state.
I found using an effect to run some logic after a submission to be too indirect, and there seem to be plenty of cases where you want to submit a form and then perform some other work on the client (sometimes async, like requesting the user's permission for their location), and I'd rather just do that after a submission in the event handler rather than an effect.
So here's a proof of concept hook that wraps Remix's useFetcher
and returns a version of submit
that is a promise, and resolves with the data from the action:
function useFetcherWithPromise() {
let resolveRef = useRef();
let promiseRef = useRef();
import * as d3 from "d3"; | |
import { | |
eachMonthOfInterval, | |
endOfMonth, | |
format, | |
isSameMonth, | |
parseISO, | |
startOfMonth, | |
} from "date-fns"; | |
import useMeasure from "react-use-measure"; |