亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

react表單受控的實(shí)現(xiàn)方案

 更新時(shí)間:2023年12月08日 08:36:13   作者:九七97  
數(shù)據(jù)的受控控制一直是react里的一個(gè)痛點(diǎn),當(dāng)我想要實(shí)現(xiàn)一個(gè)輸入框的受控控制時(shí),我需要定義一個(gè)onChange和value,手動(dòng)去實(shí)現(xiàn)數(shù)據(jù)的綁定,本文小編給大家介紹了react表單受控的實(shí)現(xiàn)方案,需要的朋友可以參考下

背景

數(shù)據(jù)的受控控制一直是react里的一個(gè)痛點(diǎn),當(dāng)我想要實(shí)現(xiàn)一個(gè)輸入框的受控控制時(shí),我需要定義一個(gè)onChangevalue,手動(dòng)去實(shí)現(xiàn)數(shù)據(jù)的綁定。當(dāng)受控的元素一多,便會(huì)出現(xiàn)滿屏的set。

筆者所在的公司業(yè)務(wù)比較大,偏向于后臺(tái)管理的sass系統(tǒng),用戶群體比較大,其中就包括有谷歌這些用戶。自然迭代更新速度也比較快,而隨著不斷的迭代更新,項(xiàng)目也是日益龐大。在日常需求中,表單的開發(fā)就占據(jù)了大部分場景,而在用react開發(fā)表單這塊,特別是當(dāng)表單字段過于復(fù)雜,表單過于龐大時(shí),開發(fā)受控表單也要投入不小的開發(fā)生產(chǎn)力和不少的受控代碼,不說優(yōu)雅和后期的維護(hù),對(duì)于頁面響應(yīng)速度來說,也是會(huì)隨著字段的增加而變的越來越慢,即使拆分成顆粒度最小的組件。

在一個(gè)表單業(yè)務(wù)中,字段A依賴于字段B,字段C又依賴于字段A的變化,而字段C追蹤依賴后又要實(shí)時(shí)渲染在視圖里。這是很常見的需求場景,當(dāng)組織這些依賴的時(shí)候,隨之而來的考慮的是一個(gè)性能問題,我們很常見的一個(gè)做法便是狀態(tài)的提升,將它們都放到頂層容器中,統(tǒng)一管理。但是這樣會(huì)隨著依賴的不斷增加,而造成當(dāng)前渲染的樹不斷渲染,當(dāng)越來越多的字段沉積,不斷的重新渲染,直到最后頁面奔潰,內(nèi)存溢出。

當(dāng)這種做法產(chǎn)生了較大的副作用后,我們這時(shí)候會(huì)開始考慮改變做法,優(yōu)化代碼,考慮在各自的組件中定義onchangevalue維護(hù)這個(gè)字段,然后在注入到全局狀態(tài)管理中,在需要用到的組件中訂閱這個(gè)字段,這樣就減少了重復(fù)渲染的次數(shù)。

在這個(gè)過程中,我們通常需要定義一系列受控代碼,以達(dá)到我們的預(yù)期。

第三方庫

當(dāng)然,如果在使用第三方UI庫的時(shí)候,通常會(huì)提供Form組件,比如antd。而 antd的Form強(qiáng)依賴于它本身的表單控件,而且對(duì)于定義一個(gè)表單而言,所定義的受控邏輯略微繁瑣。表單業(yè)務(wù)復(fù)雜時(shí),需要傳入一系列的prop和方法。當(dāng)需要與別的UI結(jié)合的時(shí)候,F(xiàn)orm組件就失去了他的意義。

筆者之前所用的是react-hook-form,react-hook-form能夠輕易集成第三方UI,同樣的,對(duì)于數(shù)據(jù)受控以及數(shù)據(jù)訂閱方面,rect-hook-form需要定義的代碼同樣不少,比如使一個(gè)表單項(xiàng)受控,需要顯示引入它的Controller組件包裹。比如需要一個(gè)狀態(tài)去實(shí)時(shí)反應(yīng)到表單之外的視圖的時(shí)候,要另外定義一個(gè)變量結(jié)合它的react-hook-form的watch去維護(hù)這個(gè)變量的狀態(tài)。

