UNPKG

react-vmodel

Version:

a vue v-model like usage for react with ts prompt

637 lines (588 loc) 14.8 kB
# react-vmodel A vue v-model similar usage for react . Easy to access deep path with ts prompt. ![](https://raw.githubusercontent.com/leafio/react-vmodel/main/img.png "img.png") > - react-vmodel ^1.3 for React ^19 > - react-vmodel ^0.3 for React ^18 <!-- ![](img.png "img.png") --> - [Usage](#usage) - [Bind to Component](#bind-to-component) - [Bind to input](#bind-to-input) - [Text](#text) - [Checkbox](#checkbox) - [True-False](#true-false) - [CheckedList](#checkedlist) - [Radio](#radio) - [Select](#select) - [Advance Usage](#advance-usage) - [Full Example](#full-example) - [Vanilla Form](#vanilla-form) - [Ant Design](#ant-design) - [Material UI](#material-ui) - [Installation](#installation) ### Usage #### Bind to Component ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 ```bash npx degit https://github.com/leafio/react-vmodel/examples react-vmodel-examples ``` #### Vanilla Form ```tsx 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 ```tsx 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 ```tsx 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 ```bash npm install react-vmodel ```