dpm
dpm
TTCTheo's Typesafe Cult
Created by dpm on 2/18/2024 in #questions
What's the idiomatic way to enable/disable a button based on Zod results?
Hi, New to React, not really a frontend developer. I want to disable my button if my Zod schema doesn't like the field value. Ideally without adding a redundant useState to track whether the field is valid. In the example below, I can use disabled = (nextItem === ''), but that pattern won't scale to more complex validations (I assume). I'm used to rxjs from Angular-land, I assume there's a reactive approach here as well. Or am I totally off-base?
function RapidEntryList () {
const [items, setItems] = useState([] as string[]);
const [nextItem, setNextItem] = useState<string>('');

function addItem(item: string): () => boolean {
return () => {
const copy = items.slice();
copy.push(item);
setItems(copy);
return false;
}
}

function inputChange(newValue: string) {
const result = itemName.safeParse(newValue);
setNextItem(result.success ? result.data : '');
}

const itemName: ZodString = z.string().trim().min(1).max(maxTaskNameLength);


return (<div>
<div className="join join-vertical">
{items.map((str, i) => <p key={i} className="join-item">{str}</p>)}
</div>
<input type="text" onChange={e => inputChange(e.target.value)}
placeholder="Start entering your items" className="input w-full max-w-xs"/>
<button className="btn" disabled={/* what goes here??? */false} onClick={addItem(nextItem)}>Add</button>
</div>)
}
function RapidEntryList () {
const [items, setItems] = useState([] as string[]);
const [nextItem, setNextItem] = useState<string>('');

function addItem(item: string): () => boolean {
return () => {
const copy = items.slice();
copy.push(item);
setItems(copy);
return false;
}
}

function inputChange(newValue: string) {
const result = itemName.safeParse(newValue);
setNextItem(result.success ? result.data : '');
}

const itemName: ZodString = z.string().trim().min(1).max(maxTaskNameLength);


return (<div>
<div className="join join-vertical">
{items.map((str, i) => <p key={i} className="join-item">{str}</p>)}
</div>
<input type="text" onChange={e => inputChange(e.target.value)}
placeholder="Start entering your items" className="input w-full max-w-xs"/>
<button className="btn" disabled={/* what goes here??? */false} onClick={addItem(nextItem)}>Add</button>
</div>)
}
1 replies