Как сделать так, чтобы выбранный переключатель переключал один элемент состояния на основе другого переключателя, изменяющего другой элемент состояния? - PullRequest
1 голос
/ 14 февраля 2020

У меня есть пара компонентов, которые я строю, и наткнулся на камень преткновения.

Компоненты начинаются с клавиатуры пианино, на которой я могу накладывать различные музыкальные объекты, такие как ноты, интервалы, аккорды, гаммы и т. д. c ... путем передачи имен заметки через массив notes={[]} в компонент Keyboard. В этом конкретном экземпляре компонента я затем импортирую его в компонент Scales, в который я добавил кнопки масштабирования и заметки, чтобы в этом случае я мог наложить целые шкалы на верхнюю часть клавиатуры, что в принципе работает. у меня есть список имен заметок, по которым я могу щелкнуть, а затем наложить этот масштаб на верхнюю часть клавиатуры, например:

GIF показывает текущее поведение компонента Scales, который не пока что вполне корректно ...

В gif вы можете видеть, что кнопки основной и вспомогательной шкалы изменяют состояние шкалы, которое затем используется кнопками имени заметки для изменения состояния клавиатура под ним. Но то, что я также хочу, это переключить выбранный в настоящее время масштаб при нажатии основной или вспомогательной кнопки, но в настоящее время кнопки имени примечания не реагируют автоматически на изменение состояния в основных и вспомогательных кнопках, но должны быть нажмите еще раз, чтобы изменения произошли.

Мне нужно просто нажать основные и второстепенные кнопки, и любая выбранная нота просто изменится с основной на второстепенную без необходимости повторного нажатия на выбранную Снова масштабируем заметку, которая является текущим поведением.

Итак, в моем компоненте Scales я использую настраиваемые переключатели, например, сначала для управления основными и вспомогательными кнопками:

<MajorInput
  type="radio"
  name="scale"
  id="major"
  label="major"
  value="major"
  checked={scale === 'major'}
  onChange={handleChange}
  onClick={() => setScale('major')}
/>
<MajorLabel
  whileHover={{ scale: 1 }}
  whileTap={{ scale: 0.9 }}
  htmlFor="major"
>
  Major
</MajorLabel>

. ... затем для управления кнопками заметки, например:

<NoteInput
  id="c"
  scale={scale}
  type="radio"
  name="notes"
  label="c"
  value="c"
  onClick={
    () => setNotes(
      scale === 'major' ? ['c1p', 'd1ma', 'e1ma', 'f1p', 'g1p', 'a1ma', 'b1ma'] :
      scale === 'minor' ? ['c1p', 'd1ma', 'eb1mi', 'f1p', 'g1p', 'ab1mi', 'bb1mi'] :
      ''
    )
  }
/>
<NoteLabel
  whileHover={{ scale: 1 }}
  whileTap={{ scale: 0.9 }}
  scale={scale}
  htmlFor="c"
>
{
  scale === 'major' ? 'C' :
  scale === 'minor' ? 'C' :
  'C'
}
</NoteLabel>

... и состояние устанавливается с помощью двух перехватчиков useState, например:

const [ scale, setScale] = useState('')

const [ notes, setNotes] = useState([])

... then в конечном итоге импортированный Keyboard компонент получает notes={notes} реквизит от кнопок заметок, например:

<Keyboard octaves={'2'} notes={notes}/>

... так что я не знаю, как сделать заметку, но тонны знать или знать о нажатых кнопках весов, а затем транслировать эту информацию на клавиатуры notes prop, где я застрял сейчас ...

Вот песочница для кода компонента:

https://codesandbox.io/s/scales-981uk

Спасибо за помощь: -)

1 Ответ

0 голосов
/ 14 февраля 2020

Я просмотрел твой код.

Проблема, с которой вы столкнулись сейчас, заключается в том, что ваши компоненты заметки не перерисовываются и не изменяют стиль при нажатии основной кнопки. В React вы можете использовать изменения в реквизите, чтобы запустить рендеринг, который также приведет к изменению стиля ваших заметок.

Я бы посоветовал поместить все входные данные ваших заметок в подкомпонент. :

// ./Scales.js

import NoteButtonBox from ./NoteButtonBox.js

//...

// important: pass scale as props. 
// Everytime scale changes, the note buttons are rerendered and restyled
sub component
  return (
    <Container>
      <ScaleButtonBox>
        {/* ... */}
      <ScaleButtonBox>
      <NoteButtonBox scale={scale} />
      {/* ... */}
// ./NoteButtonBox.js


const NoteButtonBox = ({scale}) => {
   // Don't forget to also move 'const [notes, setNotes] = useState([]);' into the 
  const [notes, setNotes] = useState([]);
  return { 
    /* return your styled notes based on props scale */
  }
}

РЕДАКТИРОВАТЬ

В ситуациях, когда вам необходимо получить доступ к состоянию между несколькими подкомпонентами, вы можете использовать Контекст реагирования . Кроме того, вы можете использовать React Redux , который выполняет то же самое. Я бы предложил Comtext, потому что он является родной частью React.

Разделение вашего приложения на подкомпоненты может показаться ненужной работой, но хорошей практикой является создание множества небольших компонентов в React. Реакт поощряет композицию, как я предлагаю.

  1. Создание класса NotesStateContext.
  2. Вы определяете, где это необходимо NotesStateContext.Provider:
      <NotesStateContext.Provider value="dark">
        <NoteButtonBox />
        </* All other components that need to access the state of your notes */>
      </NotesStateContext.Provider>
Получите и обновите свой штат у провайдера
...