如何使选定的单选按钮基于另一个单选按钮更改另一种状态而更改一个状态?

时间:2020-02-14 07:10:05

标签: reactjs gatsby styled-components

我正在构建几个组件,并且遇到了一些绊脚石。

这些组件从钢琴键盘开始,我可以在钢琴键盘上叠加不同的音乐实体,例如音符,音程,和弦,音阶等,方法是通过notes={[]}数组道具将音符名称传递到{{ 1}}组件。然后,在该组件的特定实例中,将其导入到Keyboard组件中,在其中添加了音阶和音符按钮,因此可以在此实例的整个音阶上覆盖整个键盘,这基本上可以正常工作。有一个音符名称列表,我可以单击该音符名称,然后将该音阶覆盖在键盘上方,如下所示:

The gif shows the current behavior of the Scales component, which is not quite correct yet...

在gif中,您可以看到主要和次要音阶按钮更改了音阶的状态,然后音符名称按钮使用该音阶来更改其下方键盘的状态。但是我还希望它做的是单击主按钮或次按钮时切换当前选择的音阶,但是当前音符名称按钮不会自动响应主按钮和次按钮的状态变化,但是必须再次单击以进行更改。

我想要的是能够仅单击大调和小调按钮,并且无论选择哪个音符,都将简单地从大调更改为小调,而不必再次单击所选的音阶音符,这是当前的行为。 / p>

因此,在我的Scales组件中,我使用了像这样的自定义单选按钮,首先要控制主要和次要按钮:

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>

...并且通过两个useState挂钩建立状态,如下所示:

<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>

...然后,最终导入的const [ scale, setScale] = useState('') const [ notes, setNotes] = useState([]) 组件从注释按钮中接收到Keyboard道具,就像这样:

notes={notes}

...所以我真的不知道如何知道音符按钮或知道所单击的缩放按钮,然后将该信息转换为键盘<Keyboard octaves={'2'} notes={notes}/> 道具,这就是我所在的位置现在卡住了...

这是组件的代码沙箱:

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

谢谢您的帮助:-)

1 个答案:

答案 0 :(得分:0)

我查看了您的代码。

您现在遇到的问题是,单击主按钮时,笔记组件未重新渲染和重新设置样式。在React中,您可以使用props中的更改触发重新渲染,这也会重新设置笔记的样式。

我建议将您所有的笔记输入放到一个子组件中。 :

// ./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 Context。另外,您可以使用React Redux完成相同的操作。我建议使用Comtext,因为它是React的本机部分。

将您的应用分解为子组件看似不必要的工作,但在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>
  1. 从提供商那里获取并更新您的状态