翻譯|Simple React Native forms with redux-form, immutable.js and styled-components - Esben Petersen


title: 翻譯|Simple React Native forms with redux-form, immutable.js and styled-components - Esben Petersen
date: 2017-04-03 16:07:15
categories: 翻譯
tags: Redux


在React中處理表單還不怎么好弄,看看這篇文章講的挺好的看看,試著翻譯一下
原文請參看原文

start

如果你想看看怎么在react-native 想使用redux-form和immutable.js.你看可以看看這篇文章的代碼

Introduction

Traede,我使用redux整合redux-form來創(chuàng)建表單.redux-form是一個非常好的庫,但是沒有什么好的示例代碼介紹怎么和React-native配合使用.所以當(dāng)我開始在React-Natvie中使用redux-form的時候,發(fā)現(xiàn)還是有一點(diǎn)難度的.大多數(shù)的情況都因為我發(fā)現(xiàn)在React-Native中使用Immutable.js的時候會中斷redux-form運(yùn)行的bug.Redux-form主版本號已經(jīng)到了6.4.2了.所以我考慮可以根據(jù)我的學(xué)習(xí)過程來寫一點(diǎn)怎么在應(yīng)用中同時使用redux-form和Immutable.js的文檔.

Agenda

大體的步驟是:

  1. 看看redux-form在native和web之間的差異點(diǎn)
  2. 看看怎么使redux-form和Immutable.js一起使用
  3. 使用react-native-clean-form的完整實(shí)例

雞凍不?好了,開始了

在React-native中使用redux-form

如果你不太熟悉redux-form,我建議你看看redux-form簡單文檔
.注意:這個指南假定你使用的redux-form的版本大于6.4.2.如果不是這個版本,并且還在使用Immutable.js,那么要看看這個issue.創(chuàng)建一個表單基礎(chǔ)的三個步驟是:

  1. 在你的redux store中加入redux-form reducer
  2. 使用reduxForm包裝器把你的表單連接到store
  3. 使用Field包裝器把特定的表單字段連接到Store

0. 創(chuàng)建React Native 項目

假設(shè)你已經(jīng)有了可以運(yùn)行的React Native項目.如果沒有,使用react-native init MyReduxFormProjct終端命令行命令也很容易創(chuàng)建項目.

1.把redux-form reducer添加到你的redux store

做這一步,請參考redux-form文檔

2.使用redux-form包裝器把你的form連接到store

我們使用一個簡單的表單來開始工作.

import React from 'react'
import {
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  View
} from 'react-native'

const Form = props => {
  return (
    <View style={styles.container}>
      <Text>Email:</Text>
      <TextInput style={styles.input} />
      <TouchableOpacity>
        <Text style={styles.button}>Submit</Text>
      </TouchableOpacity>
    </View>
  )
}

export default Form

const styles = StyleSheet.create({
  button: {
    backgroundColor: 'blue',
    color: 'white',
    height: 30,
    lineHeight: 30,
    marginTop: 10,
    textAlign: 'center',
    width: 250
  },
  container: {

  },
  input: {
    borderColor: 'black',
    borderWidth: 1,
    height: 37,
    width: 250
  }
})

好了,我們已經(jīng)有了表單,看起來和十億美元級別的app差不多.下面我們需要使用reduxForm包裝器把表單連接到redux form上.這是因為在表單中的每一個按鍵操作都會發(fā)送輸入字段的值到store.當(dāng)我們按下提交按鈕,redux-form將會從store中獲取保存的值發(fā)送到一個我們定制的回調(diào)函數(shù).

 import { reduxForm } from 'redux-form'

const submit = values => {
  console.log('submitting form', values)
}

const Form = props => {
  const { handleSubmit } = props

  return (
    <View style={styles.container}>
      <Text>Email:</Text>
      <TextInput style={styles.input} />
      <TouchableOpacity onPress={handleSubmit(submit)}>
        <Text style={styles.button}>Submit</Text>
      </TouchableOpacity>
    </View>
  )
}

export default reduxForm({
  form: 'test'
})(Form)

注釋:為了簡單,省略了樣式和對象的導(dǎo)入代碼

好了,首先我們使用reduxForm包裝form并連接到store.這是react-redux的基礎(chǔ)版本之上的一點(diǎn)修改,可能你比較熟悉了.

接著,我們使用了redux-form的handleSubmit(這個函數(shù)是通過redux-Form注入到組件中的).submit函數(shù)附加到我們的submit按鈕上,所以點(diǎn)擊按鈕的時候,表單會被提交.這一點(diǎn)和web開發(fā)的submit函數(shù)是不同的,web開發(fā)中這個函數(shù)附加到form元素上.在移動平臺上沒有form元素,所以我們直接把它添加到button上,或者TouchableOpaticy.就是這么回事.

到了這一步,可以使用模擬器運(yùn)行代碼試試.我高度推薦react-native-debugger作為Debugger.你可以看看React Native 有關(guān)degugging文檔的建議.

當(dāng)你在模擬器中試著點(diǎn)擊提交表單時,你可以看到回調(diào)函數(shù)返回了空值.