而其實(shí)在開發(fā)過程中,我們并不想要關(guān)心這種受控過程,只想要知道受控的結(jié)果和應(yīng)用受控狀態(tài)。當(dāng)定義好一套表單模型數(shù)據(jù)時(shí),并將這套模型與他對(duì)應(yīng)的表單項(xiàng)視圖關(guān)聯(lián)起來的時(shí)候,它們之間應(yīng)該自動(dòng)建立起一個(gè)受控的橋梁和紐帶,開發(fā)者不需要知道這個(gè)橋梁是怎么建立的,不需要去維護(hù)這個(gè)橋梁,開發(fā)者需要做的,就是去應(yīng)用這套模型。而這套模型,永遠(yuǎn)是最新的。并且不影響到它們外部的其他元素。

React-form-simple

react-form-simple是一個(gè)基于react的可受控可擴(kuò)展的輕量級(jí)表單庫,以最快的速度以及最精簡的代碼渲染出一個(gè)可受控的表單。React-form-simple除了集成自身功能之外,還具有非??蓴U(kuò)展的接口, 并可與第三方ui集成使用。

react-hook-form 啟發(fā), 得源于 react-hook-form 的設(shè)計(jì)靈感,筆者所在團(tuán)隊(duì)花費(fèi)了兩個(gè)月時(shí)間梳理了項(xiàng)目的全部表單,綜合整理并開發(fā)出了一款輕量級(jí)表單庫。該庫已重寫了項(xiàng)目的大部分表單,并已在生產(chǎn)環(huán)境中使用了大半年之久。

react-form-simple 基于 es6Proxy 創(chuàng)建一個(gè)可觀察的表單模型對(duì)象,該庫有如下特點(diǎn):

  • 通過創(chuàng)建一個(gè)可觀察對(duì)象來觀察表單的模型操作, 表單項(xiàng)的受控直接通過_. 賦值。

  • 簡單幾行代碼就可以完成表單受控, 無需關(guān)心受控邏輯, 無需關(guān)心受控過程, 只需要知道受控結(jié)果和如何應(yīng)用你的受控狀態(tài)。

  • 每個(gè)表單項(xiàng)之間的渲染自動(dòng)完全隔離, 不需要自行組織組件隔離。這將能夠更快的處理表單輸入后的響應(yīng)速度, 以及很大程度的避免在大型動(dòng)態(tài)數(shù)據(jù)下造成的頁面卡頓。

  • 具有數(shù)據(jù)觀測功能, 可以在某些場景下對(duì)整個(gè)表單或者某個(gè)具體的表單項(xiàng)進(jìn)行單一或者統(tǒng)一的觀察監(jiān)測, 可以在你需要用表單項(xiàng)最新的值進(jìn)行渲染的地方進(jìn)行值的訂閱。

  • 靈活的使用方式, 靈活的頁面布局組合, 開發(fā)者可以根據(jù)自己的喜好和場景使用某種方式以及內(nèi)置布局。在大多數(shù)場景下, 無需開發(fā)者手動(dòng)布局。

  • 簡約的 API 設(shè)計(jì), 在操作表單的過程中, 簡單的只需要引入兩個(gè) API, 就可以完成大部分工作。

  • 高度可擴(kuò)展的表單接口, 在一些復(fù)雜需求或者定制化場景中, 開發(fā)者可以自行定制表單的控制邏輯。

  • 可以輕易集成在你的 UI 或者 第三方庫中。

  • 完整的類型推斷。

單元測試覆蓋

使用

npm install react-form-simple -S

簡化表單受控

react-form-simple 暴露出一個(gè) render 方法,在一般情況下, 傳入表單模型字段和渲染視圖,便能搭建它們之間的受控橋梁。

import React, { useEffect } from 'react';
import { useForm } from 'react-form-simple';

export default function App() {
  const { render, model } = useForm({ name: '' });
  const renderName = render('name')(<input  />);
  const onSubmit = () => void console.log(model);
  return (
    <>
      {renderName}
      <button onClick={onsubmit}>submit</button>
    </>
  );
}

如上例子,創(chuàng)建一個(gè)受控表單只需要兩行代碼。

  • 通過useForm創(chuàng)建一個(gè)表單數(shù)據(jù)模型。
  • 使用useForm暴露出的render方法創(chuàng)建表單項(xiàng)與渲染視圖的受控橋梁。

開發(fā)者不需要知道name字段與input的受控過程,不需要關(guān)心他們是如何受控的,開發(fā)者需要做的,就是將model 模型數(shù)據(jù)如何運(yùn)用在代碼中。更多用法請(qǐng)查看文檔

而在name字段與 input 視圖受控時(shí),它們之間的變化不會(huì)重新導(dǎo)致外部的任何重復(fù)渲染。也就是說,表單的渲染都是完全相互隔離的。

