Обрабатывать заполнение состояния из нескольких флажков - PullRequest
0 голосов
/ 30 января 2020

У меня есть форма, которая строит список флажков на основе некоторых данных:

<fieldset className="visibility">
        <div className="input-container checkbox">
          <span className="label">Visible to</span>
          <ul>
            {
              allForces.map(force => {
                if (force.name !== 'White' && force.name !== currentMarkerForce) {
                  return (
                    <li key={force.uniqid}>
                      <label>
                        <input onChange={handleVisibilityChange} name={`visibility-${_.kebabCase(force.name)}`} type="checkbox" value={force.name} checked={markerVisibleTo.includes(force.name) }/>
                        {force.name} cell
                      </label>
                    </li>
                  )
                }
              })
            }
          </ul>
        </div>
      </fieldset>

Поскольку обычно появляется как минимум 2 элемента, которые можно проверить, я написал для них обработчик который заполняет массив перед отправкой обратно в состояние, содержимое этого массива изначально заполняется из существующего состояния:

 const visibilityChecked = [...markerVisibleTo]

  const handleVisibilityChange = ({ target }) => {
    const { checked, value } = target
    checked ? visibilityChecked.push(value) : visibilityChecked.pop(value)
    setMarkerVisibleTo(visibilityChecked)
}

Последняя строка - это вызов useState hook, это в основном работает, но иногда я получаю странное поведение, когда установлен неправильный флажок:

An example of the bug

Может кто-нибудь помочь помочь пролить свет на то, что вызывает эту проблему?

1 Ответ

1 голос
/ 30 января 2020

Я могу предположить, что это происходит потому, что обновление состояния происходит асинхронно, и к тому времени, когда вы пытаетесь применить изменения с помощью setMarkerVisibleTo(), ваше состояние отличается от того, которое вы предполагаете, вы можете попытаться поместить const visibilityChecked = [...markerVisibleTo] в handleVisibilityChange() body:

const handleVisibilityChange = ({ target }) => {
    const visibilityChecked = [...markerVisibleTo]
    const { checked, value } = target
    checked ? visibilityChecked.push(value) : visibilityChecked.pop(value)
    setMarkerVisibleTo(visibilityChecked)
}

Или, как я написал бы, что:

const handleVisibilityChange = ({target:{checked,value}}) => {
    const visibilityChecked = checked ? 
        [...markerVisibleTo, value] : 
        [...markerVisibleTo].filter(val => val != value)
    setMarkerVisibleTo(visibilityChecked)
}

Здесь вы можете найти полную демонстрацию:

//dependencies
const { render } = ReactDOM,
      { useState } = React

//mocking source data      
const checkItems = [...'abcd']      

//check list component
const CheckList = ({items}) => {
  const [visibleMarkers, setVisibleMarkers] = useState(checkItems),
        onVisibilityChange = ({target:{checked,value}}) => {
            const visibilityChecked = checked ? 
                [...visibleMarkers, value] : 
                [...visibleMarkers].filter(val => val != value)
            setVisibleMarkers(visibilityChecked)
        }
  return (
  <div>
      <ul>
        {
          items.map((item,key) => (
            <li {...{key}}>
              <label>
                Option {item}
                <input 
                  type="checkbox" 
                  value={item} 
                  checked={visibleMarkers.includes(item)}
                  onChange={onVisibilityChange}
                />
              </label>
            </li>
          ))
        }
      </ul>
      <span>visibleMarkers: {JSON.stringify(visibleMarkers)}</span>
  </div>
  )
}

//render
render (
  <CheckList items={checkItems} />,
  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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...