web-dev-qa-db-ja.com

React.js:Fetch APIとオブジェクト配列からの小道具でJSONデータをロードする

React.jsはまったく新しく、チュートリアルを読んでドキュメントを読んだ後も、js fetchを使用してJSONファイルからデータをロードしたり、オブジェクトの配列からプロパティを設定したりすることにまだ苦労しています。また、イベントハンドラーでDOMプロパティに正しくアクセスしていることも確信できません。かなり簡単に何かを見逃しているに違いありません。

参照用に、 ここにプロジェクトの他の部分のコードがあります および これがどのように見えるかです

ETA:ドキュメントからbabelブラウザが非推奨になったことを知らなかったので、JSXの代わりにES5構文のストレートJavascriptを使用することにしました。以下でコードを更新しましたが、まだマークアップをレンダリングしていません。

var CanvasAnimation = React.createClass({
    getInitialState: function() {
        return {data: []};
    },                            
    loadData: function() {
        /*
        fetch("data.json")
            .then(function(response) {
                return response.json    
                    .then(function(json){
                        this.setState({data: json});
                    }.bind(this))
            }.bind(this));
        */
        const data = [
            { id: "stalkerOne", width: 225, height: 434, spriteSheetURL: 'spriteSheets/stalkerone.jpg', rows: 5, columns: 5, totalFrames: 24 },
            { id: "stalkerTwo", width: 175, height: 432, spriteSheetURL: 'spriteSheets/stalkertwo.jpg', rows: 6, columns: 5, totalFrames: 26 },
            { id: "stalkerThree", width: 251, height: 432, spriteSheetURL: 'spriteSheets/stalkerthree.jpg', rows: 6, columns: 5, totalFrames: 28 }
        ];
    },
    componentDidMount: function() {
        this.loadData();
    },
    componentDidUpdate: function() {
        function animation(json) {
            return json.map(function(data) {
                return(
                    new CanvasSprite(
                        document.getElementById(data.id),
                        data.width,
                        data.height,
                        data.spriteSheetURL,
                        data.rows,
                        data.columns,
                        data.totalFrames)
                );
            });
        };
        this.setState({animaton: animation(this.state.data)});  
    },
    handleInteraction: function(event, index) {
        var offsetY = event.clientY - event.node.getBoundingClientRect().top;
        var relY = offsetY/this.state.data.height;
        this.props.animation[index].setFrame(relY);
    },
    render: function() {
        var canvases = this.state.data.map(function(data, index) {
            return (
                React.createElement('canvas', 
                                    id = data.id,
                                    width = data.width,
                                    height = data.height,
                                    style = 'border:5px solid white',
                                    onMouseOver= this.handleInteraction(event, index))
            );
        });
        return(
            React.createElement('div', canvases)
        );
    }
});
  
    
ReactDOM.render(
    React.createElement(CanvasAnimation, null),
    document.getElementById('content')
); 
20
Sophia Gold

わかりました... これが作業中のプロジェクトです。 @gumingfengと@hkalから助けを得ました。

学んだ教訓:

  1. Reactのドキュメントはとんでもなく古くなっています。
  2. ストレートJS対JSXは本当に悪くはありません。
  3. Fetchの構文エラーを修正しました。
  4. コンストラクターでDOM参照を渡すために、オブジェクト配列をインスタンス化する必要がありますafterデータをロードします。
  5. ただし、setState()内でcomponentDidUpdate()を呼び出すと、無限ループがトリガーされるため、オブジェクト配列を状態から直接独立して設定する必要がありました。
  6. 配列からDOM要素を作成する場合、Reactは特定の要素にイベントハンドラーを自動的に割り当てません。つまり、配列の値にアクセスするために使用できるように、配列インデックスを渡す必要があります。

ふう、それだと思う。これが他の人に役立つことを願っています。

最後に、JSXを使用せずにReactを試してみてください。本当にそんなに悪くない:)

const { Component } = React;
const { render } = ReactDOM;

class CanvasAnimation extends Component {
    
    constructor(){
        super();
        this.state = {
            data: []
        };
    };
    
    componentDidMount() {
        fetch("data.json")
            .then( (response) => {
                return response.json() })   
                    .then( (json) => {
                        this.setState({data: json});
                    });
    };
    
    componentDidUpdate() {
        function animation(json) {
            return json.map( (data) => {
                return(
                    new CanvasSprite(
                        document.getElementById(data.id),
                        data.width,
                        data.height,
                        data.spriteSheetURL,
                        data.rows,
                        data.columns,
                        data.totalFrames)
                );
            });
        };
        //this.setState({animation: animation(this.state.data)}); //causes infinite loop
        this.animation = animation(this.state.data);
    };
    
    handleInteraction(event, index) {
        var offsetY = event.clientY -  document.getElementById(this.state.data[index].id).getBoundingClientRect().top;
        var relY = offsetY/this.state.data[index].height;
        this.animation[index].setFrame(relY);
    };
    
    render() {
        var canvases = this.state.data.map( (data, index) => {
            return (
                React.createElement('canvas', 
                                    {id : data.id,
                                    width : data.width,
                                    height : data.height,
                                    //style : {border: '5px solid white'},
                                    onMouseMove : (event) => this.handleInteraction(event, index)}
                                    )
            );
        });
        return(
            React.createElement('div', null, ...canvases)
        );
    };
    
};
  
    
render(
    React.createElement(CanvasAnimation, null),
    document.getElementById('content')
);
14
Sophia Gold

コードに大量の構文エラーがあります。私はそれらを修正しました。

const { Component } = React;
const { render } = ReactDOM;

class CanvasAnimation extends Component {
  state = {
    data: []
  };

  loadData() {
    function animation(json) {
      return json.map(function(data) {
        return (
          new CanvasSprite(
            document.getElementById(data.id),
            data.width,
            data.height,
            data.spriteSheetURL,
            data.rows,
            data.columns,
            data.totalFrames
          )
        );
      });
    }
    fetch("data.json")
      .then(response => response.json())
      .then(json => {
        console.log(json);
        this.setState({
          data: json,
          animation: animation(json)
        });
      });
  }

  componentDidMount() {
    this.loadData();
  }

  handleInteraction(e) {
    var offsetY = e.clientY - e.node.getBoundingClientRect().top;
    var relY = offsetY/this.state.data.height;
    this.props.animation.setFrame(relY);
  }

  render() {
    var canvases = this.state.data.map(function(data) {
      return (
        <canvas
          id={data.id} 
          width={data.width} 
          height={data.height}
          style={{border: '5px white'}}
          onMouseOver={this.handleInteraction}
        />
      );
    });

    return (
      <div>{canvases}</div>
    );
  }
}

render(
  <CanvasAnimation />,
  content
);

APIの応答がわからないため、他に修正すべきものがあるかどうかはわかりません。

私が気づいたいくつかの問題:

  • ダブルreturnステートメントを持つ関数があったため、おそらくインデントが間違っています。これらのエラーをキャッチするには、IDEでESLintを有効にすることをお勧めします。

  • setStateがどのように機能するのか理解していないので、あなただけではできません:

    this.setState({
      foo: 'bar',
      baa: myFn(this.state.foo)
    });
    

    それ以外の場合、myFn内のthis.state.fooは、現在設定している新しい値ではなく、古い値を参照します。
    this.setState({foo: 'bar'}, () => this.setState({baa: myFn(this.state.foo)})を実行する必要がありますが、その後、上記で修正したコードで行ったように実行することをお勧めします。

24
Fez Vrasta