2016-10-12 6 views
1

現在、リレー/リアクションWebアプリケーションを構築中です。 1つの例外を除いて、それは驚くほど単純です。私は、どのコンポーネントがネットワーク要求を行っているときに、どのようにグローバル通知を受け取ることができるかを理解できませんでした。ネットワーク活動があるときに私のアプリの上部にスピナーを追加するために飛び回っています。なぜなら、私の突然変異の中にはロードに時間がかかるからです。すべてのRelay.jsネットワークリクエストにローディングインジケータを追加する方法

これは私がこの問題を解決しようとしたものですが、新しいルートページの読み込み時にのみ機能します。

function renderer(info) 
{ 
    let {props, error, element} = info; 
    if (error) { 
     return (<ServerError errors={error}/>); 
    } else { 
     if (props) { 
      return React.cloneElement(element, props); 
     } else { 
      return (<Loading />); 
     } 
    } 
} 


ReactDOM.render(
    <Router 
     history={browserHistory} 
     render={applyRouterMiddleware(useRelay)} 
     environment={Relay.Store} 
    > 
     <Route 
      path="/" 
      queries={ViewerQuery} 
      component={App} 
     > 
      <IndexRoute 
       queries={ViewerQuery} 
       component={Libraries} 
       render={renderer} 
      /> 
     <Route path="*" component={Error}/> 

    </Route> 
</Router> 

理想的には、すべてのページヘッダーとフッターをレンダリングするAppコンポーネントに渡すことができるコールバックを得ることができます。これに関する助けがあれば大いに感謝します。私はこの間、良い解決策を見つけようとしている間、インターネットのいたるところにいました。

答えて

0

私は主なルートコンポーネントが聴いているFluxイベントをいくつか作ることができるように、Relayのデフォルトネットワークレイヤーを拡張しました。これにより、もし私が望むなら、ロードとエラーメッセージの処理をすべて1か所で行うことができます。

ここに私の最終的な解決策があります。それが最もクリーンであるとは確信していませんが、かなりうまくいきます。

import Relay from "react-relay"; 
import RelayMutationRequest from "react-relay/lib/RelayMutationRequest"; 
import AppDispatcher from "./AppDispatcher"; 

export default class CustomNetworkLayer extends Relay.DefaultNetworkLayer { 

    constructor(uri, init) 
    { 
     super(uri, init); 
    } 

    networkLoadingEvent() 
    { 
     AppDispatcher.dispatch({ 
      actionType: 'LOADING' 
     }); 
    } 

    networkDoneLoadingEvent() 
    { 
     AppDispatcher.dispatch({ 
      actionType: 'DONE_LOADING' 
     }); 
    } 

    networkErrorEvent(error) 
    { 
     AppDispatcher.dispatch({ 
      actionType: 'ERROR', 
      payload: error 
     }); 
    } 

    sendQueries(requests) 
    { 
     this.networkLoadingEvent(); 
     return Promise.all(requests.map(request => (
      this._sendQuery(request).then(
       result => result.json() 
      ).then(payload => 
      { 
       if (payload.hasOwnProperty('errors')) { 
        const error = CustomNetworkLayer.createRequestError(request, '200', payload); 
        this.networkErrorEvent(payload.errors[0].message); 
        request.reject(error); 
       } else { 
        if (!payload.hasOwnProperty('data')) { 
         const error = new Error(
          'Server response was missing for query ' + 
          `\`${request.getDebugName()}\`.` 
         ); 
         this.networkErrorEvent(error); 
         request.reject(error); 
        } else { 
         this.networkDoneLoadingEvent(); 
         request.resolve({response: payload.data}); 
        } 
       } 
      }).catch(
       error => 
       { 
        this.networkErrorEvent(error); 
        request.reject(error) 
       } 
      ) 
     ))); 
    } 

    sendMutation(request) 
    { 
     this.networkLoadingEvent(); 
     return this._sendMutation(request).then(
      result => result.json() 
     ).then(payload => 
     { 
      if (payload.hasOwnProperty('errors')) { 
       const error = CustomNetworkLayer.createRequestError(request, '200', payload); 
       this.networkErrorEvent(payload.errors[0].message); 
       request.reject(error); 
      } else { 
       this.networkDoneLoadingEvent(); 
       request.resolve({response: payload.data}); 
      } 
     }).catch(
      error => 
      { 
       this.networkErrorEvent(error); 
       request.reject(error) 
      } 
     ); 
    } 


    /** 
    * Formats an error response from GraphQL server request. 
    */ 
    static formatRequestErrors(request, errors) 
    { 
     const CONTEXT_BEFORE = 20; 
     const CONTEXT_LENGTH = 60; 

     const queryLines = request.getQueryString().split('\n'); 
     return errors.map(({locations, message}, ii) => 
     { 
      const prefix = (ii + 1) + '. '; 
      const indent = ' '.repeat(prefix.length); 

      //custom errors thrown in graphql-server may not have locations 
      const locationMessage = locations ? 
       ('\n' + locations.map(({column, line}) => 
       { 
        const queryLine = queryLines[line - 1]; 
        const offset = Math.min(column - 1, CONTEXT_BEFORE); 
        return [ 
         queryLine.substr(column - 1 - offset, CONTEXT_LENGTH), 
         ' '.repeat(Math.max(0, offset)) + '^^^', 
        ].map(messageLine => indent + messageLine).join('\n'); 
       }).join('\n')) : 
       ''; 

      return prefix + message + locationMessage; 

     }).join('\n'); 
    } 

    static createRequestError(request, responseStatus, payload) 
    { 
     const requestType = 
      request instanceof RelayMutationRequest ? 'mutation' : 'query'; 
     const errorReason = typeof payload === 'object' ? 
      CustomNetworkLayer.formatRequestErrors(request, payload.errors) : 
      `Server response had an error status: ${responseStatus}`; 
     const error = new Error(
      `Server request for ${requestType} \`${request.getDebugName()}\` ` + 
      `failed for the following reasons:\n\n${errorReason}` 
     ); 
     error.source = payload; 
     error.status = responseStatus; 
     return error; 
    } 
} 

次にインデックスにあります。

Relay.injectNetworkLayer(new CustomNetworkLayer("/graphql", 
    { 
     fetchTimeout: 35000, // timeout after 35 seconds 
     retryDelays: [2000] // retry after 2 seconds 
    })); 

簡単なメモは:AppDispatcherはちょうどフラックスJSディスパッチャであり、私は私のメインラッパーコンポーネントで、それらのイベントに聞いてJSファイル私はこれを行います。

これは他の誰かを助けることを望みます。私は確かにこれに多くの時間を費やしました。

この解決策を手伝ってくれた皆さん、ありがとうございます。

1

リアクションにカスタムスピナーコンポーネントを作成し、データロードステータスに基づいてスピナーを表示または非表示にすることができます。

このための例は、であることができる -

あなたスピナーコンポーネントは、このようにすることができ -

let SpinMe 
    = (
     <div className="spinner-container"> 
      <div className="loader"> 
       <svg className="circular"> 
        <circle className  = "path" 
         cx    = "50" 
         cy    = "50" 
         r     = "20" 
         fill    = "none" 
         strokeWidth  = "3" 
         strokeMiterLimit = "10" 
        /> 
       </svg> 
      </div> 
     </div> 
    ); 

このスピナー成分が他の成分よりz-index若干高くなければならない負荷はユーザに行われている間ことができないように他のコンポーネントをクリックするか、他のコンポーネントとやり取りします。

スタイリングでも、スピナーの透明な暗い背景を見せてください。今

例えば

.spinner-container { 

    position   : absolute; 
    background-color : rgba(12, 12, 12, 0.61); 
    width   : 100%; 
    min-height  : 100%; 
    background-size : 100% 100%; 
    text-align  : center; 
    z-index   : 3; 
    top    : 0; 
    left    : 0; 
} 

あなたはスピナーを使用すると、このコンポーネントで使用すると、ネットワーク要求を作りたいあなたの別のコンポーネント。

import React from 'react'; 

class SpinTestComponent extends React.Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     isLoading:false 
    }; 
    } 

    sendNetworkRequest(URL, dataToSend) { 
     return $.ajax({ 
      type  : 'POST', 
      url   : URL, 
      data  : JSON.stringify(dataToSend), 
      dataType : 'json' 
      }); 
    } 

    componentDidMount() { 
     const URL = "test url"; 
     const dataToSend = { param1:"val", param2:"val" }; 

     this.setState({isLoading:true}); 
     this.sendNetworkRequest(dataToSend) 
      .then(
      () => { 
       // success response now remove spinner 
       this.setState({isLoading:false}); 
      }, 
      () => { 

       // error response again remove spinner and 
       // show error message to end user 
       this.setState({isLoading:false}); 
      }); 
    } 

    render() { 
     return (
       <div> 
       { this.state.isLoading ? <SpinMe/> : null } 
        <div> 
         <h1> 
          Remaining Component structure 
          or Jsx 
         </h1> 
         <p> 
          To be show after loading is done. 
         </p> 
        </div> 
       </div> 
       ); 
    } 
} 