值在哪里呢棍辕?

3.使用Field包裝器把fields連接到store

所以說,redux-form要工作,你必須要使用Field包裝器把每一個field連接到store.

 import { Field, reduxForm } from 'redux-form'

const submit = values => {
  console.log('submitting form', values)
}

const renderInput = ({ input: { onChange, ...restInput }}) => {
  return <TextInput style={styles.input} onChangeText={onChange} {...restInput} />
}

const Form = props => {
  const { handleSubmit } = props

  return (
    <View style={styles.container}>
      <Text>Email:</Text>
      <Field name="email" component={renderInput} />
      <TouchableOpacity onPress={handleSubmit(submit)}>
        <Text style={styles.button}>Submit</Text>
      </TouchableOpacity>
    </View>
  )
}

export default reduxForm({
  form: 'test'
})(Form)

注意,我們添加了Field組件,給定了name屬性,和web開發(fā)中的inputfield工作是類似的.我們也添加了一個渲染函數(shù)告訴reduxForm,這個字段應(yīng)該怎么渲染.(基本上就是一個TextInput組件).

現(xiàn)在這里有些小技巧,很多人可能會出錯.所以留心一下.在web Reac中input組件中,當(dāng)field的值發(fā)生變化時,觸發(fā)一個onChange回調(diào)函數(shù).在React Native中TextInput組件觸發(fā)的是onChangeText回調(diào)函數(shù).為了應(yīng)對這個問題,我們手動添加變化的句柄onChangeText={onChange}.


現(xiàn)在當(dāng)我們提交的時候,表單工作了.

使用Immutable.js時候也可以工作

如果你想在state的管理中使用immutable.js,那么需要一些額外的步驟了配合redux-form工作.我建議你讀讀使用immutable.js和redux-form的官方文檔.但是我們通過一些步驟馬上開始.

1.使用redux-immutablejs combineReducers和redux-form reducer的immutable版本

找到你穿件redux store的代碼處

import { combineReducers } from 'redux-immutablejs'
import { reducer as form } from 'redux-form/immutable' // <--- immutable import

const reducer = combineReducers({ form })

export default reducer

這里有兩件事:(1)你必須使用從redux-immutable或者redux-immutablejs注入combineReducers方法.重要的是輸入的reducer是從redux-form/immutable.并不是redux-form.

2.使用reduxForm包裝器和Field的immutable版本

這一步和第一步實(shí)際有點(diǎn)類似.當(dāng)你在reduxForm中包裝一個表單連接到redux store的時候,確保是從redux-form/immutable導(dǎo)入的.類似
Field也是從這里導(dǎo)入的.

import { Field, reduxForm } from 'redux-form/immutable' // <---- LOOK HERE

const submit = values => {
  console.log('submitting form', values.toJS()) <--- use toJS() to cast to plain object
}

const renderInput = ({ input: { onChange, ...restInput }}) => {
  return <TextInput style={styles.input} onChangeText={onChange} {...restInput} />
}

const Form = props => {
  const { handleSubmit } = props

  return (
    <View style={styles.container}>
      <Text>Email:</Text>
      <Field name="email" component={renderInput} />
      <TouchableOpacity onPress={handleSubmit(submit)}>
        <Text style={styles.button}>Submit</Text>
      </TouchableOpacity>
    </View>
  )
}

export default reduxForm({
  form: 'test'
})(Form)

3.完成了

就這些內(nèi)容,是不是很簡單?

加點(diǎn)樣式組件讓我們的app看起來像十億美元級別的app

使用絕對酷炫的React樣式庫styled-components .
看看源代碼esbenp/react-native-clean-form

第一步:安裝react-native-clean-form

使用npm install —save react-native-clean-form安裝form元素.
也需要vector icon fonts.Readme

第二步:設(shè)計酷炫的表單

看看代碼

 import React, { Component } from 'react'
import {
  ActionsContainer,
  Button,
  FieldsContainer,
  Fieldset,
  Form,
  FormGroup,
  Label,
  Input,
  Select,
  Switch
} from 'react-native-clean-form'

const countryOptions = [
  {label: 'Denmark', value: 'DK'},
  {label: 'Germany', value: 'DE'},
  {label: 'United State', value: 'US'}
]

const FormView = props => (
  <Form>
    <FieldsContainer>
      <Fieldset label="Contact details">
        <FormGroup>
          <Label>First name</Label>
          <Input placeholder="John" />
        </FormGroup>
        <FormGroup>
          <Label>Last name</Label>
          <Input placeholder="Doe" />
        </FormGroup>
        <FormGroup>
          <Label>Phone</Label>
          <Input placeholder="+45 88 88 88 88" />
        </FormGroup>
        <FormGroup>
          <Label>First name</Label>
          <Input placeholder="John" />
        </FormGroup>
      </Fieldset>
      <Fieldset label="Shipping details" last>
        <FormGroup>
          <Label>Address</Label>
          <Input placeholder="Hejrevej 33" />
        </FormGroup>
        <FormGroup>
          <Label>City</Label>
          <Input placeholder="Copenhagen" />
        </FormGroup>
        <FormGroup>
          <Label>ZIP Code</Label>
          <Input placeholder="2400" />
        </FormGroup>
        <FormGroup>
          <Label>Country</Label>
          <Select
              name="country"
              label="Country"
              options={countryOptions}
              placeholder="Denmark"
          />
        </FormGroup>
        <FormGroup border={false}>
          <Label>Save my details</Label>
          <Switch />
        </FormGroup>
      </Fieldset>
    </FieldsContainer>
    <ActionsContainer>
      <Button icon="md-checkmark" iconPlacement="right">Save</Button>
    </ActionsContainer>
  </Form>
)

