将子组件点击处理程序绑定到父状态

时间:2020-01-23 12:32:52

标签: javascript reactjs

其他SO答案都无济于事,所以我认为我在概念上缺少一些东西。

我有一个“父”(包装)组件和一个“子”(输入)组件。父母将功能传递给孩子:

const Wrapper = () => {
  const [dictionary, setDictionary] = useState([{ word: "init", definition: "def init" }]);

  const handleWordChange = (e, value) => {
    e.preventDefault();

    /// IS NEVER TRIGGERED
  };

  return (
    <Input setDictionary={{ setDictionary }} onChange={handleWordChange} />
  )
}

子组件处理自己的状态,但应该通过调用setDictionary函数来更新“父”道具:

const Input = props => {
  const [definition, setDefinition] = useState("");
  const [word, setWord] = useState("");

  const handleSubmit = e => {
    const { setDictionary } = props.setDictionary;
    e.preventDefault();
    setDictionary([{ word, definition }]);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        name='word'
        onChange={e => setWord(e.target.value)}
        onFocus={() => setWord("")}
        placeholder='Word'
        type='text'
        value={word}
      />

      <input
        name='definition'
        onChange={e => setDefinition(e.target.value)}
        onFocus={() => setDefinition("")}
        placeholder='Definition'
        type='text'
        value={definition}
      />
      <input type='submit' value='Submit' />
    </form>    
  )
}

我看到的其他答案建议将回调传递给Child(setDictionary),但是永远不会在更改时调用onChange处理程序。我也尝试使用onSubmit代替。

如何成功更新dictionary? 我知道上面创建了子代对父代的依赖关系,考虑到我最终需要将dictionary传递给第二个子代,是否有更好的编程方式来实现这一点?

4 个答案:

答案 0 :(得分:0)

您甚至都不会触发传递给组件的onChange

  <Input setDictionary={{ setDictionary }} onChange={handleWordChange} />

您必须像命名props.onChange

一样正确地命名道具
//there is no props.onChange here in this component

const Input = props => {
  const [definition, setDefinition] = useState("");
  const [word, setWord] = useState("");

  const handleSubmit = e => {
    const { setDictionary } = props.setDictionary;
    e.preventDefault();
    setDictionary([{ word, definition }]);
    //like here
    props.onChange(any arguments);

  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        name='word'
        onChange={e => setWord(e.target.value)}
        onFocus={() => setWord("")}
        placeholder='Word'
        type='text'
        value={word}
      />

      <input
        name='definition'
        onChange={e => setDefinition(e.target.value)}
        onFocus={() => setDefinition("")}
        placeholder='Definition'
        type='text'
        value={definition}
      />
      <input type='submit' value='Submit' />
    </form>    
  )
}

如果我重命名

 <Input setDictionary={{ setDictionary }} onInputChanged={handleWordChange} />

我会这样称呼

const handleSubmit = e => {
    const { setDictionary } = props.setDictionary;
    e.preventDefault();
    setDictionary([{ word, definition }]);
    //like here
    props.onInputChanged(any arguments);

  }

答案 1 :(得分:0)

//there is not props.onChange here in this component

const Input = props => {
  const [definition, setDefinition] = useState("");
  const [word, setWord] = useState("");

  const handleSubmit = e => {
    const { setDictionary } = props.setDictionary;
    e.preventDefault();
    setDictionary([{ word, definition }]);
    //like here
    props.onChange(any arguments);

  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        name='word'
        onChange={e => {
          setWord(e.target.value)
         props.onChange();
        }}
        onFocus={() => setWord("")}
        placeholder='Word'
        type='text'
        value={word}
      />

      <input
        name='definition'
        onChange={e => {
    setDefinition(e.target.value)
              props.onChange();
    }}
        onFocus={() => setDefinition("")}
        placeholder='Definition'
        type='text'
        value={definition}
      />
      <input type='submit' value='Submit' />
    </form>    
  )
}

在输入组件中使用父级onChange()方法,如果您未调用该方法,将会触发该方法,希望它会如何触发。

答案 2 :(得分:0)

您不能通过这种方式分配孩子的onChange()事件处理程序。

相反,您将子事件处理程序称为道具,并将父回调绑定到这些道具。

这个概念被称为lifting state up

完整的用例演示,您可以在下面找到:

const { render } = ReactDOM,
      { useState } = React
      
const Input = ({onInput}) => {
  const [word, setWord] = useState(''),
        [definition, setDefinition] = useState('')
  return (
        <form onSubmit={e => (e.preventDefault(), onInput(word, definition))}>
          <label>
            Word: 
            <input onChange={({target:{value}}) => setWord(value)} />
          </label>
          <label>
            Definition: 
            <input onChange={({target:{value}}) => setDefinition(value)} />
          </label>
          <input type="submit" value="Submit" />
        </form>
  )
}

const List = ({list}) => (
  <ul>
    {
      list.map(({word,definition},key) => <li {...{key}}><strong>{word}</strong> - {definition}</li>)
    }
  </ul>
)

const Parent = () => {
  const [dictionary, setDictionary] = useState([]),
        onDicionaryItemSubmit = (word,definition) => setDictionary([...dictionary, {word,definition}])
   return (
    <div>
      <Input onInput={onDicionaryItemSubmit} />
      <List list={dictionary} />
    </div>
   )
}

render (
  <Parent />,
  document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>

答案 3 :(得分:0)

错误:-没有在onChange中调用<Input/>函数,而在<Wrapper />中设置了字典状态。
这是您查询的有效解决方案。

const {useState} = React;
const Wrapper = () => {
  const [dictionary, setDictionary] = useState([
    { word: "computer", definition: "an electronic device for storing and processing data" }
  ]);

  const handleWordChange = (e, value) => {
    e.preventDefault();
    let updateDictionary = [...dictionary];
    updateDictionary.push(value);
    setDictionary(updateDictionary);
    // console.log(updateDictionary);
    /// IS NEVER TRIGGERED
  };

  return (
    <React.Fragment>
      <Input onChange={handleWordChange} />
      {dictionary.length > 0 ? (
        <table>
          <tr>
            <th>WORD</th>
            <th>DEFINITION</th>
          </tr>
          {dictionary.map(datum => (
            <tr>
              <td>{datum.word}</td>
              <td>{datum.definition}</td>
            </tr>
          ))}
        </table>
      ) : null}
    </React.Fragment>
  );
};

const Input = props => {
  const [definition, setDefinition] = useState("");
  const [word, setWord] = useState("");

  const handleSubmit = e => {
    e.preventDefault();
    props.onChange(e, { word, definition });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="word"
        onChange={e => setWord(e.target.value)}
        onFocus={() => setWord("")}
        placeholder="Word"
        type="text"
        value={word}
      />

      <input
        name="definition"
        onChange={e => setDefinition(e.target.value)}
        onFocus={() => setDefinition("")}
        placeholder="Definition"
        type="text"
        value={definition}
      />
      <input type="submit" value="Submit" />
    </form>
  );
};

ReactDOM.render(<Wrapper />, document.getElementById('root'));
table,
th,
td {
  border: 1px solid black;
}
table {
  margin-top: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>