react-vmodel
v1.4.0
Published
a vue v-model like usage for react with ts prompt
Maintainers
Readme
react-vmodel
A vue v-model similar usage for react . Easy to access deep path with ts prompt.

Usage
Bind to Component
import { makeVModel, useVModel } from "react-vmodel";
export default function Demo() {
const [data, setData] = useState({
name: "example",
tasks: [{ id: 1, name: "test" }],
});
const vModel = makeVModel(data, setData);
//or define with hook
// const [vModel,data,setData]=useVModel({
// { name:'example',
// tasks:[{id:1,name:'test'}]
// }
// )
return (
<>
{/* All Bind with react-vmodel */}
<CustomComponent {...vModel()} />
{/* //--not with */}
<CustomComponent
value={data}
onChange={(e) => {
setData(e.target ? e.target.value : e);
}}
/>
{/* //Path Bind with react-vmodel */}
<CustomComponent2 {...vModel("tasks[0].name")} />
{/* //--not with */}
<CustomComponent2
value={data.tasks[0].name}
onChange={(e) => {
const clone = structuredClone(data);
clone.tasks[0].name = e.target ? e.target.value : e;
setData(clone);
}}
/>
</>
);
}Bind to input
Text
import { makeVModel } from "react-vmodel";
export default function Demo() {
const [text, setText] = useState("Hello World");
const vModel = makeVModel(text, setText);
return (
<>
<input {...vModel()}></input>
{/* //trim */}
<input {...vModel.trim()}></input>
{/* //number */}
<input type="number" {...vModel()}></input>
{/* //or */}
<input {...vModel.number()}></input>
</>
);
}Checkbox
True-False
import { makeVModel } from "react-vmodel";
export default function Demo() {
const [checked, setChecked] = useState(false);
const vModel = makeVModel(checked, setChecked);
return (
<>
{/* //true-false */}
<input type="checkbox" {...vModel.checked()}></input>
{/* //true 1 false 0 */}
<input
type="checkbox"
{...vModel.checked({ trueValue: 1, falseValue: 0 })}
></input>
</>
);
}CheckedList
import { makeVModel } from "react-vmodel";
export default function Demo() {
const [checkedList, setCheckedList] = useState([]);
const vModel = makeVModel(checkedList, setCheckedList);
return (
<>
{["one", "two", "three"].map((op) => (
<input
key={op}
type="checkbox"
{...vModel.checklist({ value: op })}
></input>
))}
</>
);
}Radio
import { makeVModel } from "react-vmodel";
export default function Demo() {
const [selected, setSelected] = useState("");
const vModel = makeVModel(selected, setSelected);
return (
<>
{["one", "two", "three"].map((op) => (
<input key={op} type="radio" {...vModel.checked({ value: op })}></input>
))}
</>
);
}Select
import { makeVModel } from "react-vmodel";
export default function Demo() {
const [selected, setSelected] = useState("");
const vModel = makeVModel(selected, setSelected);
return (
<>
{
<select {...vModel()}>
{["one", "two", "three"].map((op) => {
return (
<option key={op} value={op}>
{op}
</option>
);
})}
</select>
}
</>
);
}Advance Usage
import { makeVModel } from "react-vmodel";
export default function Demo() {
const [checked, setChecked] = useState(false);
const vModel = makeVModel(checked, setChecked);
return (
<>
{/* //true 1 false 0 */}
<input
type="checkbox"
{...vModel.checked({ trueValue: 1, falseValue: 0 })}
></input>
{/* custom the same function */}
<input
type="checkbox"
{...vModel((value, onChange) => ({
checked: value === 1,
value: String(value === 1),
onChange: (e) => onChange(e.target.checked ? 1 : 0),
}))}
/>
</>
);
}Component Model
import { Button, Form, Switch } from "antd";
import { Model } from "react-vmodel";
type FieldType = { status: number };
const initialValues = { status: 1 };
export default function Demo() {
return (
<Form onFinish={handleSubmit} initialValues={initialValues}>
<Form.Item name={"status"}>
<Model>
{(vModel) => (
<Switch
{...vModel.checked({ trueValue: 1, falseValue: 0 })}
></Switch>
)}
</Model>
</Form.Item>
</Form>
);
}Full Example
npx degit https://github.com/leafio/react-vmodel/examples react-vmodel-examplesVanilla Form
import { useEffect, useState } from "react";
import { makeVModel } from "react-vmodel";
export default function DemoVanilla() {
const [form, setForm] = useState({
name: "demo",
gender: "male",
hobbies: [],
job: {
id: 0,
year: 1,
},
projects: [
{
name: "First",
isFinished: 1,
},
{
name: "Last",
isFinished: 0,
},
],
});
const vModel = makeVModel(form, setForm);
useEffect(() => {
console.log(form);
});
return (
<form className="flex flex-col ">
<label className="mb-1">
<span className="w-24 inline-block">Name:</span>
<input type="text" className=" border" {...vModel("name")} />
</label>
<div className="mb-1">
<span className="w-24 inline-block">Gender:</span>
<label>
Male
<input
type="radio"
className=" border"
{...vModel.checked("gender", { value: "male" })}
/>
</label>
<label>
Female
<input
type="radio"
className=" border"
{...vModel.checked("gender", { value: "female" })}
/>
</label>
</div>
<label className="mb-1">
<span className="w-24 inline-block">Hobbies:</span>
{hobbyOptions.map((h) => (
<label key={h}>
{h}
<input
type="checkbox"
className=" border"
{...vModel.checklist("hobbies", { value: h })}
/>
</label>
))}
</label>
<label className="mb-1">
<span className="w-24 inline-block">Job:</span>
<select {...vModel.number("job.id")}>
{jobOptions.map((job) => {
return (
<option key={job.value} value={job.value}>
{job.label}
</option>
);
})}
</select>
</label>
<label className="mb-1">
<span className="w-24 inline-block">Experience:</span>
<input type="number" className=" border" {...vModel("job.year")} />
</label>
<div className="mb-1">
<span className="w-24 inline-block">Projects:</span>
{form.projects.map((p, index) => (
<label key={p.name}>
<span>{p.name}</span>
<input
type="checkbox"
{...vModel.checked(`projects[${index}].isFinished`, {
trueValue: 1,
falseValue: 0,
})}
/>
</label>
))}
</div>
</form>
);
}
const hobbyOptions = ["film", "sports", "music"];
const jobOptions = [
{
label: "Front End Developer",
value: 0,
},
{
label: "Back End Developer",
value: 1,
},
{
label: "Test Engineer",
value: 2,
},
];Ant Design
import {
Checkbox,
Form,
Input,
InputNumber,
Radio,
Select,
Switch,
} from "antd";
import { useEffect, useState } from "react";
import { makeVModel } from "react-vmodel";
export default function DemoAntd() {
const [form, setForm] = useState({
name: "demo",
join: "yes",
gender: "male",
hobbies: [],
job: {
id: 0,
year: 1,
},
projects: [
{
name: "First",
isFinished: 1,
},
{
name: "Last",
isFinished: 0,
},
],
});
const vModel = makeVModel(form, setForm);
useEffect(() => {
console.log(form);
});
return (
<Form className="flex flex-col " labelCol={{ span: 4 }} labelAlign="left">
<Form.Item label="Name:">
<Input type="text" {...vModel("name")} />
</Form.Item>
<Form.Item label="Join:">
<Switch
{...vModel.checked("join", {
trueValue: "yes",
falseValue: "no",
})}
/>
</Form.Item>
<div className="mb-1">
<Form.Item label="Gender:">
<Radio {...vModel.checked("gender", { value: "male" })}>Male</Radio>
<Radio {...vModel.checked("gender", { value: "female" })}>
Female
</Radio>
</Form.Item>
</div>
<Form.Item label="Hobbies">
{hobbyOptions.map((h) => (
<Checkbox key={h} {...vModel.checklist("hobbies", { value: h })}>
{h}
</Checkbox>
))}
</Form.Item>
<Form.Item label="Job">
<Select {...vModel.number("job.id")} options={jobOptions} />
</Form.Item>
<Form.Item label="Experience">
<InputNumber {...vModel("job.year")} />
</Form.Item>
<Form.Item label="Projects">
{form.projects.map((p, index) => (
<Checkbox
key={p.name}
{...vModel.checked(`projects[${index}].isFinished`, {
trueValue: 1,
falseValue: 0,
})}
>
{p.name}{" "}
</Checkbox>
))}
</Form.Item>
</Form>
);
}
const hobbyOptions = ["film", "sports", "music"];
const jobOptions = [
{
label: "Front End Developer",
value: 0,
},
{
label: "Back End Developer",
value: 1,
},
{
label: "Test Engineer",
value: 2,
},
];Material UI
import {
Checkbox,
FormControl,
FormControlLabel,
FormLabel,
Input,
MenuItem,
Radio,
Select,
Switch,
} from "@mui/material";
import { useEffect, useState } from "react";
import { makeVModel } from "react-vmodel";
export default function DemoMui() {
const [form, setForm] = useState({
name: "demo",
join: "yes",
gender: "male",
hobbies: [],
job: {
id: 0,
year: 1,
},
projects: [
{
name: "First",
isFinished: 1,
},
{
name: "Last",
isFinished: 0,
},
],
});
const vModel = makeVModel(form, setForm);
useEffect(() => {
console.log(form);
});
return (
<form className="flex flex-col ">
<FormControl>
<FormLabel>Name:</FormLabel>
<Input type="text" {...vModel("name")} />
</FormControl>
<FormControl>
<FormLabel>Join:</FormLabel>
<Switch
{...vModel.checked("join", {
trueValue: "yes",
falseValue: "no",
})}
/>
</FormControl>
<FormControl>
<FormLabel>Gender:</FormLabel>
<div className="flex">
<FormControlLabel
label={"Male"}
control={
<Radio
{...vModel.checked("gender", {
value: "male",
})}
/>
}
/>
<FormControlLabel
label={"Female"}
control={
<Radio
{...vModel.checked("gender", {
value: "female",
})}
/>
}
/>
</div>
</FormControl>
<FormControl>
<FormLabel>Hobbies:</FormLabel>
<div className="flex">
{hobbyOptions.map((h) => (
<FormControlLabel
key={h}
label={h}
control={
<Checkbox
{...vModel.checklist("hobbies", {
value: h,
})}
/>
}
/>
))}
</div>
</FormControl>
<FormControl>
<FormLabel>Job:</FormLabel>
<Select {...vModel.number("job.id")}>
{jobOptions.map((job) => {
return (
<MenuItem key={job.value} value={job.value}>
{job.label}
</MenuItem>
);
})}
</Select>
</FormControl>
<FormControl>
<FormLabel>Experience:</FormLabel>
<Input type="number" {...vModel("job.year")} />
</FormControl>
<FormControl>
<FormLabel>Projects:</FormLabel>
<div className="flex">
{form.projects.map((p, index) => (
<FormControlLabel
key={p.name}
label={p.name}
control={
<Checkbox
{...vModel.checked(`projects[${index}].isFinished`, {
trueValue: 1,
falseValue: 0,
})}
/>
}
/>
))}
</div>
</FormControl>
</form>
);
}
const hobbyOptions = ["film", "sports", "music"];
const jobOptions = [
{
label: "Front End Developer",
value: 0,
},
{
label: "Back End Developer",
value: 1,
},
{
label: "Test Engineer",
value: 2,
},
];Installation
npm install react-vmodel