【问题标题】:Using Dynamic Var with `Set` State in React Hooks?在 React Hooks 中使用带有“Set”状态的动态 Var?
【发布时间】:2019-07-07 20:40:41
【问题描述】:

这是 React 组件中非常常见的模式:

handleTextFieldChange(event)
{
    const name = event.currentTarget.name;
    this.setState({[name]: event.currentTarget.value})
}

什么 Javascript 语法可以用来对 React 钩子做同样的事情?

即可能类似于:

handleTextFieldChange(event)
{
    const name = event.currentTarget.name;
    this.set[name](event.currentTarget.value);
}

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    您可以将单个 useState 与包含所有输入值的对象的默认值一起使用,并像使用类组件一样进行更新。

    示例

    const { useState } = React;
    
    function App() {
      const [state, setState] = useState({ email: "", password: "" });
      function onChange(event) {
        const { name, value } = event.target;
        setState(prevState => ({ ...prevState, [name]: value }));
      }
    
      return (
        <div>
          <input value={state.email} name="email" onChange={onChange} />
          <input value={state.password} name="password" onChange={onChange} />
        </div>
      );
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    
    <div id="root"></div>

    【讨论】:

    • 如果我们将每个状态键分组到一个对象中,我们会不会失去细粒度控制?当然,在 hooks 之前就是这样的
    • 经过数小时试图让更“物理”的条件状态发挥作用后,这个“隐形”案例对我有用。我的用例是尝试为在任何时间以任何数量存在或不存在的复选框制作处理程序,所以如果有人这样做(或类似的),这让我找到了正确的地方。
    【解决方案2】:
    class Yup extends React.Component {
      state = {
        first: "",
        second: ""
      };
    
      handleTextFieldChange = ({ target: { name, value } }) =>
        this.setState({ [name]: value });
    
      render() {
        const { first, second } = this.state;
        return (
          <div>
            <p>{first}</p>
            <p>{second}</p>
            <input type="text" name="first" onChange={this.handleTextFieldChange} />
            <input
              type="text"
              name="second"
              onChange={this.handleTextFieldChange}
            />
          </div>
        );
      }
    }
    

    与钩子相同

    function Yup() {
      const [{ first, second }, setState] = useState({ first: "", second: "" });
    
      function handleTextFieldChange({ target: { name, value } }) {
        setState(prevState => ({ ...prevState, [name]: value }));
      }
    
      return (
        <div>
          <p>{first}</p>
          <p>{second}</p>
          <input type="text" name="first" onChange={handleTextFieldChange} />
          <input type="text" name="second" onChange={handleTextFieldChange} />
        </div>
      );
    }
    

    【讨论】:

    • 很好的答案。从 class -> hook 的转换非常有用。
    【解决方案3】:

    这样的事情怎么样?

    function handleTextFieldChange(mySetFunction, event) {
        const value = event.currentTarget.value;
        mySetFunction(value);
    }
    
    <TextField
        placeholder="Email"
        name="passwordResetEmailAddress"
        onChange={(e) => handleTextFieldChange(setPasswordResetEmailAddress, e)}
    >
        {passwordResetEmailAddress}
    </TextField>
    

    我已经对其进行了测试,并且可以正常工作。

    【讨论】:

    • 我犹豫不决,因为添加额外代码会产生开销,但目前,这似乎是使用 hooks 的唯一方法
    【解决方案4】:

    我最近在将组件从类转换为函数时解决了同样的问题。我最终创建了一个对象,然后可以指向单独的状态挂钩:

    const textStates = {};
    const setTextStates= {};
    for (var name of names) {
      let [textState, setTextState] = useState("");
      textStates[name] = textState;
      setTextStates[name] = setTextState;
    }
    

    【讨论】:

      【解决方案5】:

      您可以通过在 onChange 函数中接收更新状态函数作为参数来动态更新目标字段的状态。

      示例

      import React, { useState } from "react";
      
      const App = () => {
        const [email, setEmail] = useState("");
        const [password, setPassword] = useState("");
      
        const onChangeHandler = (setIdentifierState, event) => {
          setIdentifierState(event.target.value);
        };
      
        return (
          <div>
            <p>{"Email: " + email}</p>
            <p>{"Password: " + password}</p>
            <input
              type="text"
              placeholder="email"
              onChange={onChangeHandler.bind(this, setEmail)}
            />
            <input
              type="text"
              placeholder="password"
              onChange={onChangeHandler.bind(this, setPassword)}
            />
          </div>
        );
      };
      
      export default App;
      
      
      
      

      【讨论】:

        【解决方案6】:

        我以这种方式解决了它(比@VikR 提供的更动态的解决方案)

        const [title, setTitle] = useState("");
        const [desc, setDesc] = useState("");
        const [video, setVideo] = useState("");
        
        const handleChange = setter => event => {
            const value = event.target.value;
            //special cases
            if (setter === setVideo) {
                setInvalidVideo(!ReactPlayer.canPlay(value))
            }
        
            setter(value)
        }
        

        然后在我的代码中:

                <TextField fullWidth value={title} type="date"
                           label={t('service.ticket.add.title')}
                           placeholder={t('service.ticket.add.titlePh')}
                           onChange={handleChange(setTitle)} variant="outlined"/>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-10-15
          • 1970-01-01
          • 2020-09-10
          • 2020-11-25
          • 1970-01-01
          • 2019-11-08
          • 2023-03-08
          • 1970-01-01
          相关资源
          最近更新 更多