根據產品需求迭代出來的一個簡單好用的React-Input組件

這篇文章會包含以下幾個小知識點:html

  • 如何編寫一個debounce input.
  • 如何發佈一個React組件到npm.
  • 思考如何在業務中提升本身.(這純是我在吹NB,O(∩_∩)O哈哈~)

react-best-input

這年代都講究個專利註冊,一個好聽的名字真的比什麼都重要,原諒我臭不要臉的把best這個名字提早佔有了!真的是先下手爲強啊。^_^ react-best-input通過gzip後大概在6KB左右,因爲我的能力有限,代碼質量應該還能夠提升,陸續會改進代碼質量,爭取控制的更精簡,並且這些功能都很容易實現,主要想說的是這個過程。下面是這個input組件的Demo,目前暫時支持以下幾個功能:

  • 繼承了普通input的屬性,使用的時候就當成是普通的input標籤加強版就能夠了。
  • 標籤屬性label,能夠自動在input前面增長label。
  • debounce特性,在特定的場景下你會想使用這個功能的,後續會說明。
  • 經過error屬性以及errMsg在值不是預期的時候提示用戶。
  • 自動配置hint屬性,能夠在下方加上input的說明介紹。
  • getLength,能夠自定義配置字符的個數從而改變返回的值得真實長度,與charBase屬性配套使用,默認 { 'zh-cn': 1, 'eng': 1 },默認中英文都是一個字符長度。
  • ...others,後續可能遇到新需求還會不斷地加進來,好比全角半角。

下面我就記錄一下我爲何想要寫這個組件的心路歷程:html5

Debounce Input

首先,我其實只是想寫一個debounce input。緣由有如下幾點:node

  • 第1、input的onChange不斷變化,也就是不debounce的時候沒法知足某些場景。好比:input作驗證的時候,輸入是不是郵箱或者手機號,那麼剛輸入的時候就會提示不合法,你說這不是廢話嗎?怎麼也得等我輸入完你再去判斷我輸入的是否是合法的郵箱啊,也就是下面的狀況(寫篇文章還得作動圖,也是沒誰了):

如上圖所示,每輸一次就須要校驗是不是合法的url,體驗很很差,若是換成debounce input的話,效果就會好不少。在代碼里加上timer屬性:

<BestInput
  label='類型校驗'
  style={{ width: '40%' }}
  timer={600} /*上面的示例沒有timer屬性,這裏設置用戶在600ms內沒其餘輸入再監聽*/
  error={this.state.emailTrue}
  errMsg='這不是一個合法的郵箱'
  onChange={this.handleRegExp}
/>
複製代碼

效果以下:react

能夠看出來,當用戶連續的輸入一個合法郵箱的時候,中間是不會報錯的,也就是不會進行類型檢驗,這就很符合通常的邏輯。

固然,不用input就不能完成上面的效果了嗎?固然能夠,你能夠在普通的input裏使用onBlur來進行輸入的校驗,也就是說輸入完成當窗口失焦才校驗,也能夠實現用戶輸入完成進行校驗的效果。可是,若是你須要動態監聽input的變化,就須要使用onChange,若是你還增長校驗,就須要額外寫一個onBlur,而如今你只須要一個onChange就能夠知足兩個要求。webpack

  • 第2、在目前的項目中,存在大量使用input的組件,而且每一個input的變化須要反饋到另外一個組件中。也就是使用redux,每一個input框的每次onChange都會大量觸發action,犧牲性能。

公司的項目就不上截圖了,你們明白個人意思就好,O(∩_∩)O哈哈~。無非就是少幾回沒必要要的請求,微微的提高一下性能~我一直以爲,即便是0.001ms的提高,也是很重要的。git

  • 其餘的應該還有一些優勢,固然,並非說必須debounce纔好,仍是要看場景,不然爲何html5不直接把debounce加入到input規範裏。嗯,最終仍是看本身的使用場景而定。

[實現]:實現一個debounce input其實很簡單,不過在實際應用場景中,有不少都須要debounce的狀況,不是隻有input能夠debounce,具體的能夠參照lodash的debounce函數,讀讀源碼也可根據本身的實際場景再開發。我這裏就只講怎麼debounce input了。github

setTimeout + clearTimeout

沒錯,其實就是這麼簡單,咱們想要在用戶600ms後不繼續輸入了再獲取input的value,就是設一個600ms的setTimeout,而後在裏面獲取值。當用戶不斷輸入觸發setTimeout的時候,再經過clearTimeout進行重置定時器並從新計時,這樣就很簡單的實現了咱們的需求。web

// 下面是普通的js實現,能夠參考一下
// 獲取input元素
var textInput = document.getElementById('test-input');

// 初始化一個定時器函數
var timeout = null;

textInput.onkeyup = function (e) {
    // 不斷重置定時器函數
    clearTimeout(timeout);
    // 500ms內沒任何其餘輸入,獲取debounce以後的結果
    timeout = setTimeout(function () {
        console.log('Input Value:', textInput.value);
    }, 500);
};
複製代碼

產品驅動業務

