2016-10-15 25 views
0

私は<input>のリストであるインターフェースを持っています。いずれかの入力でEnterキーを押すと、次の入力にフォーカスが移ります。最後の入力になっている場合は、もう1つを追加し、もう1つはフォーカスします。アイテムのリストはreduxによって管理されます。ここで 還元状態変更後のDOM操作の処理

は集中せずに、この純粋な部分を実行するコードです:

class ListItem extends Component { 
    render() { 
    return (
     <li> 
     <input 
      defaultValue={this.props.value} 
      onKeyUp={this.onKeyUp.bind(this)} 
      ref={(input) => this.input = input} 
     /> 
     </li> 
    ); 
    } 

    onKeyUp(event) { 
    this.props.onChange(event.target.value, event.keyCode === 13); 
    } 

    focus() { 
    this.input.focus(); 
    } 
} 


class List extends Component { 
    render() { 
    return (
     <ul> 
     {this.props.items.map((item, i) => 
      <ListItem 
      key={i} 
      value={item} 
      onChange={(value, enterPressed) => this.onChange(i, value, enterPressed)} 
      /> 
     )} 
     </ul> 
    ); 
    } 

    onChange(i, value, enterPressed) { 
    this.props.dispatch({ 
     type: 'UPDATE_ITEM', 
     index: i, 
     value: value 
    }); 
    if (enterPressed && i === this.props.items.length - 1) { 
     this.props.dispatch({ 
     type: 'ADD_ITEM' 
     }); 
    } 
    } 
} 

我々はそれを集中したいとき、次のリスト要素がまだ存在しない場合がありますので、これは、本当に難しいと思われるので、私たち何とかredux状態の変化が起こるまで待つ必要があり、リストは最後の項目と並び直します。

私が考えることができる唯一の方法は、リスト項目のそれぞれに参照配列を格納し、Enterを押したときにreduxイベントを送出し、コンポーネント状態でフォーカスされたリスト項目のインデックスを設定することです。次に、componentDidUpdate(redux状態が更新され、余分な入力がDOMにある場合に呼び出されます)で、どの入力をフォーカスする必要があるかを確認し、フォーカスメソッドを呼び出します。

class List extends React.Component { 
    constructor(props) { 
    super(props); 
    this.inputs = []; 
    } 

    render() { 
    return (
     <ul> 
     {this.props.items.map((item, i) => 
      <ListItem 
      key={i} 
      value={item} 
      onChange={(value, enterPressed) => this.onChange(i, value, enterPressed)} 
      ref={(input) => this.inputs[i] = input} 
      /> 
     )} 
     </ul> 
    ); 
    } 

    onChange(i, value, enterPressed) { 
    this.props.dispatch({ 
     type: 'UPDATE_ITEM', 
     index: i, 
     value: value 
    }); 
    if (enterPressed) { 
     this.setState({ 
     inputToFocus: i + 1 
     }) 
     if (i === this.props.items.length - 1) { 
     this.props.dispatch({ 
      type: 'ADD_ITEM' 
     }); 
     } 
    } 
    } 

    componentDidUpdate() { 
    if (typeof this.state.inputToFocus === 'number') { 
     this.inputs[this.state.inputToFocus].focus(); 
     this.setState({ 
     inputToFocus: null 
     }); 
    } 
    } 

これは本当に壊れやすいと醜い感じています。それを行うより良い方法はありますか?

完全な例はhttps://jsfiddle.net/69z2wepo/59903/です。

答えて

0

上記のようにリストにstateを使用するのではなく、propItをListItemに渡す必要があります。また、propアイテムがtrueの場合、リストアイテム自体がフォーカスすることができます。あなたが例えばisFocusedかどうかのフラグを含むように少しだけでなく、あなたの行動を変えることができるように:

{ 
    type: 'ADD_ITEM' 
    isFocused: true 
} 

{ 
    type: 'UPDATE_ITEM', 
    index: i, 
    value: value, 
    isFocused: false/true 
} 

それはより多くの仕事に見えるが、それは簡単にテストし、約理由するようになります小道具ではなく、状態を使用することがあります。

+0

ListItemはどのような方法でフォーカスする必要がありますか? isFocusedフラグがフォーカスされた後にunsetされますか? –

+0

これはcomponentDidMountとcomponentDidUpdate(同じコードを2回複製しないようにメソッドを呼び出すことができます)、本質的にif(this.props.isFocused)this.input.focusのようなものでなければなりません。 – luanped

+0

フラグがフォーカスされた後にフラグを解除する必要はありません。基本的には、propsを真実のソースにすることができます。ただ1つのListItemだけがisFocused trueを持つようにする必要があります。 – luanped

関連する問題