2017-04-15 14 views
5

私は、ドラフトjsでcontentEditorを構築しようとしています。厳密にはFacebookのようなURLからデータを抽出する機能です。しかし、私はこの部分に立ち往生しています。コールバックが機能していません。ajaxリクエストでコールバックが機能していませんか?

まず私は、私はこれが基本的なJavaScriptの問題であるかわからない ...コールバックが動作しない場合、コンポーネントは表示されませんcompositeDecorator

このよう
constructor(props) { 
    super(props); 
    const compositeDecorator = new CompositeDecorator([ 
     .... { 
      strategy: linkStrategy, 
      component: decorateComponentWithProps(linkComp, { 
       passit 
      }) 
     } 
     .... 
    ]); 
} 
// This is my strategy 
function linkStrategy(contentBlock, callback, contentState) { 
    findLinkInText(LINK_REGEX, contentBlock, callback) 
} 

function findLinkInText(regex, contentBlock, callback) { 
    const text = contentBlock.getText(); 
    let matchArr, start; 
    if ((matchArr = regex.exec(text)) !== null) { 
     start = matchArr.index; 
     let URL = matchArr[0]; 
     console.log(URL); 
     axios.post('/url', { 
      url: URL 
     }).then(response => { 
      passit = response.data 
      //not working 
      callback(start, start + URL.length) 
     }) 
     //working 
     callback(start, start + URL.length) 
    } 
} 

と私の状態を包みました。しかし、私は自分のサーバーからURLデータを取得したいので、データをプロップ経由でコンポーネントに渡してコンポーネントに渡してレンダリングする必要があります。他のすべてが動作していると仮定すると、ANSWER

function findLinkInText(regex, contentBlock, callback) { 
    const text = contentBlock.getText(); 
    let matchArr, start; 
    if ((matchArr = regex.exec(text)) !== null) { 
     start = matchArr.index; 
     let url = matchArr[0]; 
     axios.post('/url', { 
      url: URL 
     }).then(response => { 
      passit = response.data 
      handleWithAxiosCallBack(start, start + matchArr[0].length, callback) 
     }).catch(err => console.log(err)) 
    } 
} 


function handleWithAxiosCallBack(start, startLength, callback) { 
    console.log(callback); //Spits out the function But Not working 
    callback(start, startLength) 
} 
+0

私の例では、 'linkStrategy'にコールバックを渡す方法はありません。 'Strategy:linkStrategy'の詳細を投稿してください。 –

+0

Sir、LinkStrategyからコールバックを他のfuntionに渡しています。コールバックが実行されるコールバックが見つかります。@ MaximShoustin – Nane

+0

@Nane - あなたのpassit変数に' passit = response。データ 'である。 'console.log'で確認できますか? –

答えて

1

下に示す。

あなたのソリューションが動作しない理由:callbackによって実行される必要があるアクションが実行されないのは、draftcallbackを同期と呼びますからです。 async関数(Axios api呼び出し)を使用していて、非同期的にcallbackを呼び出すことは効果がないためです。

解決策:これは効率的なソリューションではないかもしれませんが、仕事を完了することができます。簡単に言えば、axiosコールの結果を(一時的に)変数に格納してから、editorre-renderをトリガーし、結果ストアを先に検索してコールバックを呼び出すだけです。

この例では、hereに基づいています。エディタの状態をコンポーネントの状態に格納すると仮定します。以下は、必要に応じて実装する必要がある疑似コードです。

あなたのコンポーネントの状態がEditorの状態を保持する以下のようになっているとしましょう。

constructor(props){ 
super(props); 
// .. your composite decorators 

// this is your component state holding editors state 
this.state = { 
    editorState: EditorState.createWithContent(..) 
} 

// use this to temporarily store the results from axios. 
this.tempResults = {}; 

} 

Editorを次のようにレンダリングしているとします。 refに注目してください。ここで、エディタのリファレンスは、後でアクセスできるコンポーネントのeditor変数に格納されます。 refとして文字列を使用することもできますが、これはrefを格納するための推奨方法です。あなたのコンポーネントで