重點來了,做爲一個剛畢業的職場小白,公司的流程還不是很熟悉,進入公司無非就是作業務。評審—>排期->開發->上線,期間可能會包含着產品屢次的改需求,哈哈,我並非針對產品哦~所以,對於我來講,我所作的是我應該作的業務,但可能並非我想作的業務。可是,每作一個需求,我以爲仍是須要思考的,爲何要這麼作,爲何要改爲這樣,產品確定有本身的想法,可能這麼作更符合用戶的邏輯等等。
廢話很少說,開始進入正題,囉嗦一大堆跟這篇文章有啥關係,固然有關係了,沒看到小標題嗎?產品驅動業務!項目裏有這麼一個需求:
獲取用戶輸入的內容,而後不能超過10個字符,可是其中中文字符算1個,英文字母和數字算0.5個
確實不是一個複雜的需求,獲取輸入的內容正則匹配一下而後從新計算length返回就行了,那麼問題來了,若是多個組件都用到這個需求了可是要求又不同呢?好比頁面A要求中文1個英文也是1個,頁面B要求中文是2個英文是1個。那豈不是每個都要配套寫對應的函數。因此,順便的,我把這個需求也加到了react-best-input裏,能夠經過配置屬性charBase來進行字符的修改,而後經過getLength獲取自定義的輸入長度。npm

charBase {
    'zh-cn': number//中文字符長度,
    'eng': number//英文字符長度
}
getLength(length) // 獲取自定義長度
複製代碼

如何發佈一個React組件到npm

開發完了,該發佈組件到npm了,步驟特別簡單,首先就是配置好webpack的各類配置,每一個人配置都不同,能夠參考各類文檔配置一個適合你的就能夠,我就不介紹了,由於我也在進修中,O(∩_∩)O哈哈~。redux

這裏多說一句啊,webpack4+默認就是壓縮代碼,也就是自帶uglifyJs的功能,所以,你若是在開發的時候,可使用webpack --mode devlopment進行打包查看打包後的代碼,也能夠參照個人配置。

  • 發佈第一步:yarn build 把你的代碼打包,爲了最簡化,打包完以後會在指定文件夾出現對應的文件。個人就是在lib下的index.js文件。
  • 發佈第二步:yarn link 開發完了固然須要測試一下了,不然你發佈的包別人安裝了發現不能用豈不是很尷尬!!!使用yarn link,該命令會幫你建立本地的引用包命令,你就能夠在本地使用命令來測試你的包是否正確了

這裏有個小坑,本地測試必須使用雙引號引用包名稱,不然會報錯,也就是yarn link "react-best-input"才能夠。

  • 發佈第三步:yarn publish 測試結束沒問題了,就能夠發佈了,使用yarn publish命令來進行發佈,固然你須要先在npm上註冊本身的帳號才能夠,註冊的過程就很少說了。第一次發佈須要你的登陸信息,以後就會發布你的包。

    這裏也有一個小坑:npm註冊的時候郵箱好像不能用國內的郵箱,要否則提示錯誤,沒測試過,可是我用126郵箱註冊了五次都沒成功,而使用gmail郵箱註冊了一次就成功了,相同的帳戶名密碼。。。

  • 發佈第四步:更新 更新使用的命令也是yarn publish,只不過他會提示你當前版本和你想要發佈的版本,若是當前版本v1.0.1,你只須要修改一個不一樣的版本號就能夠更新上去。

踩坑記錄

react語法坑

若是沒有使用原生的js編寫包,使用的是react語法寫的,那麼在webpack的時候須要使用babel轉譯成es5代碼才能夠。須要使用babel-preset-react,babel-preset-es2015和babel-preset-stage-1。

SSR坑

服務端渲染,很火的一個詞,也可能大部分項目都在用了,我是想說的不是這個問題,我想說的是若是你寫的組件用到了底層諸如window,document這些變量的話,那麼在服務端渲染是過不去的,通常來講是node端,node端是沒有上面兩個變量的。由於我用的是input,而且使用了樣式,style-loader會使用底層的document.querySelector來查找dom節點插入樣式,所以這個包在服務端渲染的時候會報錯:window is not defined.

[解決辦法]:兵來將擋,水來土屯。其實就是異步加載組件唄,這種組件通常來講也不必在服務端渲染出來因此目前個人解決辦法就是使用webpack的import()方法對組件進行異步加載,這樣就沒問題了。所以,我又額外寫了一個異步加載的組件,有須要的話直接拿來用就能夠了:rc-async-component。這裏應該叫react-async-component的,可是奈何被人家一個月前註冊了,因此說提早搶個好名字有用啊,哈哈。

使用方法很是簡單,代碼以下:

...
import asyncComponent from 'rc-async-component';
...
const BestInput = asyncComponent(() => import('react-best-input'));
...
render() {
    return (
        <BestInput />
    )
}

複製代碼

強調一下,非服務端渲染直接就可使用,沒有任何問題,服務端渲染目前須要用異步加載的方式,可能後續有更好的解決辦法到時候會更新文檔。

結束語

若是看到這還能堅持看下去,我真的感謝大家了,感受本身水平有限,會不斷提升的!我以爲對一我的有幫助也是有意義的事情,O(∩_∩)O哈哈~

傳送門:react-best-inputrc-async-component

若是您喜歡,謝謝star,我會很是開心

相關文章
相關標籤/搜索