React + Redux-양식 구성 요소에서 CRUD를 처리하는 가장 좋은 방법은 무엇입니까?
작성, 읽기, 업데이트 및 삭제에 사용되는 양식이 하나 있습니다. 같은 형식으로 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-form 의 자바 스크립트 (및 상용구)를 마크 업 선언과 교환하는 것으로 보이는 react-redux-form ( 단계별 )도 있습니다. 좋아 보이지만 아직 사용하지 않았습니다.
읽어보기에서 잘라내어 붙여 넣기 :
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 || {})
}
...
}
}
The second and final step is create a container component for our form and connect it with respective part of Redux state and actions.
Also we need to define a form model specifying validation of form fields. Now we instantiate ReduxFormHelper
object as a member of the component and pass there our form model and a callback dispatching update of the form state.
Then in the component's render()
method we have to bind each field's onChange
and the form's onSubmit
events with processField()
and processForm()
methods respectively as well as display error blocks for each field depending on the form error flags in the state.
The example below uses CSS from Twitter Bootstrap framework.
Container Component example:
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)
'Programming' 카테고리의 다른 글
setuptools 대 distutils : 왜 distutils가 여전히 중요한가? (0) | 2020.07.06 |
---|---|
유효한 국제 전화 번호의 최소 길이는 얼마입니까? (0) | 2020.07.06 |
REST, HTTP 삭제 및 매개 변수 (0) | 2020.07.06 |
MongoDB 다 대다 협회 (0) | 2020.07.06 |
테이블 찾아보기 / 편집 및 쿼리 실행을위한 SQL Server Management Studio 대안 (0) | 2020.07.06 |