작성, 읽기, 업데이트 및 삭제에 사용되는 양식이 하나 있습니다. 같은 형식으로 3 개의 구성 요소를 만들었지 만 다른 소품을 전달합니다. CreateForm.js, ViewForm.js (삭제 버튼으로 읽기 전용) 및 UpdateForm.js가 있습니다.
예전에는 PHP로 작업 했었으므로 항상 한 가지 형태로 수행했습니다.
상점을 관리하기 위해 React와 Redux를 사용합니다.
CreateForm 구성 요소에있을 때 하위 구성 요소에 전달 createForm={true}
하여 입력으로 값을 채우지 않고 비활성화하지 않도록합니다. 내 ViewForm 구성 요소 에서이 소품을 전달합니다 readonly="readonly"
.
그리고 나는 값이 가득하고 업데이트 할 수없는 텍스트 영역에 또 다른 문제가 있습니다. 값이있는 반응 텍스트 영역은 읽기 전용이지만 업데이트해야합니다
이러한 다양한 형태의 양식을 처리하는 하나의 구성 요소 만 갖는 가장 좋은 구조는 무엇입니까?
조언, 튜토리얼, 비디오, 공유 할 데모가 있습니까?
답변
Redux Form 패키지를 찾았습니다 . 정말 잘해!
따라서 Reux-Redux 와 함께 Redux 를 사용할 수 있습니다 .
먼저 폼 구성 요소를 만들어야합니다 (분명히).
import React from 'react';
import { reduxForm } from 'redux-form';
import validateContact from '../utils/validateContact';
class ContactForm extends React.Component {
render() {
const { fields: {name, address, phone}, handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit}>
<label>Name</label>
<input type="text" {...name}/>
{name.error && name.touched && <div>{name.error}</div>}
<label>Address</label>
<input type="text" {...address} />
{address.error && address.touched && <div>{address.error}</div>}
<label>Phone</label>
<input type="text" {...phone}/>
{phone.error && phone.touched && <div>{phone.error}</div>}
<button onClick={handleSubmit}>Submit</button>
</form>
);
}
}
ContactForm = reduxForm({
form: 'contact', // the name of your form and the key to
// where your form's state will be mounted
fields: ['name', 'address', 'phone'], // a list of all your fields in your form
validate: validateContact // a synchronous validation function
})(ContactForm);
export default ContactForm;
그런 다음 폼을 처리하는 구성 요소를 연결합니다.
import React from 'react';
import { connect } from 'react-redux';
import { initialize } from 'redux-form';
import ContactForm from './ContactForm.react';
class App extends React.Component {
handleSubmit(data) {
console.log('Submission received!', data);
this.props.dispatch(initialize('contact', {})); // clear form
}
render() {
return (
<div id="app">
<h1>App</h1>
<ContactForm onSubmit={this.handleSubmit.bind(this)}/>
</div>
);
}
}
export default connect()(App);
그리고 결합 된 감속기에 redux- 폼 감속기를 추가하십시오.
import { combineReducers } from 'redux';
import { appReducer } from './app-reducers';
import { reducer as formReducer } from 'redux-form';
let reducers = combineReducers({
appReducer, form: formReducer // this is the form reducer
});
export default reducers;
그리고 유효성 검사기 모듈은 다음과 같습니다.
export default function validateContact(data, props) {
const errors = {};
if(!data.name) {
errors.name = 'Required';
}
if(data.address && data.address.length > 50) {
errors.address = 'Must be fewer than 50 characters';
}
if(!data.phone) {
errors.phone = 'Required';
} else if(!/\d{3}-\d{3}-\d{4}/.test(data.phone)) {
errors.phone = 'Phone must match the form "999-999-9999"'
}
return errors;
}
양식이 완료된 후 모든 필드를 일부 값으로 채우려면 initialize
함수를 사용할 수 있습니다 .
componentWillMount() {
this.props.dispatch(initialize('contact', {
name: 'test'
}, ['name', 'address', 'phone']));
}
양식을 채우는 또 다른 방법은 initialValues를 설정하는 것입니다.
ContactForm = reduxForm({
form: 'contact', // the name of your form and the key to
fields: ['name', 'address', 'phone'], // a list of all your fields in your form
validate: validateContact // a synchronous validation function
}, state => ({
initialValues: {
name: state.user.name,
address: state.user.address,
phone: state.user.phone,
},
}))(ContactForm);
이 문제를 처리 할 다른 방법이 있다면 메시지를 남겨주세요! 감사합니다.
답변
업데이트 : 2018 년이며 Formik 만 사용 합니다. (또는 Formik와 같은 라이브러리) 만 사용합니다.
또한 거기에 반응-REDUX 형태 ( 단계별 일부 교환하는 것), REDUX 형태를 마크 업 선언의 자바 스크립트 (보일러는). 좋아 보이지만 아직 사용하지 않았습니다.
읽어보기에서 잘라내어 붙여 넣기 :
import React from 'react';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { modelReducer, formReducer } from 'react-redux-form';
import MyForm from './components/my-form-component';
const store = createStore(combineReducers({
user: modelReducer('user', { name: '' }),
userForm: formReducer('user')
}));
class App extends React.Component {
render() {
return (
<Provider store={ store }>
<MyForm />
</Provider>
);
}
}
./components/my-form-component.js
import React from 'react';
import { connect } from 'react-redux';
import { Field, Form } from 'react-redux-form';
class MyForm extends React.Component {
handleSubmit(val) {
// Do anything you want with the form value
console.log(val);
}
render() {
let { user } = this.props;
return (
<Form model="user" onSubmit={(val) => this.handleSubmit(val)}>
<h1>Hello, { user.name }!</h1>
<Field model="user.name">
<input type="text" />
</Field>
<button>Submit!</button>
</Form>
);
}
}
export default connect(state => ({ user: state.user }))(MyForm);
편집 : 비교
반응 리덕스 양식 문서는 리덕스 양식과 비교합니다.
https://davidkpiano.github.io/react-redux-form/docs/guides/compare-redux-form.html
답변
양식 관련 문제를 처리하기 위해 거대한 라이브러리를 신경 쓰지 않는 사람들에게는 redux-form-utils를 권장합니다. 합니다.
양식 컨트롤에 대한 값을 생성하고 핸들러를 변경하고, 양식의 감속기를 생성하고, 특정 (또는 모든) 필드를 지우는 편리한 액션 생성기 등을 생성 할 수 있습니다.
코드로 조립하기 만하면됩니다.
을 사용 redux-form-utils
하면 다음과 같은 양식 조작으로 끝납니다.
import { createForm } from 'redux-form-utils';
@createForm({
form: 'my-form',
fields: ['name', 'address', 'gender']
})
class Form extends React.Component {
render() {
const { name, address, gender } = this.props.fields;
return (
<form className="form">
<input name="name" {...name} />
<input name="address" {...address} />
<select {...gender}>
<option value="male" />
<option value="female" />
</select>
</form>
);
}
}
그러나,이 라이브러리는 문제를 해결 C
하고 U
, 위해 R
그리고 D
어쩌면 더 통합 된 Table
구성 요소가 antipate하는 것입니다.
답변
특 대형 라이브러리를 사용하지 않고 완전히 제어 된 양식 구성 요소를 작성하려는 사람들에게는 또 다른 것입니다.
ReduxFormHelper -100 줄 미만의 작은 ES6 클래스 :
class ReduxFormHelper {
constructor(props = {}) {
let {formModel, onUpdateForm} = props
this.props = typeof formModel === 'object' &&
typeof onUpdateForm === 'function' && {formModel, onUpdateForm}
}
resetForm (defaults = {}) {
if (!this.props) return false
let {formModel, onUpdateForm} = this.props
let data = {}, errors = {_flag: false}
for (let name in formModel) {
data[name] = name in defaults? defaults[name] :
('default' in formModel[name]? formModel[name].default : '')
errors[name] = false
}
onUpdateForm(data, errors)
}
processField (event) {
if (!this.props || !event.target) return false
let {formModel, onUpdateForm} = this.props
let {name, value, error, within} = this._processField(event.target, formModel)
let data = {}, errors = {_flag: false}
if (name) {
value !== false && within && (data[name] = value)
errors[name] = error
}
onUpdateForm(data, errors)
return !error && data
}
processForm (event) {
if (!this.props || !event.target) return false
let form = event.target
if (!form || !form.elements) return false
let fields = form.elements
let {formModel, onUpdateForm} = this.props
let data = {}, errors = {}, ret = {}, flag = false
for (let n = fields.length, i = 0; i < n; i++) {
let {name, value, error, within} = this._processField(fields[i], formModel)
if (name) {
value !== false && within && (data[name] = value)
value !== false && !error && (ret[name] = value)
errors[name] = error
error && (flag = true)
}
}
errors._flag = flag
onUpdateForm(data, errors)
return !flag && ret
}
_processField (field, formModel) {
if (!field || !field.name || !('value' in field))
return {name: false, value: false, error: false, within: false}
let name = field.name
let value = field.value
if (!formModel || !formModel[name])
return {name, value, error: false, within: false}
let model = formModel[name]
if (model.required && value === '')
return {name, value, error: 'missing', within: true}
if (model.validate && value !== '') {
let fn = model.validate
if (typeof fn === 'function' && !fn(value))
return {name, value, error: 'invalid', within: true}
}
if (model.numeric && isNaN(value = Number(value)))
return {name, value: 0, error: 'invalid', within: true}
return {name, value, error: false, within: true}
}
}
그것은 당신을 위해 모든 일을하지 않습니다. 그러나 제어 양식 구성 요소의 작성, 유효성 검증 및 처리를 용이하게합니다. 위 코드를 복사하여 프로젝트에 붙여 넣거나 대신 해당 라이브러리를 포함시킬 수 있습니다.redux-form-helper
(플러그!).
사용하는 방법
첫 번째 단계는 양식의 상태를 나타내는 특정 데이터를 Redux 상태에 추가하는 것입니다. 이 데이터에는 양식의 각 필드에 대한 현재 플래그 값과 오류 플래그 세트가 포함됩니다.
폼 상태는 기존 감속기에 추가되거나 별도의 감속기에 정의 될 수 있습니다.
또한 양식 작성 및 각 조치 작성자의 업데이트를 시작하는 특정 조치를 정의해야합니다.
액션 예 :
export const FORM_UPDATE = 'FORM_UPDATE'
export const doFormUpdate = (data, errors) => {
return { type: FORM_UPDATE, data, errors }
}
...
감속기 예 :
...
const initialState = {
formData: {
field1: '',
...
},
formErrors: {
},
...
}
export default function reducer (state = initialState, action) {
switch (action.type) {
case FORM_UPDATE:
return {
...ret,
formData: Object.assign({}, formData, action.data || {}),
formErrors: Object.assign({}, formErrors, action.errors || {})
}
...
}
}
두 번째이자 마지막 단계는 양식에 대한 컨테이너 구성 요소를 만들고 Redux 상태 및 작업의 각 부분에 연결하는 것입니다.
또한 양식 필드의 유효성 검사를 지정하여 양식 모델을 정의해야합니다. 이제 ReduxFormHelper
객체를 컴포넌트의 멤버로 인스턴스화 하고 폼 모델과 폼 상태의 콜백 디스패치 업데이트를 전달합니다.
그런 다음 구성 요소의에 render()
방법 우리는 각 필드의 결합해야 onChange
하고 폼의 onSubmit
이벤트를 processField()
하고processForm()
메소드 하고 상태의 폼 오류 플래그에 따라 각 필드에 대한 오류 블록을 표시해야합니다.
아래 예는 Twitter Bootstrap 프레임 워크의 CSS를 사용합니다.
컨테이너 구성 요소 예 :
import React, {Component} from 'react';
import {connect} from 'react-redux'
import ReduxFormHelper from 'redux-form-helper'
class MyForm extends Component {
constructor(props) {
super(props);
this.helper = new ReduxFormHelper(props)
this.helper.resetForm();
}
onChange(e) {
this.helper.processField(e)
}
onSubmit(e) {
e.preventDefault()
let {onSubmitForm} = this.props
let ret = this.helper.processForm(e)
ret && onSubmitForm(ret)
}
render() {
let {formData, formErrors} = this.props
return (
<div>
{!!formErrors._flag &&
<div className="alert" role="alert">
Form has one or more errors.
</div>
}
<form onSubmit={this.onSubmit.bind(this)} >
<div className={'form-group' + (formErrors['field1']? ' has-error': '')}>
<label>Field 1 *</label>
<input type="text" name="field1" value={formData.field1} onChange={this.onChange.bind(this)} className="form-control" />
{!!formErrors['field1'] &&
<span className="help-block">
{formErrors['field1'] === 'invalid'? 'Must be a string of 2-50 characters' : 'Required field'}
</span>
}
</div>
...
<button type="submit" className="btn btn-default">Submit</button>
</form>
</div>
)
}
}
const formModel = {
field1: {
required: true,
validate: (value) => value.length >= 2 && value.length <= 50
},
...
}
function mapStateToProps (state) {
return {
formData: state.formData, formErrors: state.formErrors,
formModel
}
}
function mapDispatchToProps (dispatch) {
return {
onUpdateForm: (data, errors) => {
dispatch(doFormUpdate(data, errors))
},
onSubmitForm: (data) => {
// dispatch some action which somehow updates state with form data
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyForm)
답변