<Editor 
    ref={ (editor) => this.editor } 
    editorState={this.state.editorState} 
    onChange={this.onChange} 
    // ...your props 
/> 

re-renderを強制するcurrentStateのでエディタを更新する関数を記述します。この関数がコンポーネントにバインドされていることを確認して、正しいthis(コンテキスト)を取得してください。

forceRenderEditor =() => { 
    this.editor.update(this.state.editorState); 
} 

findLinkInText関数では、以下のようにします。

まず、find(FindLinkInText)がコンポーネントにバインドされていることを確認して、正しいthisを取得します。矢印関数を使用してこれを行うか、コンポーネントコンストラクタでバインドすることができます。

次に、urlの結果がコンポーネントのコンストラクタで宣言したtempResults にあるかどうかを確認します。もしあれば、適切な引数でコールバックを直ちに呼び出します。

結果がまだない場合は、電話をかけて結果をtempResultsに保存してください。格納した後、再定義するためにdraftを呼び出す定義済みのthis.forceRenderEditorメソッドを呼び出し、今度はtempResultsに結果を格納しているので、コールバックが呼び出され、適切な変更が反映されます。

function findLinkInText(regex, contentBlock, callback) { 
const text = contentBlock.getText(); 
let matchArr, start; 
if ((matchArr = regex.exec(text)) !== null) { 
    start = matchArr.index; 
    let URL = matchArr[0]; 
    console.log(URL); 

    // do we have the result already,?? 
    // call the callback based on the result. 
    if(this.tempResults[url]) { 
     // make the computations and call the callback() with necessary args 
    } else { 
    // if we don't have a result, call the api 
     axios.post('/url', { 
     url: URL 
     }).then(response => { 
     this.tempResults[url] = response.data; 
     this.forceRenderEditor(); 
     // store the result in this.tempResults and 
     // then call the this.forceRenderEditor 
     // You might need to debounce the forceRenderEditor function 
     }) 
    } 
} 
} 

注:

  1. あなたはtempResultsをクリアする必要があるかどうかを判断しなければなりません。そうであれば、適切な場所にロジックを実装する必要があります。
  2. tempResultsを保存するには、memoizationというテクニックを使用できます。上記のものは単純なものです。
  3. 結果が記録されるので、axios apiの呼び出し結果が同じ入力に対して変更されない場合には、これは利点になる場合があります。同じクエリでもう一度apiを押す必要はないかもしれません。
  4. tempResultsに格納するデータは、api呼び出しなどの応答か、callbackに渡す必要がある引数を判別できるものである必要があります。
  5. 私は、レンダリングごとに多くのAPIが呼び出されている場合は、debounceforceRenderEditorメソッドを繰り返す必要があるかもしれないと思うかもしれません。
  6. 最後に、draftasyncコールバックを使用または示唆している場所を見つけることができませんでした。そのような機能をサポート/必要とする場合は、図書館のチームに確認する必要があります。 (必要に応じて変更を行い、そのチームは1でOKであればPRを上げる。)

    は、コンポーネント内の機能を移動し、それを以下の方法を書くことができますをバインドする

を更新。

linkStrategy = (contentBlock, callback, contentState) => { 
    this.findLinkInText(LINK_REGEX, contentBlock, callback) 
} 


findLinkInText = (...args) => { 
} 

そして、あなたのコンストラクタで、あなたはこの

const compositeDecorator = new CompositeDecorator([ 
    .... { 
     strategy: this.linkStrategy, 
     component: decorateComponentWithProps(linkComp, { 
      passit 
     }) 
    } 
    .... 
]); 
} 

のようにそれを呼び出すことができますそれとも、複数のコンポーネント間で機能を再利用する場合、あなたは以下の方法でそれをバインドすることができます。しかし、共有コンポーネントのすべてに同じstateを使用することを確認します(またはカスタム状態を定義するためにコールバックを使用)

const compositeDecorator = new CompositeDecorator([ 
    .... { 
     strategy: linkStrategy.bind(this), 
     component: decorateComponentWithProps(linkComp, { 
      passit 
     }) 
    } 
    .... 
]); 
} 

あなたのリンク戦略がこの