訂閱最新值

在一個(gè)表單開發(fā)中,通常有A字段依賴于B字段的場景,比如在B字段的值發(fā)生改變后,A字段需要做相應(yīng)的邏輯處理,并將A字段的值實(shí)時(shí)渲染在視圖里。

react-form-simple 里,表單項(xiàng)的受控并不能直接引起外部視圖的刷新,可以借助 useSubscribe 來訂閱某個(gè)字段或者整個(gè)表單,以將它渲染在表單視圖之外。

import React from 'react';
import { useForm } from 'react-form-simple';

export default function App() {
  const { render, useSubscribe } = useForm({ name: 'name' });

  const renderName = render('name')(<input />);

  const subscribeName = useSubscribe(({ model }) => model.name);

  console.log({ subscribeName });

  return (
    <>
      {renderName}
    </>
  );
}

如上所示,在 name 發(fā)生變化的時(shí)候,subscribeName 便會(huì)實(shí)時(shí)打印。

但是一般不推薦在父級(jí)組件中來訂閱, 因?yàn)檫@會(huì)引起整個(gè)渲染樹的更新, 推薦的做法是只用在需要訂閱的地方, 可以通過 props 透傳, 也可以將它注入到全局狀態(tài)管理中。

下面這個(gè)例子展示的是有兩個(gè)輸入框,當(dāng)其中一個(gè)輸入框的值等于 amount 的時(shí)候,便顯示另外一個(gè)輸入框。

import { useForm } from "react-form-simple";
export default function App() {
  const { render, useSubscribe } = useForm({ name: "", amount: "" });
  const renderName = render("name")(<input />);
  const nameValue = useSubscribe(({ model }) => model.name);
  const renderAmount = nameValue === "amount" && render("amount")(<input />);

  return (
    <>
      {renderAmount}
      {renderName}
    </>
  );
}

watch監(jiān)聽

react-form-simple 提供數(shù)據(jù)觀測功能,使用 useWatch 可以觀察某個(gè)字段或者整個(gè)表單的變化。

import { useForm } from 'react-form-simple';

export default function App() {
  const { render, useWatch } = useForm({ name: 'name', age: 'age' });

  const renderName = render('name')(<input className="input" />);
  const renderAge = render('age')(<input className="input" />);

  useWatch(
    ({ model }) => [model?.name, model?.age],
    (value, preValue) => {
      console.log({ value, preValue });
    },
  );

  return (
    <>
      {renderName}
      {renderAge}
    </>
  );
}

表單校驗(yàn)

通過 useForm 暴露出的 validate 方法可以快速的對(duì)表單模型進(jìn)行校驗(yàn)。

import Button from '@components/Button';
import React from 'react';
import { useForm } from 'react-form-simple';

export default function App() {
  const { render, validate, model, clearValidate, setError } = useForm({
    name: '',
    age: '',
  });

  const renderName = render('name', {
    rules: { required: 'Please Input' },
    requireIndicator: true,
    label: 'name',
  })(<input className="input" />);

  const renderAge = render('age', {
    label: 'age',
    rules: [
      { required: 'Please Input' },
      {
        validator(value) {
          if (value < 10) {
            return 'Min 10';
          }
          return '';
        },
      },
    ],
  })(<input className="input" />);

  const renderSubmit = (
    <Button
      onClick={async () => {
        await validate();
        console.log(model);
      }}
    >
      Submit
    </Button>
  );

  const renderclear = (
    <Button
      onClick={async () => {
        clearValidate();
      }}
    >
      clear
    </Button>
  );

  return (
    <>
      {renderName}
      {renderAge}
      {renderSubmit}
      {renderclear}
    </>
  );
}

集成第三方UI

在實(shí)際項(xiàng)目中,我們通常需要用到第三方UI來渲染視圖,rect-form-simple 可以很輕易的與這些UI庫集成在一起,無論什么UI庫。

下面的例子是集成 antd 的例子。

import Button from '@components/Button';
import { Checkbox, Input, Select } from 'antd';
import React from 'react';
import { useForm } from 'react-form-simple';

