【问题标题】:Javascript, react hooks: access member property of member object using same functionJavascript,反应钩子:使用相同的功能访问成员对象的成员属性
【发布时间】:2020-08-18 09:00:47
【问题描述】:

我有一个基本问题是访问成员对象的属性。

state.group - 好的 state.person(object) - 不行

这是一个反应示例代码:

https://codesandbox.io/s/access-perperty-of-member-2hm4e?file=/src/App.js

我制作了具有 setState 的 updateState 函数。 此函数正在读取名称和值对并更新状态。 如果成员直接具有价值,则可以更新。 但是如果成员是一个具有属性的对象,那么最好的代码是什么? 我想为所有情况保留“updateState”功能。

  1. 这里是更新状态的主要功能

    函数更新状态(e){ 让名称 = e.target.name; 让值 = e.target.value; setState({ ...state, [name]: value }); }

  2. 好的:

    <input
            type="textbox"
            name="group"
            value={state.group}
            onChange={updateState}
          />
    
  3. 不行:

    <input
            type="textbox"
            name="person.name"
            value={state.person.name}
            onChange={updateState}
          />
    
    • No.3 正在创建另一个名为“person.name”的成员。我的期望是访问与 state.person.name 相同的 state.person['name']。

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    它应该是state["person.name"],因为“person.name”是用于存储值的键。 Javascript 对象是键值对的关联数组。

    const state = {};
    state["person.name"] = "some value";
    console.log(state);
    console.log(state["person.name"]);

    给定处理程序:

    function updateState(e) {
      const { name, value } = e.target;
      setState({ ...state, [name]: value });
    }
    

    输入值应该是:

    <input
      type="textbox"
      name="person.name"
      value={state["person.name"]}
      onChange={updateState}
    />
    

    如果您有一个更复杂的状态形状,即具有不同深度属性的对象,那么您需要设计您的处理程序以匹配每个 可以更新的属性,为每种类型创建单独的处理程序更新、将您的状态拆分为更易于管理的块、使用 action/reducer 模式等...

    这是一个将状态拆分为深度不超过 2 的块(即 1 级嵌套)的示例:

    export default function App() {
      const [group, setGroup] = useState('A1');
      const [person, setPerson] = useState({
        name: "xyz",
        age: 31
      });
    
      const updateState = stateObject => e => {
        const { name, value } = e.target;
    
        switch(stateObject) {
          case 'group':
            setGroup(value);
            return;
          case 'person':
            setPerson(person => ({ ...person, [name]: value }));
            return;
          default:
            // ignore
        }
      }
    
      useEffect(() => {
        console.log(group, person);
      });
    
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
          <label>Group</label>
          <input
            type="textbox"
            name="group"
            value={group}
            onChange={updateState('group')}
          />
          <hr />
          <label>Name</label>
          <input
            type="textbox"
            name="name"
            value={person.name}
            onChange={updateState('person')}
          />
        </div>
      );
    }
    

    在这里,我拆分了状态并创建了一个 curried 处理程序,将其处理的状态“区域”作为第一个参数,第二个参数是事件对象。状态区进入 switch 语句,以特定方式处理该状态。

    【讨论】:

    • 这不适用于多深度对象情况。
    • @SGSNETWORKS 它基于您问题中提供的信息,这就是对象的工作方式。 Javascript 对象是键值对的关联数组。如果您有复杂对象形状的状态,那么您需要处理程序来匹配。我会更新答案。
    【解决方案2】:

    useState 仅用于获取状态的一部分,并且由于您的状态是嵌套对象,因此在这种情况下,如果您使用 useReducerhere 会更好,您可以看到该样式的代码框的分支,但代码是这样的:

    function reducer(state, action) {
      switch (action.type) {
        case "group":
          return { ...state, group: action.payload };
        case "personName":
          return { ...state, person: { ...state.person, name: action.payload } };
        default:
          return state;
      }
    }
    
    export default function App() {
      const [state, dispatch] = useReducer(reducer, {
        group: "A1",
        person: {
          name: "xyz",
          age: 31
        }
      });
    
      if (state) {
        console.log(state);
      }
    
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
          <label>Group</label>
          <input
            type="textbox"
            name="group"
            value={state.group}
            onChange={e => dispatch({ type: "group", payload: e.target.value })}
          />
          <hr />
          <label>Name</label>
          <input
            type="textbox"
            name="person.name"
            value={state.person.name}
            onChange={e =>
              dispatch({ type: "personName", payload: e.target.value })
            }
          />
        </div>
      );
    }
    
    

    如果你的表单会变大,你可以使用 formik 之类的东西来管理它。

    【讨论】:

    • 在我的情况下,花费 onChange 事件将是简化代码的额外努力。
    【解决方案3】:

    我像这样更新了“updateState”函数。

    let name = e.target.name;
    let value = e.target.value;
    let objnames = name.split(".");
    let obj = state;
    let objdepth = objnames.length;
    if (objdepth > 0) {
      for (let idx = 0; idx < objdepth; idx++) {
        if (idx + 1 === objdepth) obj[objnames[idx]] = value;
        obj = obj[objnames[idx]];
      }
    }
    setState({ ...state });
    

    此功能解决了多深度会员访问问题。 这是一个复杂状态访问案例的沙箱。

    https://codesandbox.io/s/access-nested-perperty-of-member-2f3wp?file=/src/App.js:651-1048

    如果有人有更好的想法,请与我们分享。

    谢谢。

    【讨论】:

      猜你喜欢
      • 2011-04-07
      • 2010-12-16
      • 1970-01-01
      • 2021-11-13
      • 1970-01-01
      • 1970-01-01
      • 2020-10-02
      • 2013-02-19
      • 2014-08-21
      相关资源
      最近更新 更多