export default SpinTestComponent; 
+1

恐ろしい!このソリューションをありがとうございました!!!私は今日それを試してみるつもりです。 –

1

また、リクエストごとにローディングインジケータコンポーネントをレンダリングするカスタムRelay Network Layerを追加することもできます。私は、 "グローバル"ローディングインジケータの考慮すべき主な懸案事項は、インジケータだけでなく、UIへのインパクトについても同様です。

handleSubmit(event) { 
    event.preventDefault(); 
    this.setState({isLoading: true}); 

    this.props.relay.commitUpdate(
     new LoginMutation({ 
     email: this.refs.email.value, 
     password: this.refs.password.value 
     }), { 
     onSuccess: response => { 
      Auth.login(response.login.accessToken); 
      const { location, router } = this.props; 

      if (location.state && location.state.nextPathname) { 
      router.replace(location.state.nextPathname) 
      } else { 
      router.replace('/') 
      } 
     }, 
     onFailure: transaction => { 
      this.setState({hasError: true}); 
      this.setState({isLoading: false}); 
     } 
     } 
    ); 
    } 

:それは?、など一方

を他の要素をアップ変位/ダウンう?UI?それのほんの一部をブロックしようとしている、あなたのような何かを行うことができます上記のスニペットはhereから取られています。そのレポの残りのロジックを見ることができます。

関連する問題