以表格形式更新数据。保持可编辑。 (与Redux反应,sans redux-form)

时间:2017-04-25 21:59:57

标签: javascript forms reactjs redux react-redux

问题

enter image description here

我有一份人员名单。我想:

  1. 通过单击其名称选择要编辑的用户。
  2. 编辑该用户的信息,以便点击提交按钮并更新列表。
  3. 如果我点击其他名称,我想切换到该人的信息,而不必先故意关闭该表格。
  4. enter image description here

    一切正常,直到#3。当我点击另一个人时,表单本身不会更新。

    我的代码

    更新表单的

    更新组件

    const UpdateForm = ({ updatePerson, personToUpdate, handleInputChange }) => {
    
      let _name, _city, _age, _id;
    
      const submit = (e) => {
        e.preventDefault();
    
        updatePerson({
          name: _name.value,
          city: _city.value,
          age: _age.value,
          _id: _id.value
        });
    
      };
    
      return (
        <div>
          <form onSubmit={submit}>
            <h3>Update Person</h3>
            <label htmlFor="_id">Some Unique ID: </label>
            <input type="text" name="_id" ref={input => _id = input}  id="_id" defaultValue={personToUpdate._id} onChange={input => handleInputChange(personToUpdate)} required />
            <br />
            <label htmlFor="name">Name: </label>
            <input type="text" name="name" ref={input => _name = input} id="name" defaultValue={personToUpdate.name} onChange={input => handleInputChange(personToUpdate)} />
            <br />
            <label htmlFor="city">City: </label>
            <input type="text" name="city" ref={input => _city = input} id="city" defaultValue={personToUpdate.city} onChange={input => handleInputChange(personToUpdate)} />
            <br />
            <label htmlFor="age">Age: </label>
            <input type="text" name="age" ref={input => _age = input} id="age" defaultValue={personToUpdate.age} onChange={input => handleInputChange(personToUpdate)} />
            <br />
            <input type="submit" value="Submit" />
          </form>
    
        </div>
      );
    };
    
    export default UpdateForm;
    

    Person Component 的相关部分:

    class Person extends Component {
    
      nameClick() {
        if (this.props.person._id !== this.props.personToUpdate._id) {
          this.props.setForUpdate(this.props.person);
          this.forceUpdate();
        }
        else {
          this.props.toggleUpdatePersonPanel();
        }
    
      }
    
        render() {
            return (
              <div>
                <span onClick={this.nameClick}>
                    {this.props.person.name} ({this.props.person.age})
                </span>
              </div>
            );
        }
    }
    
    export default Person;
    

    PeopleList 的相关部分,其中包含人物:

    class PeopleList extends Component {
    
      render() {
        return(
          <div>
            {this.props.people.map((person) => {
              return <Person
                key={person._id}
                person={person}
                updatePersonPanel={this.props.updatePersonPanel}
                setForUpdate={this.props.setForUpdate}
                personToUpdate={this.props.personToUpdate}
                />;
            })}
          </div>
        );
      }
    
    } // end class
    
    export default PeopleList;
    

    Form Reducer ,仅提供相关操作:

    export default function formReducer(state = initialState.form, action) {
      let filteredPeople;
    
      switch (action.type) {
        case TOGGLE_UPDATE_PANEL:
          return Object.assign({}, state, { updatePersonPanel: false }, { personToUpdate: {
            _id: "",
            name: "",
            city: "",
            age: ""
          }});
        case SET_FOR_UPDATE:            
          return Object.assign({}, state, { personToUpdate: action.person }, { updatePersonPanel: true });
        case UPDATE_RECORD:
          filteredPeople = state.people.filter((person) => {
            return person._id === action.person._id ? false : true;
          }); // end filter
    
          return Object.assign({}, state, { people: [ ...filteredPeople, action.person] }, { personToUpdate: {
            _id: "",
            name: "",
            city: "",
            age: ""
          }}, { updatePersonPanel: false });
        case HANDLE_INPUT_CHANGE:
          return Object.assign({}, state, { personToUpdate: action.person });
        default:
          return state;
      }
    
    }
    

    我的初始状态档案的相关部分:

      form: {
        people: [
          {
            _id: "adfpnu64",
            name: "Johnny",
            city: "Bobville",
            age: 22
          },
          {
            _id: "adf2pnu6",
            name: "Renee",
            city: "Juro",
            age: 21
          },
          {
            _id: "ad3fpnu",
            name: "Lipstasch",
            city: "Bobville",
            age: 45
          }
        ],
        updatePersonPanel: false,
        personToUpdate: {
          _id: "",
          name: "",
          city: "",
          age: ""
        },
      }
    

    尝试解决方案(目前为止)

    • 我试图通过将表单属性切换为value而不是defaultValue来使组件成为完全受控的组件。当我这样做时,名称切换得很好,但形式变得无法改变和无用。

    我的问题

    几乎所有这类问题的解决方案都建议使用redux-form或者提供two-way binding solutions that work fine in React without reduce我想知道如何在不使用redux-form或其他任何额外内容的情况下使用Redux执行此操作。有没有办法在不触及生命周期方法的情况下解决此问题?

    结论(目前)

    好吧,现在,我决定让我的表单不受控制,并使用一些经典的Js DOM方法和生命周期方法来控制表单。无论出于何种原因,一旦我使用了一些答案建议,我的浏览器就会吃掉CPU并崩溃,大概是因为存在某种无限循环。如果有人有进一步的建议,我真的很感激。现在我满足于此:

    class UpdateForm extends Component {
    
      constructor(props){
        super(props);
    
        this.submit = this.submit.bind(this);
      }
    
      componentWillReceiveProps(nextProps) {
        if (nextProps.personToUpdate._id !== this.props.personToUpdate._id) {
          document.getElementById("name").value = nextProps.personToUpdate.name;
          document.getElementById("age").value = nextProps.personToUpdate.age;
          document.getElementById("city").value = nextProps.personToUpdate.city;
        }
    
      }
    
      submit(e) {
        e.preventDefault();
    
        this.props.updatePerson({
          name: document.getElementById("name").value,
          city: document.getElementById("city").value,
          age: document.getElementById("age").value,
          _id: this.props.personToUpdate._id
        });
      }
    
      render() {
        return (
          <div>
            <form onSubmit={this.submit}>
              <h3>Update Person</h3>
              Unique ID: {this.props.personToUpdate._id}
              <br />
              <label htmlFor="name">Name: </label>
              <input type="text" name="name" id="name" ref="name" defaultValue={this.props.personToUpdate.name} required />
              <br />
              <label htmlFor="city">City: </label>
              <input type="text" name="city" id="city" ref="city" defaultValue={this.props.personToUpdate.city} required />
              <br />
              <label htmlFor="age">Age: </label>
              <input type="text" name="age" id="age" ref="age" defaultValue={this.props.personToUpdate.age} required />
              <br />
              <input type="submit" value="Update" />
            </form>
    
          </div>
        );
      }
    } // end class
    
    export default UpdateForm;
    

    我很快就会探索redux-form,因为很明显,作为输入和输出的表单是一个不稳定的业务。现在,我的小应用程序正常工作。

