Javascript, реагировать на ловушки: получить доступ к свойству члена объекта-члена с помощью той же функции - PullRequest
1 голос
/ 04 мая 2020

У меня есть базовый c вопрос для доступа к свойству объекта члена.

state.group - OK state.person (объект) - Не в порядке

Вот Пример кода реакции:

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

Я сделал функцию updateState, которая имеет setState. Эта функция читает пару имя-значение и состояние обновления. Если член имеет значение напрямую, это нормально для обновления. Но если член является объектом, обладающим свойствами, какой код будет лучшим? Я хочу сохранить функцию 'updateState' для всех случаев.

  1. Вот основная функция для обновления состояния

    function updateState (e) {let name = e.target.name; let value = e.target.value; setState ({... состояние, [имя]: значение}); }

  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.

Ответы [ 3 ]

1 голос
/ 04 мая 2020

Это должно быть 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}
/>

Если у вас более сложная форма состояния, то есть объект со свойствами различной глубины, тогда вам нужно спроектировать свой обработчик так, чтобы он соответствовал каждому свойству, которое можно обновить, создать отдельные обработчики для каждого типа обновления, разделить ваше состояние на более легкие в управлении чанки, использовать шаблон действия / редуктора, et c ...

Вот пример разделения состояния на куски глубиной не более 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>
  );
}

Edit access nested perperty of member

Здесь я разделил состояние и создал обработчик карри, который принимает в качестве первого параметра «область» состояния, которое он обрабатывает, а второй - событие объект. Область состояний входит в оператор switch для обработки этого состояния определенным c образом.

0 голосов
/ 04 мая 2020

Я обновил функцию '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

, если у кого есть идея Пожалуйста, поделитесь им с нами.

Спасибо.

0 голосов
/ 04 мая 2020

useState используется, чтобы взять только одну часть состояния, и поскольку ваше состояние является вложенным объектом, в этом случае было бы лучше, если вы используете useReducer, здесь , вы можете увидеть форк вашего codesanbox в этом стиле, но код выглядит примерно так:

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 для управления ею.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...