質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

388閲覧

【React】jsx を生成する非同期関数が上手く動作しない

foowa

総合スコア6

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2018/07/30 14:13

React 16.4.1 で jsx を生成する非同期関数を作成したのですが、意図した通りに動作しません。
説明が至らない点もあるかと思いますが、もし原因がお分かりになる方がいればご指摘を頂けると幸いです。

前提・実現したいこと

  • Verbose コンポーネントのメソッドとして、処理に時間のかかる jsx を生成する generateContents() という非同期関数がある。それが解決されるまでは <Loading /> コンポーネントをユーザーに表示しておきたい。
  • 解決後に this.state.contents に結果を格納して、this.state.isLoading を false にすることで

<Loading />コンポーネントの代わりに this.state.contents をレンダリングしたい。

問題点

generateContents() が非同期扱いにならず、この関数の処理が終了するまで Verbose クラス自体のレンダリングが行われないため、ユーザーに処理中であることを表示できずに困っています。
ソースコード中にもいくつかコメントを記載しています。

該当のソースコード

jsx

1import React, { Component } from 'react'; 2import Loading from '../common/Loading'; 3 4class Verbose extends Component { 5 constructor(props) { 6 super(props); 7 8 this.state = { 9 10 // 予め Loading 状態にしてある 11 isLoading: true, 12 contents: null 13 }; 14 } 15 16 componentDidMount() { 17 // JSX の生成が終わったら それを this.state.contents にセットして Loading 状態を解除する 18 this.generateContents().then(contents => { 19 this.setState({ 20 isLoading: false, 21 contents 22 }); 23 }); 24 } 25 26 // 時間のかかる JSX の生成関数 27 generateContents() { 28 29 // 例えば、このようにした場合は、意図通り最初に Loading コンポーネントが 30 // ちゃんと表示されており、5秒後に this.state.contents がレンダリングされる 31 // return new Promise((resolve) => { 32 // setTimeout(() => {resolve("foo")}, 5000); 33 // }); 34 35 // 問題点: 実際に行いたいこちらの処理だと、非同期にならずに以下がすべて終了するまで 36 // Loading コンポーネントどころか この Verbose コンポーネント自体のレンダリングも行われない 37 return new Promise((resolve) => { 38 39 // this.props.verbose.content は 長さ 10,000,000 の配列 40 const contents = this.props.verbose.content.map(row => { 41 const songInfo = row[0]; 42 const cells = row.map((cell, i) => { 43 return <div key={`${songInfo}_${i}`}>{cell.trim()}</div> 44 }); 45 return (<div className="grid" key={`${songInfo}`}>{cells}</div>); 46 }); 47 48 resolve(contents); 49 }); 50 } 51 52 render() { 53 const {verbose} = this.props; 54 55 return ( 56 <section className="result-section verbose"> 57 <div className="result-box__col"> 58 <span className="label result-box__col__label">{verbose.label}</span> 59 60 {/* Loading 状態が解除されたら this.state.contents を表示したい */} 61 {this.state.isLoading ? ( 62 <div className="grid"> 63 <div className="grid__item grid__item--join"> 64 <Loading /> 65 </div> 66 </div> 67 ) : this.state.contents } 68 69 </div> 70 </section> 71 ); 72 } 73} 74 75export default Verbose;

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

自己解決しました。
jsx の生成コードを setTimeout() のコールバックに渡すことで無事解決しました。
ご覧下さった方々、ありがとうございました。

jsx

1class Verbose extends Component { 2 constructor(props) { 3 super(props); 4 5 this.state = { 6 rows: null 7 }; 8 } 9 10 componentDidMount() { 11 setTimeout(() => { 12 const rows = this.props.verboseTexts.content.map(row => { 13 const songInfo = row[0]; 14 const cls = row.length === 1 ? "grid__item grid__item--join" : "grid__item "; 15 const cells = row.map((cell, i) => { 16 return <div key={`${songInfo}_${i}`} className={cls}>{cell.trim()}</div> 17 }); 18 return (<div className="grid" key={`${songInfo}`}>{cells}</div>); 19 }); 20 21 this.setState({rows}) 22 }, 0) 23 } 24 25 render() { 26 const {verboseTexts } = this.props; 27 const { rows } = this.state; 28 29 if(!rows) { 30 return ( 31 <Loading /> 32 ) 33 } 34 35 return ( 36 <section className="result-section verbose"> 37 <div className="result-box__col"> 38 <span className="label result-box__col__label">{verboseTexts.label}</span> 39 {rows} 40 </div> 41 </section> 42 ); 43 } 44}

投稿2018/07/30 18:32

foowa

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問