export default function App() {
  const { render, model, validate } = useForm(
    { name: '', select: 'jack', checkbox: true },
    { labelPosition: 'top' },
  );
  const renderName = render('name', {
    label: 'name',
    rules: { required: 'please Input' },
    requireIndicator: true,
    defineProps(options) {
      return { status: options.isError ? 'error' : '' };
    },
  })(<Input style={{ width: '300px' }} placeholder="Please Input" />);

  const renderSelect = render('select', {
    label: 'age',
    formatChangeValue: (e) => e,
  })(
    <Select
      options={[
        { value: 'jack', label: 'Jack' },
        { value: 'lucy', label: 'Lucy' },
        { value: 'Yiminghe', label: 'yiminghe' },
      ]}
      style={{ width: '300px' }}
    />,
  );

  const renderCheckbox = render('checkbox', {
    label: 'Checkbox',
    labelPosition: 'row',
  })(<Checkbox />);

  const renderSubmit = (
    <Button
      onClick={async () => {
        await validate();
        console.log(model);
      }}
    >
      Submit
    </Button>
  );

  return (
    <>
      {renderName}
      {renderSelect}
      {renderCheckbox}
      <div>{renderSubmit}</div>
    </>
  );
}

無論開發(fā)者使用的什么UI庫,react-form-simple 都可以很好的與它們集成在一起。

組件形式

在開發(fā)者使用的習(xí)慣上,可能有些開發(fā)人員習(xí)慣于以組件的形式來渲染視圖,這可以更加直觀的組織代碼。 react-form-simple 暴露出了兩個(gè)組件 FormFormItem 來提供給開發(fā)人員使用組件形式來創(chuàng)建表單。在需要定制化表單,或者處理一些額外的邏輯的時(shí)候,這兩個(gè)組件將非常有用。

開發(fā)者可以基于此來封裝適合自己使用習(xí)慣的 useForm,以此來定制化的開發(fā)人員的表單hook。

使用 FormItem 例子,關(guān)于更多介紹請(qǐng)查看FormItem

import Button from '@components/Button';
import React from 'react';
import { FormItem, useForm } from 'react-form-simple';

export default function App() {
  const { contextProps, model, validate } = useForm({
    name: '',
    age: 'age',
  });

  return (
    <>
      <FormItem
        defaultValue={model.name}
        rules={{ required: 'Please Input' }}
        bindId="name"
        getContent={({ attrs }) => <input {...attrs} className="input" />}
        contextProps={contextProps}
      />
      <FormItem
        defaultValue={model.age}
        rules={{ required: 'Please Select' }}
        bindId="age"
        getContent={({ attrs }) => {
          return (
            <select {...attrs}>
              <option value="name">name</option>
              <option value="age">age</option>
              <option value="email">email</option>
            </select>
          );
        }}
        contextProps={contextProps}
      />

      <Button
        onClick={async () => {
          await validate();
          console.log(model);
        }}
      >
        Submit
      </Button>
    </>
  );
}

定制化表單

開發(fā)者可以傳入一個(gè)普通的表單對(duì)象完全自定義表單的受控邏輯來定制化表單,而無需依賴于 useForm hook。

import Button from '@components/Button';
import React, { useEffect, useRef } from 'react';
import {
  Form,
  FormItem,
  type ContextProps,
  type FormApis,
} from 'react-form-simple';
export default function App() {
  const formRef = useRef<FormApis>(null);
  const model = useRef({
    name: '',
  }) as any;
  const contextProps = useRef<ContextProps>({
    updated({ bindId, value }) {
      model.current[bindId] = value;
    },
    reset({ bindId }) {
      model.current[bindId] = '';
      formRef.current?.setValue(bindId, '');
    },
  });
  useEffect(() => {
    const values = { name: 'name' };
    model.current = values;
    formRef.current?.setValues(values);
  }, []);
  const renderName = (
    <FormItem
      bindId="name"
      rules={{ required: 'Please Input' }}
      label="name"
      getContent={({ attrs }) => {
        return (
          <input placeholder="Please Input" {...attrs} className="input" />
        );
      }}
    />
  );
 

  return (
    <Form
      ref={formRef}
      contextProps={contextProps.current}
      direction="column"
      labelWidth="40px"
    >
      {renderName}
      <FormItem label=" ">
        <Button
          onClick={() => {
            console.log(model.current);
          }}
        >
          submit
        </Button>

        <Button
          style={{ marginLeft: '15px' }}
          plain
          onClick={() => {
            formRef.current?.reset();
          }}
        >
          reset
        </Button>
      </FormItem>
    </Form>
  );
}

關(guān)于更多定制化表單,請(qǐng)查看定制化表單

文檔地址

結(jié)語

