将多个输入onChange反应为单个数组

时间:2018-05-17 23:46:48

标签: reactjs

我有一个状态,它是组件A中的一个数组。然后我有一个组件B(其道具是组件的状态),其中根据状态生成许多输入(类型文本) A.说3,然后我有3个输入类型的文本,它们包含在不同的组件和div中。我想知道我是否可以onChange获取所有三个值并将其添加到组件A中的数组?订单无关紧要。也许有一些东西比如获取这个div容器的子代,然后将它们的所有值onChange映射到一个数组中并设置状态?像这样的东西

编辑:

所以我写了这个,我可以看到名字是对的,但是我收到了这个错误:"警告:出于性能原因,这个合成事件会被重复使用。如果你看到这个,你正在访问已发布的财产目标...等等等等#34;。为什么我感觉我的setState不纯净。好的,我休息一下......

  onMultipleChange(e) {
        console.log(e.target.name);
        this.setState((prevState, props) => {
            let publicKeys = {...prevState.publicKeys, [e.target.name]: e.target.value};
            return {...prevState, publicKeys}
        }, console.log(this.state));
    }

动态设置refs:

refSetter = (ix) => (ref) => { this._refs[ix] = ref; };

2 个答案:

答案 0 :(得分:2)

警告:这是一种非常天真的做法,显然感觉很骇客,但仍然有效,并且是合法的。我确信有一种更好的方法并不依赖于refs

示例https://codesandbox.io/s/002o3275jl

组件A

class ComponentA extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      vals: []
    }
    this._refs = {};
  }

  onChange = () => {
    this.setState({
      vals: Object
        .keys(this._refs)
        .map(key => 
          this._refs[key] && 
          this._refs[key].value
        )
     });
  }

  render() {
    return (
      <div>
        All Vals: {this.state.vals.join(', ')}
        <ComponentB _ref={ref => this._refs['b'] = ref} onChange={this.onChange} />
        <ComponentC _ref={ref => this._refs['c'] = ref} onChange={this.onChange} />
        <ComponentD _ref={ref => this._refs['d'] = ref} onChange={this.onChange} />
      </div>
    )
  }
}

子组件

const ComponentB = ({_ref, onChange}) => (
  <input ref={_ref} onChange={onChange} type="text" />
);

const ComponentC = ({ _ref,  onChange }) => (
  <input ref={_ref} onChange={onChange} type="text" />
);

const ComponentD = ({ _ref,  onChange }) => (
  <input ref={_ref} onChange={onChange} type="text" />
);

答案 1 :(得分:1)

我建立在@ lux的答案上(我的意思是我实际上采用了他的例子,并修改了它)并提出了一个不涉及refs的替代方案。

就在最近,我了解到React的SyntheticEvent(每次都重复使用)可以保留,这意味着它被从事件池中取出,即使其他事件发生,也可以保留引用被解雇。这就是我最终的结果:

class ComponentA extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      vals: [
        {
          name: "ComponentB",
          value: ""
        },
        {
          name: "ComponentC",
          value: ""
        },
        {
          name: "ComponentD",
          value: ""
        },
      ]
    }
  }

  onChange = e => {
    e.preventDefault();
    e.persist();
    this.handleMultipleChanges(e);
  }

  handleMultipleChanges = e => {
    let currentInput = this.state.vals.find(val => val.name === e.target.name);
    currentInput.value = e.target.value;
    this.setState(prevState => ({
      ...prevState,
      vals: prevState.vals.map(val => val.name === currentInput.name ? currentInput : val)
    }));
  }

  render() {
    return (
      <div style={styles}>
        AllVals: {this.state.vals.map(val => val.value).join(", ")}
        <div><ComponentB name="ComponentB" onChange={this.onChange} /></div>
        <div><ComponentC name="ComponentC" onChange={this.onChange} /></div>
        <div><ComponentD name="ComponentD" onChange={this.onChange} /></div>
      </div>
    )
  }
}

const ComponentB = ({name, onChange}) => (
  <input name={name} onChange={onChange} type="text" />
);

const ComponentC = ({name, onChange }) => (
  <input name={name} onChange={onChange} type="text" />
);

const ComponentD = ({name, onChange }) => (
  <input name={name} onChange={onChange} type="text" />
);

修改

这是一个(非常基本的)变体,通过数字输入动态添加输入,因为这是OP的用例:

class ComponentA extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      inputNumber: 0,
      vals: []
    }
  }

  onChange = e => {
    e.preventDefault();
    e.persist();
    this.handleMultipleChanges(e);
  }

  handleMultipleChanges = e => {
    let currentInput = this.state.vals.find(val => val.name === e.target.name);
    if (!currentInput) {
      currentInput = {
        name: e.target.name,
        value: e.target.value
      }
      this.setState({vals: this.state.vals.concat(currentInput)});
    } else {
      currentInput.value = e.target.value;
      this.setState(prevState => ({
        ...prevState,
        vals: prevState.vals.map(val => val.name === currentInput.name ? currentInput : val)
      }));
    }
  }

  createInputs = e => {
    const {inputNumber} = this.state;
    const vals = [];

    for (let i = 0; i<inputNumber; i++) {
      vals[i] = {name: "input"+i, value:""};
    }

    this.setState({vals});
  }

  render() {
    return (
      <div>
        AllVals: {this.state.vals.map(val => val.value).join(", ")}
        <div>
        <input type="number" onChange={e => this.setState({inputNumber: e.target.value})} />
        <button onClick={this.createInputs}>Make Inputs</button>
        </div>
        {this.state.vals.map(
          val => <div><input name={val.name} value={val.value} onChange={this.onChange} /></div>
        )}
      </div>
    )
  }
}