web-dev-qa-db-fra.com

React.js: chargement de données JSON avec l'API Fetch et les propriétés d'un tableau d'objets

Tout à fait nouveau pour react.js et après avoir lu le didacticiel et lu la documentation, je ne parviens toujours pas à utiliser js fetch pour charger mes données à partir d’un fichier JSON et à définir les propriétés à partir d’un tableau d’objets. Je ne suis pas certain non plus d'accéder correctement aux propriétés DOM dans mon gestionnaire d'événements. Je dois manquer quelque chose d'assez simple.

Pour référence, voici mon code avec le reste du projet et voici à quoi il est censé ressembler.

ETA: D'après la documentation, je ne savais pas que le navigateur babel était obsolète. Nous avons donc décidé d'utiliser simplement du Javascript avec la syntaxe ES5 au lieu de JSX. Code mis à jour ci-dessous, mais il ne rend toujours pas le balisage.

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

Ok ... Voici le projet en cours. Vous avez l'aide de @gumingfeng et @hkal.

Leçons apprises:

  1. Les documents React sont ridiculement obsolètes).
  2. Straight JS vs JSX n’est vraiment pas pire.
  3. Correction de quelques erreurs de syntaxe dans Fetch.
  4. Le tableau d'objets doit être instancié après le chargement des données afin de permettre la transmission de références DOM dans les constructeurs.
  5. Cependant, l'appel de setState() à l'intérieur de componentDidUpdate() déclenche une boucle infinie et doit donc définir le tableau d'objets directement et indépendamment de l'état.
  6. Lors de la création d’éléments DOM à partir d’un tableau, React n’assigne pas automatiquement le gestionnaire d’événements à l’élément en question. En d’autres termes, il faut lui passer l’index afin qu’il puisse accéder à ses valeurs. dans les tableaux.

Ouf, je pense que c'est ça. J'espère que cela aide les autres.

Et je voudrais juste conclure en disant, donnez à React un essai sans JSX. Ce n’est vraiment pas si grave :)

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

Vous avez des tonnes d'erreurs de syntaxe dans votre code, je les ai corrigées pour vous.

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
);

Je ne connais pas la réponse de votre API, je ne suis donc pas sûr qu'il y ait d'autres solutions à corriger.

Certains des problèmes que j'ai remarqués:

  • Votre indentation est probablement fausse, car vous aviez des fonctions avec des déclarations doubles return. Je vous suggère d’activer ESLint dans votre IDE pour corriger ces erreurs.

  • Vous n'avez pas compris comment fonctionne setState, vous ne pouvez pas simplement faire:

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

    Sinon, this.state.foo Dans myFn fera référence à l'ancienne valeur de celle-ci, et non à la nouvelle valeur que vous définissez actuellement.
    Vous devriez faire this.setState({foo: 'bar'}, () => this.setState({baa: myFn(this.state.foo)}), mais il est préférable de faire comme dans le code que j'ai corrigé ci-dessus.

24
Fez Vrasta