本文簡單的探討了react表單的受控實(shí)現(xiàn)方案以及react-form-simple的使用,構(gòu)建可維護(hù)的代碼。以及在新技術(shù)領(lǐng)域保持學(xué)習(xí)的動(dòng)力。通過這些話題,我們不僅僅是在談?wù)摯a本身,更是在談?wù)撘环N持續(xù)的挑戰(zhàn)與成長的過程。

在編碼的旅程中,我們常常會(huì)面臨新的問題,需要找到創(chuàng)新的解決方案。正是通過解決這些挑戰(zhàn),我們才能不斷提升自己的技能,并在技術(shù)的海洋中航行得更遠(yuǎn)。每一行代碼都是一次思考的結(jié)果,每一個(gè)問題都是一次成長的機(jī)會(huì)。

在未來的代碼之旅中,愿我們能夠保持對(duì)技術(shù)的熱愛,持續(xù)學(xué)習(xí),不斷挑戰(zhàn)自己。編碼不僅僅是一項(xiàng)技能,更是一場不斷演化的冒險(xiǎn)。感謝你閱讀本文,期待與你在下一篇文章中再次相遇。

以上就是react表單受控的實(shí)現(xiàn)方案的詳細(xì)內(nèi)容,更多關(guān)于react表單受控的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React使用公共文件夾public問題

    React使用公共文件夾public問題

    這篇文章主要介紹了React使用公共文件夾public問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 詳解React Native 采用Fetch方式發(fā)送跨域POST請(qǐng)求

    詳解React Native 采用Fetch方式發(fā)送跨域POST請(qǐng)求

    這篇文章主要介紹了詳解React Native 采用Fetch方式發(fā)送跨域POST請(qǐng)求,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • 關(guān)于?React?中?useEffect?使用問題淺談

    關(guān)于?React?中?useEffect?使用問題淺談

    本文主要介紹了關(guān)于React中useEffect使用問題淺談,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • React中常見的TypeScript定義實(shí)戰(zhàn)教程

    React中常見的TypeScript定義實(shí)戰(zhàn)教程

    這篇文章主要介紹了React中常見的TypeScript定義實(shí)戰(zhàn),本文介紹了Fiber結(jié)構(gòu),F(xiàn)iber的生成過程,調(diào)和過程,以及 render 和 commit 兩大階段,需要的朋友可以參考下
    2022-10-10
  • React中引入less、less-loader問題

    React中引入less、less-loader問題

    這篇文章主要介紹了React中引入less、less-loader問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • react中使用ant組件庫的modal彈窗報(bào)錯(cuò)問題及解決

    react中使用ant組件庫的modal彈窗報(bào)錯(cuò)問題及解決

    這篇文章主要介紹了react中使用ant組件庫的modal彈窗報(bào)錯(cuò)問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • React函數(shù)式組件Hook中的useEffect函數(shù)的詳細(xì)解析

    React函數(shù)式組件Hook中的useEffect函數(shù)的詳細(xì)解析

    useEffect是react v16.8新引入的特性。我們可以把useEffect hook看作是componentDidMount、componentDidUpdate、componentWillUnmounrt三個(gè)函數(shù)的組合
    2022-10-10
  • 詳解React??App.js?文件的結(jié)構(gòu)和作用

    詳解React??App.js?文件的結(jié)構(gòu)和作用

    在React應(yīng)用中,App.js文件通常是項(xiàng)目的根組件文件,它負(fù)責(zé)組織和渲染其他組件,是應(yīng)用的核心部分,本文將詳細(xì)介紹App.js文件的結(jié)構(gòu)、作用和最佳實(shí)踐,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • react解析html字符串方法實(shí)現(xiàn)

    react解析html字符串方法實(shí)現(xiàn)

    在使用reactjs庫的時(shí)候,會(huì)遇到將一段html的字符串,然后要將它插入頁面中以html的形式展現(xiàn),本文主要介紹了react解析html字符串方法實(shí)現(xiàn),感興趣的可以了解一下
    2023-12-12
  • React中代碼分割的4種實(shí)現(xiàn)方式

    React中代碼分割的4種實(shí)現(xiàn)方式

    雖然一直有做react相關(guān)的優(yōu)化,按需加載、dll 分離、服務(wù)端渲染,但是從來沒有從路由代碼分割這一塊入手過,所以下面這篇文章主要給大家介紹了關(guān)于React中代碼分割的4種實(shí)現(xiàn)方式,需要的朋友可以參考下
    2022-01-01

最新評(píng)論