You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React切换键盘配置时子组件未正确刷新问题求助

React手风琴配置器切换键盘配置后组件不刷新问题

我正在开发一款手风琴配置器,刚接触React。我创建了三个类组件:

  • Touche:管理4个下拉选择器(note pull、note push、octavePull、octavePush)
  • Keyboard:展示所有Touche组件
  • KeyboardManager:展示当前键盘及键盘配置选择器

KeyboardManager中的finalKeyboard可通过Touche组件修改,但切换KeyboardManager中的键盘配置选择器时,Keyboard子组件无法获取正确值并刷新。不清楚原因,相关代码如下:

Touche组件代码

class Touche extends React.Component {
  constructor(props) {
    super(props);
    
    this.state = {
      ligne: props.ligne,
      colonne: props.colonne,
      handleChange: props.onChange,
      dataTouche : props.dataTouche,
    };
  }

  handleChangeNotePull(event) {
     this.state.handleChange('note','pull', event, this.state)
  }
  handleChangeNotePush(event) {
    this.state.handleChange('note', 'push', event, this.state)
  }
  handleChangeOctavePull(event) {
    this.state.handleChange('octave', 'pull', event, this.state)
  }
  handleChangeOctavePush(event) {
    this.state.handleChange('octave', 'push', event, this.state)
  }

  render() {
    return <td>
      <table>
        <tbody>
          <tr>
            <td>
              <Select options={options} value={options[this.state.dataTouche.pull]} onChange={this.handleChangeNotePull.bind(this)} />
              <Select options={options} value={options[this.state.dataTouche.push]} onChange={this.handleChangeNotePush.bind(this)} />
            </td>
            <td>
              <Select options={optionOctave} value={optionOctave[this.state.dataTouche.octpull]} onChange={this.handleChangeOctavePull.bind(this)} />
              <Select options={optionOctave} value={optionOctave[this.state.dataTouche.octpush]} onChange={this.handleChangeOctavePush.bind(this)} />
            </td>
          </tr>

       </tbody>
      </table>
    </td>; 
  }
}

Keyboard组件代码

class Keyboard extends React.Component {
  constructor(props) {
    super(props);
    console.log('constructor keyboard')
    this.state = {
      handleChangeTouche: props.onChange,
    }
  }
  handleChange = (type, pushpull, event, buttonState) => {
    this.state.handleChangeTouche(type, pushpull ,event, buttonState)
  }
  render() {    
    return (    
      this.props.keyboard.map((row, index) =>
        <tr key={index}>
          <Touche dataTouche={row[0]} onChange={this.handleChange} ligne={index} colonne={0}></Touche>
          <Touche dataTouche={row[1]} onChange={this.handleChange} ligne={index} colonne={1}></Touche>
          <Touche dataTouche={row[2]} onChange={this.handleChange} ligne={index} colonne={2}></Touche>
        </tr>
      )
    )
  }
}

KeyboardManager组件代码

class KeyboardManager extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedKeyboard: 1,
      finalKeyboard : instrumentKeyboardData[1].keyboard,
    }; 
  }

  handleChangeKeyboard(event) {
    this.setState({
      selectedKeyboard: event.value
    })
    var tempKeyboard =  instrumentKeyboardData[event.value].keyboard
    this.setState({
      finalKeyboard : tempKeyboard
    })
  }

  handleChangeTouche(type, pushpull, e, buttonState) {
    if(type === 'note'){
      var tempKeyboard = this.state.finalKeyboard
      tempKeyboard[buttonState.ligne][buttonState.colonne][pushpull] = e.value
      this.setState({
        finalKeyboard : tempKeyboard
      })
    }
  }
  render() {
    return (
      <div>
        <Select
          options={instrumentKeyboardData}
          value={instrumentKeyboardData[this.state.selectedKeyboard]}
          onChange={this.handleChangeKeyboard.bind(this)}
        />
        <table>
          <tbody>
            <Keyboard keyboard={this.state.finalKeyboard} onChange={this.handleChangeTouche.bind(this)}/>
          </tbody>
        </table>
      </div>
    );
  }
}

手风琴数据

const instrumentKeyboardData = [
  {
    value: 0, 
    label: 'Concertina',
    keyboard : [
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
      [{ push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}, { push: 4, pull: 4 , octpull : 1, octpush : 1}],
    ],
  },
  {
    value: 1,
    label: 'Chroma',
    keyboard: [
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
      [{ push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}, { push: 5, pull: 5 , octpull : 1, octpush : 1}],
    ],
  },
  {
    value: 2,
    label: 'Diato',
    keyboard: [
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
      [{ push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}, { push: 6, pull: 6 , octpull : 1, octpush : 1}],
    ],
  },
  
];

问题原因及修复方案

核心问题

  1. Touche组件将props存入state,导致更新滞后:Touche在constructor中把dataTouche等props存入自身state,后续props更新时,组件不会自动同步state,切换键盘配置后仍显示旧数据。
  2. 直接修改原数据对象,React无法检测变化:切换键盘和修改按键时,直接引用instrumentKeyboardData中的原数组/对象,或直接修改state中的数组元素,React的浅比较机制会判定state未变化,不触发重渲染。

修复步骤

1. 改造Touche组件,直接使用props

移除constructor中对props的state存储,直接使用props,确保props更新时组件自动渲染最新值:

class Touche extends React.Component {
  handleChangeNotePull(event) {
     this.props.onChange('note','pull', event, this.props)
  }
  handleChangeNotePush(event) {
    this.props.onChange('note', 'push', event, this.props)
  }
  handleChangeOctavePull(event) {
    this.props.onChange('octave', 'pull', event, this.props)
  }
  handleChangeOctavePush(event) {
    this.props.onChange('octave', 'push', event, this.props)
  }

  render() {
    const { dataTouche } = this.props;
    return <td>
      <table>
        <tbody>
          <tr>
            <td>
              <Select options={
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 23:45:40