2017-01-05 8 views
0

ユーザーがxhrを使用してデータをロードするコンポーネントを作成し、値<を選択して>要素を選択します。コンポーネントの状態がselectおよびonChangeハンドラで更新されない

class SomeComponent extends Component { 
    state = { 
     data: [], 
     currentCategory: 'all' 
    } 
    switchCategory = (ev) => { 
     console.log('Selected category is ' + ev.target.value); 

     this.setState({ 
      currentCategory: ev.target.value 
     }); 

     this.loadData(); 
    } 
    loadData = async() => { 
     let { currentCategory } = this.state; 

     // Always print previous value!!! 
     console.log(currentCategory); 

     // Get data via XHR... 
    } 
    render() { 
     return (
      <div> 
       <select value={currentCategory} onChange={this.switchCategory}> 
        <option value="all">All</option> 
        {categories.map(category => 
        <option key={category._id} value={category.category}>{category.display}</option>  
        )} 
       </select> 

       <table> 
        // ... prints data with this.state.data 
       </table> 
      </div> 
     ); 
    } 
} 

上記のコードは単なる簡単なものです。コードは非常に簡単です、私はちょうどthis.state.currentCategoryとselect要素の値を同期させ、クラスのswitchCategoryメソッドで切り替えることを検出します。

しかし、主な問題は、コンポーネントの状態にアクセスすると、常に前の値であり、存在していないということです。選択した変更の値に対してcurrentCategoryを更新していることがわかります。

switchCategory = (ev) => { 
     console.log('Selected category is ' + ev.target.value); 

     this.setState({ 
      currentCategory: ev.target.value 
     }); 

     this.loadData(); 
    } 

したがって、このような状況では、this.state.currentCategoryは何か他のもののように、「アップル」の「すべて」を持っていない必要がありますが、まだそれは「すべて」が含まれ、ない「アップル」!

loadData = async() => { 
     let { currentCategory } = this.state; 

     // Always print previous value!!! I expected "Apple", but it has "all" 
     console.log(currentCategory); 

     // Get data via XHR... 
    } 

だから、最終的にXHRは、以前の値で発生し、それは私に私は期待していない、間違ったデータを提供します。 その後、セレクト(バナナと呼ぶ)の他の値を選ぶと、バナナではなくアップルが生まれます!

私が知っているように、setStateは "sync"ジョブなので、状態を更新するとthis.switchCategoryを呼び出すので、以前の値ではなく現在の値が必要です。

しかし、コンポーネントの状態をコンソールに表示するときは、そうではありません。

私は何が欠けていますか?なぜ私は古いデータをいつも持っているのですか?私が何か間違ったアプローチをしていたら、私は何をすることができますか?

アドバイスはありがたいです。ありがとう!

+1

反応し、選択したカテゴリのプリントが右の選択したカテゴリを印刷していますか?非同期を削除しようとしましたか? – Kinnza

+1

onChangeをバインドしましたか?あなたのクラスの最上部とコンストラクタにコンストラクタを追加してください: 'this.onChange = this.onChange.bind(this)' – Celebrian

+0

あなたを助けてくれてありがとう! – modernator

答えて

1

ここでの問題は、setStateが非同期(特定の状況では同期可能)であることです。だからあなたは前の価値を得るのです。

解決策は2つあります。で、同期setState

// 
// 1. use value directly. 
// 
switchCategory = (ev) => { 
    this.setState({ currentCategory: ev.target.value }); 
    this.loadData(ev.target.value); 
} 

loadData = async (currentCategory) => { 
    console.log(currentCategory); 

    // Get data via XHR... 
} 

// 
// 2. use completition callback on `setState`. 
// 
switchCategory = (ev) => { 
    this.setState({ currentCategory: ev.target.value },() => { 
     this.loadData(ev.target.value); 
    }); 
} 

loadData = async() => { 
    const { currentCategory } = this.state; 
    console.log(currentCategory); 

    // Get data via XHR... 
} 

記事は[link]

+0

setStateの非同期で「特定の状況」を説明できますか?私はちょうど確かに知りたい。 – modernator

+0

ああ、ドキュメントのsetStateの説明が見つかりました!それは非同期で、私はそれを知らなかった!ありがとうAndreyco! – modernator

+1

@modernator記事へのリンクで自分の答えを更新しました – Andreyco

関連する問題