无法编辑文本输入反应 redux 表单

Posted

技术标签:

【中文标题】无法编辑文本输入反应 redux 表单【英文标题】:Not able to edit text input react redux form 【发布时间】:2018-05-18 17:25:07 【问题描述】:

从数据库设置值后无法编辑文本输入。该值会被最近键入的一个字符更改,同时从该文本输入中集中注意力。最初,我通过 state 属性设置 textinput 的每个值。然后编辑模式我从 db 获取该值并通过 state 属性进行设置。之后,我无法在编辑模式下进行编辑。

import React, 
    Component
 from 'react';
import ReactDOM from 'react-dom';
import 
    Field,
    reduxForm
 from 'redux-form';
import _ from 'lodash';
import 
    addEmployee
 from '../actions/employeeAction';
import 
    editEmployee
 from '../actions/employeeAction';
import 
    connect
 from 'react-redux';
import UploadImage from './uploadimage/uploadImage';
import 
    Redirect
 from 'react-router-dom';
import Init from './index';


const FIELDS = 
    firstname: 
        type: 'input',
        label: 'First Name',
        key: 1,
        name: 'firstname',
        dbName: 'firstname'
    ,
    lastname: 
        type: 'input',
        label: 'Last Name',
        key: 2,
        name: 'lastname',
        dbName: 'lastname'
    ,
    password: 
        type: 'input',
        label: 'Password',
        key: 3,
        name: 'password',
        dbName: 'password'
    ,
    reenterpassword: 
        type: 'input',
        label: 'Re-password',
        key: 4,
        name: 'reenterpassword',
        dbName: 'reenterpassword'
    ,
    age: 
        type: 'Number',
        label: 'Age',
        key: 5,
        name: 'age',
        dbName: 'age'
    ,
    occupation: 
        type: 'input',
        label: 'Occupation',
        key: 6,
        name: 'occupation',
        dbName: 'occupation'
    ,
    city: 
        type: 'input',
        label: 'City',
        key: 7,
        name: 'city',
        dbName: 'city'
    ,
    state: 
        type: 'input',
        label: 'State',
        key: 8,
        name: 'state',
        dbName: 'state'
    ,
    pin: 
        type: 'input',
        label: 'Pin',
        key: 9,
        name: 'pin',
        dbName: 'pin'
    ,
    phone: 
        type: 'input',
        label: 'Phone',
        key: 10,
        name: 'phone',
        dbName: 'phone'
    ,
    email: 
        type: 'email',
        label: 'Email',
        key: 11,
        name: 'email',
        dbName: 'email'
    ,
    dateOfJoin: 
        type: 'date',
        label: 'Date Of Join',
        key: 12,
        name: 'dateOfJoin',
        dbName: 'dateOfJoin'
    ,
    uploadPhoto: 
        type: 'blob',
        label: 'Upload Image',
        key: 13,
        name: 'uploadPhoto',
        dbName: 'croppedImage'
    


class PostNew extends Component 
    constructor() 
        super();
        this.renderField = this.renderField.bind(this);
        this.onCroppedImgData = this.onCroppedImgData.bind(this);
        this.valueChange = this.valueChange.bind(this);
        this.state = 
            croppedData: undefined,
            header: 'Registration Form',
            createdUser: false
        ;
        /********Initial setup for state for each text input********/
        _.each(FIELDS, (type, field) => 
            let dbState = type.dbName;
            this.state = 
                dbState: ""
            ;
        );
    
    componentWillMount() 
        if (this.props.header) 
            this.setState(
                header: this.props.header
            );
        
        if (this.props.userData) 
            _.each(FIELDS, (type, field) => 
                let dbState = type.dbName;
                this.setState(
                    [dbState]: this.props.userData[dbState]
                );
            );
        

    
    callAttribute(field) 
        return <Field label = 
            field.label
        
        key = 
            field.key
        
        type = 
            field.type
        
        name = 
            field.name
        
        dbname = 
            field.dbName
        
        component = 
            this.renderField
        
        />
    
    onCroppedImgData(data) 
        this.setState(
            croppedData: data
        );
    
    valueChange(e, dbName) 
        if (this.props.userData) 
            /**********Setting state dynamically here and called onChange method of textinput.And textinput value changed one character while we focused out.*********/
            this.setState(
                [dbName]: e.target.value
            );
        

    
    renderField(field) 
        const 
            meta: 
                touched,
                error
            
         = field;
        const 
            label,
            type,
            key,
            name,
            dbname
         = field;

        if (label === "Upload Image") 
            let src;
            if (this.props.userData) 
                src = this.props.userData[dbname];
            
            return ( <
                div className = "upload-image" >
                <
                UploadImage message = "Upload Image"
                callbackImgCropped = 
                    this.onCroppedImgData
                
                profileImg = 
                    src
                
                /> <
                /div>
            )
         else 
            let val;
            if (this.props.userData) 
                console.log("=====this.state[dbname]===", this.state[dbname]);
                val = this.state[dbname];
                if (dbname === "dateOfJoin") 
                    val = "";
                
            

            return ( <
                div className = "field-div" >
                <
                div >
                <
                span className = "label-name" > 
                    label
                 < /span> <
                input className = "form-input"
                key = 
                    key
                
                type = 
                    type
                  ...field.input
                
                ref = 
                    name
                
                value = 
                    this.state[dbname]
                
                onChange = 
                    (e) => 
                        this.valueChange(e, dbname)
                    
                
                /> <
                span className = "error-msg" > 
                    touched ? error : ' '
                 < /span> <
                /div> <
                /div>

            );
        

    
    onSubmit(obj) 
        if (this.state.croppedData) 
            obj.croppedImage = this.state.croppedData;
        
        if (this.props.userData) 
            obj.id = this.props.userData.id;
            console.log("edit operation");
            this.props.editEmployee(obj, (data) => 
                this.props.reset();
            );
         else 
            if (this.state.croppedData) 
                obj.croppedImage = this.state.croppedData;
            
            this.props.addEmployee(obj, (data) => 
                this.setState(
                    createdUser: true
                );
                this.props.reset();
            );
        

    
    render() 
        const 
            handleSubmit,
            pristine,
            reset,
            submitting
         = this.props;
        if (this.state.createdUser) 
            return ( < Redirect to = "/" / > );
         else 
            return ( <
                div className = "form-div" >
                <
                div className = "form-header" > 
                    this.state.header
                 < /div> <
                form className = "employee-form"
                onSubmit = 
                    handleSubmit(this.onSubmit.bind(this))
                 > 
                    _.map(FIELDS, this.callAttribute.bind(this))
                 <
                div className = "form-button" >
                <
                button type = "submit"
                disabled = 
                    submitting
                 >
                Submit <
                /button> <
                button type = "button"
                disabled = 
                    pristine || submitting
                
                onClick = 
                    reset
                 >
                Clear Values <
                /button> <
                /div> <
                /form> <
                /div>  
            );
        

    