1 个答案:

答案 0 :(得分:1)

是的,你正走在正确的道路上。方法是使用value而不是defaultValue,但您必须从状态读取value,然后使用onChange处理程序修改状态。

这样的东西
this.state = {inputText:''}

然后在输入字段

<input value={this.state.inputText} onChange={this.handleChange}/>

handleChange功能将是

handleChange(event){
   this.setState({inputText:event.target.value})
}

请记住在构造函数中绑定handleChange事件,以便您可以在输入字段this.handleChange道具中将其作为onChange传递。

像这样的东西

this.handleChange = this.handleChange.bind(this)

https://facebook.github.io/react/docs/forms.html - 这是关于它的官方文档

此外,如果您想在redux中执行此操作,则相同类型的逻辑适用于此输入字段

<input value={this.props.inputText} onChange={this.props.handleChange}/>

其中inputTexthandleChange是redux状态,并且操作分别通过props传递给组件

对于你的情况,我想它必须像你在哪里阅读&#39;来自people数组的值和action绑定到onChange的值会修改peoplestate数组中的值。

&LT; - 编辑 - &GT;

如何就此案件做到这一点。将redux状态的people作为people道具传递给组件。将操作changePeople(newPeople)作为支柱传递给组件,该支柱接受参数newPeople并将redux状态中的people更改为值newPeople。由于people嵌套在form中,您必须执行一些Object.assign等修改状态。

现在,在使用people道具的组件中,使用map函数填充复选框。 map函数接受第二个参数index,因此对于每个复选框都有一个函数,它将局部状态变量currentPerson设置为index的值

this.props.people.map((person,index) => 
    return <Checkbox onClick={()=>this.setState(currentPerson:index)}/>
) 

因此,每次点击复选框时,currentPerson都会指向相应的index

现在输入字段可以是

<input value={this.props.people[this.state.currentPerson].name} onChange={this.handleChange.bind(this,'name')}/>

这是针对&#39;名称&#39;输入字段。它从currentPerson数组的people索引读取,该数组已作为prop向下传递。

这就是handleChange的样子

handleChange(property,event){
  const newPeople = [
                    ...this.props.people.slice(0, this.state.currentPerson),
                    Object.assign({}, this.props.people[this.state.currentPerson], {
                        [property]: event.target.value
                    }),
                    ...this.props.people.slice(this.state.currentPerson + 1)
                    ]

  this.props.changePeople(newPeople)

}

handleChange获取属性(因此您不必为每个输入字段编写单独的处理程序)。 newPeople基本上修改了从this.state.currentPerson传递的people中当前索引props的元素(此处使用的是ES6语法。如果您有疑问,请询问)。然后使用changePeople动作调度它,该动作也作为道具传递。