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}], ], }, ];
问题原因及修复方案
核心问题
- Touche组件将props存入state,导致更新滞后:Touche在constructor中把
dataTouche等props存入自身state,后续props更新时,组件不会自动同步state,切换键盘配置后仍显示旧数据。 - 直接修改原数据对象,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={
相关产品推荐
相关产品推荐