function validate(values) 
    const errors = ;
    _.each(FIELDS, (type, field) => 
        if (!values[field] && type.type != "blob" && type.label != "Date Of Join") 
            if (type.type == "email") 
                errors[field] = `Enter an $field`;
             else 
                errors[field] = `Enter a $field`;
            

         else if (type.type == "email" && values[field]) 
            if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]2,4$/i.test(values[field])) 
                errors[field] = 'Invalid email address'
            
         else if (type.name == "reenterpassword" && values[field] !== values['password']) 
            errors[field] = 'Password mismatched.Please reenter password.';
        
    );
    return errors;


export default reduxForm(
    validate,
    fields: _.keys(FIELDS),
    form: 'PostNewForm'
)(connect(null, 
    addEmployee,
    editEmployee
)(PostNew));

【问题讨论】:

【参考方案1】:
    Yes got the solution ...We need to include  "change" method from 'redux-form' and we need to dispatch the method with 3 arguments.

this.props.dispatch(change('PostNewForm', [dbName], e.currentTarget.value));
1st argument = form name 
2nd argument = state name
3rd argument = value
Below is the working code...These redux form controls are uncontrolled .so we need to include change from redux-form.

    import React, Component from 'react';
    import ReactDOM from 'react-dom';
    import  Field, reduxForm,change  from 'redux-form';
    import _ from 'lodash';
    import addEmployee from '../actions/employeeAction';
    import editEmployee from '../actions/employeeAction';
    import  connect  from 'react-redux';
    import UploadImage from './uploadimage/uploadImage';
    import  Redirect  from 'react-router-dom';
    import Init from './index'; 


    const FIELDS = 
      firstname:
         type:'input',
         label:'First Name',
         key:1,
         name:'firstname',
         dbName:'firstname'
      ,
      lastname:
         type:'input',
         label:'Last Name',
         key:2,
         name:'lastname',
         dbName:'lastname'
      ,
      password:
         type:'password',
         label:'Password',
         key:3,
         name:'password',
         dbName:'password'
      ,
      reenterpassword:
         type:'password',
         label:'Re-password',
         key:4,
         name:'reenterpassword',
         dbName:'reenterpassword'
      ,
      age:
         type:'Number',
         label:'Age',
         key:5,
         name:'age',
         dbName:'age'
      ,
      occupation:
         type:'input',
         label:'Occupation',
         key:6,
         name:'occupation',
         dbName:'occupation'
      ,
      city:
         type:'input',
         label:'City',
         key:7,
         name:'city',
         dbName:'city'
      ,
      state:
         type:'input',
         label:'State',
         key:8,
         name:'state',
         dbName:'state'
      ,
      pin:
         type:'input',
         label:'Pin',
         key:9,
         name:'pin',
         dbName:'pin'
      ,
      phone:
         type:'input',
         label:'Phone',
         key:10,
         name:'phone',
         dbName:'phone'
      ,
      email:
         type:'email',
         label:'Email',
         key:11,
         name:'email',
         dbName:'email'
      ,
      dateOfJoin:
         type:'date',
         label:'Date Of Join',
         key:12,
         name:'dateOfJoin',
         dbName:'dateOfJoin'
      ,
      uploadPhoto:
         type:'blob',
         label:'Upload Image',
         key:13,
         name:'uploadPhoto',
         dbName:'croppedImage'
      
    

    class PostNew extends Component 
      constructor()
        super();
        this.renderField = this.renderField.bind(this);
        this.onCroppedImgData = this.onCroppedImgData.bind(this);
        this.valueChange = this.valueChange.bind(this);
        var stateData = [];
        var constructState='"croppedData":"undefined","header":"Registration Form","createdEditUser":false';
        _.each(FIELDS,(type,field)=>
           let dbState = type.dbName;
           constructState = constructState+',"'+dbState+'":""';
        );
        constructState = constructState + '';
        this.state = JSON.parse(constructState);
      
      componentWillMount()
        if(this.props.header)
          this.setState(header:this.props.header);
        
        if(this.props.userData)
          _.each(FIELDS,(type,field)=>
             let dbState = type.dbName;
             this.setState([dbState]:this.props.userData[dbState]);
          );
        
      
      callAttribute(field)
        return <Field label=field.label key=field.key type=field.type  name=field.name dbname=field.dbName component=this.renderField />
      
      onCroppedImgData(data)
      
        this.setState(croppedData:data);
      
      valueChange(e,dbName)
        this.setState([dbName]:e.currentTarget.value);
        this.props.dispatch(change('PostNewForm', [dbName], e.currentTarget.value));

      
      renderField(field)
        const meta:touched,error = field;
        const label,type,key,name,dbname = field;

        if(label === "Upload Image")
          let src;
          if(this.props.userData)
            src = this.props.userData[dbname];
          
           return(
              <div className="upload-image">
                  <UploadImage message="Upload Image" callbackImgCropped=this.onCroppedImgData profileImg=src/>
              </div>
           )
        else
          let val;
          let placeholder = 'Please enter your '+label;
          if(this.props.userData)

             val = this.state[dbname];
             if(dbname === "dateOfJoin")
              val = "";
             
          
          console.log("=====this.state[dbname]===",this.state[dbname]);
          return(
            <div className="field-div">
              <div >
                 <span className="label-name">label</span>
                 <input className="form-input" key=key type=type ...field.input  ref=name value=this.state[dbname] onChange=(e) => this.valueChange(e,dbname) placeholder=placeholder/>
                 <span className="error-msg">touched ? error : ' '</span>
              </div>
            </div>
          );
        

      
      onSubmit(obj)
        if(this.state.croppedData)
          obj.croppedImage = this.state.croppedData;
        
        if(this.props.userData)
          obj.id = this.props.userData.id;
          console.log("edit operation");
          this.props.editEmployee(obj,(data) => 
             this.setState(createdEditUser:data.status);
             this.props.reset();
          );
        else
          if(this.state.croppedData)
            obj.croppedImage = this.state.croppedData;
          
          this.props.addEmployee(obj,(data) => 
            this.setState(createdEditUser:true);
            this.props.reset();     
          );
        

      
      render()
        const  handleSubmit, pristine, reset, submitting  = this.props;
        if(this.state.createdEditUser)
          return( <Redirect to="/signin" /> );
        else
          return(
            <div className="form-div">
              <div className="form-header">this.state.header</div>
              <form className="employee-form" onSubmit=handleSubmit(this.onSubmit.bind(this))>
              _.map(FIELDS,this.callAttribute.bind(this))
              <div className="form-button">
                <button type="submit" disabled=submitting>
                  Submit
                </button>
                <button type="button" disabled=pristine || submitting onClick=reset>
                  Clear Values
                </button>
              </div>
              </form>
            </div>  
          );
        

      
    

    function validate(values)
       const errors = ;
       _.each(FIELDS,(type,field)=>
         if(!values[field] && type.type != "blob" && type.label !="Date Of Join")
          if(type.type == "email")
            errors[field] = `Enter an $field`;
          else
            errors[field] = `Enter a $field`;
          

         
         else if(type.type == "email" && values[field])
            if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]2,4$/i.test(values[field])) 
              errors[field] = 'Invalid email address'
            
          else if(type.name == "reenterpassword" && values[field]!==values['password'])
              errors[field] = 'Password mismatched.Please reenter password.';
          
      );
       return errors;
    

    export default reduxForm(
      validate,
      fields : _.keys(FIELDS),
      form:'PostNewForm'
    )(connect(null,addEmployee,editEmployee)(PostNew));

【讨论】:

以上是关于无法编辑文本输入反应 redux 表单的主要内容,如果未能解决你的问题,请参考以下文章

Redux 表单无法输入

如何避免或禁用 Redux 表单文本输入中的自动完成功能?

无法通过 React 和 Redux 将相同的表单组件用于添加或编辑模式

几种设置表单元素中文本输入框不可编辑的方法

反应表单错误将类型文本的受控输入更改为不受控制

React/Redux 中具有默认值的文本输入