function linkStrategy(contentBlock, callback, contentState) { 
    findLinkInText.call(this,LINK_REGEX, contentBlock, callback); 
} 
のようになりますようにあなたのコンストラクタは次のようになります

上記の方法のいずれかを使用して、関数をバインドすることができます。

+0

あなたの解決策は正常ですがエラーが発生しますこのように** TypeError:_this4.forceRenderEditorは関数ではありません** – Nane

+0

'findLinkInText'をコンポーネントにバインドする必要があります。またはあなたはそれを行うために矢印機能を使用することができます。このエラーは、 'findLinkInText'があなたのコンポーネントと同じコンテキストにないために発生します。 – Panther

+0

申し訳ありません私はこれをよくしていません私は多くを試してみましたあなたは私の質問で例を示すことができます@ Panther – Nane

-1

FOR

UPDATEは、私は以下の通りです何より、何かを期待します。 Axiosを使用するように設定されていないので、実際にこれをテストすることはできません。

// I made these global variables because you are trying to use them 
// in both the .post and the .then 
var start; // global variable 
var URL // global variable 
function processResponse (aStart, aStartURL, passit) { 
    // do something with the reponse data 
} 

function findLinkInText(regex, contentBlock) { 
    const text = contentBlock.getText(); 
    let matchArr; 
    if((matchArr = regex.exec(text)) !== null){ 
     start = matchArr.index; 
     // renamed because it is not the url, its data passed to the server 
     URL = matchArr[0]; 
     console.log(URL); 
     axios.post('/url',{url:URL}).then(response => { 
      passit = response.data; 
      processResponse (start, start + URL.length, passit) 
     }).catch(function (error) { 
      console.log(error); 
     }); 
    } 
} 
+0

いいえ運がない – Nane

+0

が呼び出されていますか?キャッチは呼ばれていますか? – Bindrid

+0

投稿を見る私はコードを更新しましたあなたのソリューションでまだ動作していません... – Nane

-1

「axiosをサポートするネイティブES6約束の実装に依存します。ご使用の環境がES6の約束をサポートしていない場合、あなたはポリフィルすることができます。」という注意これはすべてのブラウザで動作しないことを意味します。 (私はそれも後の推奨などがここに含まれるIE 11で動作させることができなかった。ここ

https://github.com/stefanpenner/es6-promise私はエッジでの作業を取得んでした私のコードです:そのことを

  axios(
       { 
        method: 'post', 
        url: '/wsService.asmx/GetDTDataSerializedList', 
        data: { parameters: 'one' }, 
        callback: function() { alert() } 
       }) 
        .then(response =>{ 
         response.config.callback(); 

         console.log(response); 
        }) 
        .catch(function (error) { 
         console.log(error); 
        }); 
      }); 

私のようにそれに応じてコードを変更あなたが期待している動作を実現するために役立つだろう下記の技術が

 function findLinkInText(regex, contentBlock, callback) { 
      const text = contentBlock.getText(); 
      let matchArr, start; 
      if ((matchArr = regex.exec(text)) !== null) { 
       start = matchArr.index; 
       var URL = matchArr[0]; 
       console.log(URL); 

       // I am putting the parameters used to make the call in a JSON object to be used in the "then" 
       var myparameters = { myCallback: callback, URL: URL, start: start }; 

       axios({ 
        method:post, 
        url:'/url', 
        data: { url: URL }, 
        // note that i am attaching the callback to be carrired through 
        myParameters: myparameters 
       }).then(response => { 
        // This section is the callback generated by the post request. 
        // it cannot see anything unless they declared globally or attached to the request and passed through 
        // which is what i did. 
        passit = response.data 
        var s = response.config.myParameters.start; 
        var u = response.config.myParameters.URL 
        response.config.myParameters.myCallback(s, s + u.length) 
       }) 

      } 
     } 
+0

もう一度幸運にも、私は何か手がかりを見つけることができませんでした! – Nane

+0

は運がないと説明しています。デバッガの行をホットにしましたか? – Bindrid

+0

handleWithAxiosCallBackの後に何も起こっていません – Nane

関連する問題