React.js:使用Fetch API加载JSON数据,并从对象数组中加载道具

时间:2022-12-04 15:38:28

Totally new to react.js and after going through the tutorial and reading the docs, I'm still struggling a bit with using js fetch to load my data from a JSON file as well as setting properties from an array of objects. I'm also not certain I'm accessing DOM properties correctly in my event handler. I must be missing something rather straightforward.

对于react.js来说是完全新的,在完成教程和阅读文档之后,我仍然在使用js fetch从JSON文件加载数据以及从对象数组设置属性方面苦苦挣扎。我也不确定我是否正在我的事件处理程序中正确访问DOM属性。我必须错过一些相当简单的事情。

For reference, here's my code with the rest of the project and here's what it's supposed to look like.

作为参考,这是我的代码与项目的其余部分,这是它应该是什么样子。

ETA: I had no idea from the docs that babel browser was deprecated so decided to just use straight Javascript with ES5 syntax instead of JSX. Code updated below, but it's still not rendering the markup.

ETA:我从文档中不知道babel浏览器已被弃用,因此决定只使用带有ES5语法的直接Javascript而不是JSX。代码在下面更新,但它仍然没有呈现标记。

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

2 个解决方案

#1


22  

You have tons of syntax errors in your code, I have fixed them for you.

你的代码中有很多语法错误,我已经为你修复了它们。

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

I don't know the response of your API so I'm not sure if there's other to fix.

我不知道您的API的响应,所以我不确定是否还有其他问题需要解决。

Some of the problems I have noticed:

我注意到的一些问题:

  • Probably your indentation is wrong, because you had functions with double return statements. I suggest you to enable ESLint in your IDE to catch those errors.

    可能你的缩进是错误的,因为你有双返回语句的函数。我建议你在IDE中启用ESLint来捕获这些错误。

  • You have not understood how setState works, you can't just do:

    你还没有理解setState是如何工作的,你不能只做:

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

    Otherwise, this.state.foo inside myFn will refer to the old value of it, and not to the new one that you are setting right now.
    You'd have to do this.setState({foo: 'bar'}, () => this.setState({baa: myFn(this.state.foo)}), but then, it's better to do as I did in the code I have fixed above.

    否则,myFn中的this.state.foo将引用它的旧值,而不是您现在正在设置的新值。你必须这样做.setState({foo:'bar'},()=> this.setState({baa:myFn(this.state.foo)}),但是,最好像我一样做在我上面修复的代码中。

#2


13  

Ok... Here's the working project. Got some help from @gumingfeng and @hkal.

好的...这是工作项目。得到了@gumingfeng和@hkal的帮助。

Lessons learned:

得到教训:

  1. The React docs are ridiculously outdated.
  2. React文档过时了。
  3. Straight JS vs. JSX is really no worse imo.
  4. Straight JS vs. JSX真的不差了。
  5. Corrected some syntax errors in Fetch.
  6. 更正了Fetch中的一些语法错误。
  7. Object array needs to be instantiated after data is loaded in order to pass DOM references in the constructors.
  8. 在加载数据之后,需要实例化对象数组,以便在构造函数中传递DOM引用。
  9. However, calling setState() inside componentDidUpdate() triggers an infinite loop so had to set the object array directly and independently from state.
  10. 但是,在componentDidUpdate()中调用setState()会触发无限循环,因此必须直接设置对象数组并独立于状态。
  11. When creating DOM elements from an array, React does not automatically assign the event handler to the particular element. In other words, it must be passed the array index so that can be used to access its values in the arrays.
  12. 从数组创建DOM元素时,React不会自动将事件处理程序分配给特定元素。换句话说,它必须传递数组索引,以便可以用于访问数组中的值。

Whew, I think that's it. Hope this helps others.

哇,我想就是这样。希望这有助于其他人。

And I would just conclude by saying, give React a try without JSX. It's really not that bad :)

最后我会说,给React一个没有JSX的尝试。这真的不是那么糟糕:)

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

#1


22  

You have tons of syntax errors in your code, I have fixed them for you.

你的代码中有很多语法错误,我已经为你修复了它们。

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

I don't know the response of your API so I'm not sure if there's other to fix.

我不知道您的API的响应,所以我不确定是否还有其他问题需要解决。

Some of the problems I have noticed:

我注意到的一些问题:

  • Probably your indentation is wrong, because you had functions with double return statements. I suggest you to enable ESLint in your IDE to catch those errors.

    可能你的缩进是错误的,因为你有双返回语句的函数。我建议你在IDE中启用ESLint来捕获这些错误。

  • You have not understood how setState works, you can't just do:

    你还没有理解setState是如何工作的,你不能只做:

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

    Otherwise, this.state.foo inside myFn will refer to the old value of it, and not to the new one that you are setting right now.
    You'd have to do this.setState({foo: 'bar'}, () => this.setState({baa: myFn(this.state.foo)}), but then, it's better to do as I did in the code I have fixed above.

    否则,myFn中的this.state.foo将引用它的旧值,而不是您现在正在设置的新值。你必须这样做.setState({foo:'bar'},()=> this.setState({baa:myFn(this.state.foo)}),但是,最好像我一样做在我上面修复的代码中。

#2


13  

Ok... Here's the working project. Got some help from @gumingfeng and @hkal.

好的...这是工作项目。得到了@gumingfeng和@hkal的帮助。

Lessons learned:

得到教训:

  1. The React docs are ridiculously outdated.
  2. React文档过时了。
  3. Straight JS vs. JSX is really no worse imo.
  4. Straight JS vs. JSX真的不差了。
  5. Corrected some syntax errors in Fetch.
  6. 更正了Fetch中的一些语法错误。
  7. Object array needs to be instantiated after data is loaded in order to pass DOM references in the constructors.
  8. 在加载数据之后,需要实例化对象数组,以便在构造函数中传递DOM引用。
  9. However, calling setState() inside componentDidUpdate() triggers an infinite loop so had to set the object array directly and independently from state.
  10. 但是,在componentDidUpdate()中调用setState()会触发无限循环,因此必须直接设置对象数组并独立于状态。
  11. When creating DOM elements from an array, React does not automatically assign the event handler to the particular element. In other words, it must be passed the array index so that can be used to access its values in the arrays.
  12. 从数组创建DOM元素时,React不会自动将事件处理程序分配给特定元素。换句话说,它必须传递数组索引,以便可以用于访问数组中的值。

Whew, I think that's it. Hope this helps others.

哇,我想就是这样。希望这有助于其他人。

And I would just conclude by saying, give React a try without JSX. It's really not that bad :)

最后我会说,给React一个没有JSX的尝试。这真的不是那么糟糕:)

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