export default FormView

如果你比較熟悉Twitter Bootstrap你可以從react-native-clean-form中看到類似的句法.好了輸入Input,SelectSwitch.這里的元素已經(jīng)被包裝在FromGroupLabel.此外我們也支持驗證

import React, { Component } from 'react'
import { reduxForm } from 'redux-form/immutable'
import {
  ActionsContainer,
  Button,
  FieldsContainer,
  Fieldset,
  Form
} from 'react-native-clean-form'
import {
  Input,
  Select,
  Switch
} from 'react-native-clean-form/redux-form-immutable'
import { View,Text } from 'react-native'

const onSubmit = (values, dispatch) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(values.toJS())
      resolve()
    }, 1500)
  })
}

const countryOptions = [
  {label: 'Denmark', value: 'DK'},
  {label: 'Germany', value: 'DE'},
  {label: 'United State', value: 'US'}
]

class FormView extends Component {
  render() {
    const { handleSubmit, submitting } = this.props

    return (
      <Form>
        <FieldsContainer>
          <Fieldset label="Contact details">
            <Input name="first_name" label="First name" placeholder="John" />
            <Input name="last_name" label="Last name" placeholder="Doe" />
            <Input name="email" label="Email" placeholder="something@domain.com" />
            <Input name="telephone" label="Phone" placeholder="+45 88 88 88 88" />
          </Fieldset>
          <Fieldset label="Shipping details" last>
            <Input name="address" label="Address" placeholder="Hejrevej 33" />
            <Input name="city" label="City" placeholder="Copenhagen" />
            <Input name="zip" label="ZIP Code" placeholder="2400" />
            <Select
              name="country"
              label="Country"
              options={countryOptions}
              placeholder="Denmark"
            />
            <Switch label="Save my details" border={false} name="save_details" />
          </Fieldset>
        </FieldsContainer>
        <ActionsContainer>
          <Button icon="md-checkmark" iconPlacement="right" onPress={handleSubmit(onSubmit)} submitting={submitting}>Save</Button>
        </ActionsContainer>
      </Form>
    )
  }
}

export default reduxForm({
  form: 'Form',
  validate: values => {
    const errors = {}

    values = values.toJS()

    if (!values.first_name) {
      errors.first_name = 'First name is required.'
    }

    if (!values.last_name) {
      errors.last_name = 'Last name is required.'
    }

    if (!values.email) {
      errors.email = 'Email is required.'
    }

    return errors
  }
})(FormView)

很簡單,是嗎唁毒?現(xiàn)在我們有了一個連接到store的好看的表單,還能支持?jǐn)?shù)據(jù)驗證,異步的按鈕反饋.你可以在repository查看更多特性.

附加資料:你可能會有疑問蚯姆,如果我要提交表單數(shù)據(jù)到服務(wù)器端怎么辦呢邀桑?
作者在這里沒有寫出來.如果想了解可以參看這個repo

The End

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市水援,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌茅郎,老刑警劉巖蜗元,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異系冗,居然都是意外死亡奕扣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門毕谴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來成畦,“玉大人,你說我怎么就攤上這事涝开⊙剩” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵舀武,是天一觀的道長。 經(jīng)常有香客問我,道長瘪匿,這世上最難降的妖魔是什么跛梗? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮棋弥,結(jié)果婚禮上核偿,老公的妹妹穿的比我還像新娘。我一直安慰自己顽染,他們只是感情好漾岳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著粉寞,像睡著了一般尼荆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上唧垦,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天捅儒,我揣著相機(jī)與錄音,去河邊找鬼振亮。 笑死巧还,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的双炕。 我是一名探鬼主播狞悲,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼妇斤!你這毒婦竟也來了摇锋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤站超,失蹤者是張志新(化名)和其女友劉穎荸恕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體死相,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡融求,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了算撮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片生宛。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肮柜,靈堂內(nèi)的尸體忽然破棺而出陷舅,到底是詐尸還是另有隱情,我是刑警寧澤审洞,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布莱睁,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏仰剿。R本人自食惡果不足惜创淡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望南吮。 院中可真熱鬧琳彩,春花似錦、人聲如沸旨袒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砚尽。三九已至,卻和暖如春辉词,著一層夾襖步出監(jiān)牢的瞬間必孤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工瑞躺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留敷搪,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓幢哨,卻偏偏與公主長得像赡勘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子捞镰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容