这个特定的 ReactJs 代码如何执行初学者问题?

IT技术 javascript reactjs
2022-08-03 00:39:25

我是初学者,正在阅读大量代码,现在我想知道下面的代码
我了解这段代码在做什么我需要澄清的是代码流。

我在运行它时看到图像加载:

  1. React 是从上到下执行代码的吗?
  2. PlaceholderImages 异步获取正确的图像,但是App如果需要时间,组件会开始渲染没有图像吗?如果是这样,我看不到任何setState通知App我大概听错了!

此代码来自此Sandbox

这是 index.js

import React from "react";
import ReactDOM from "react-dom";
import Masonry from "./Masonry";
import VerticalMasonry from "./VerticalMasonry";
import { sample, uniqueId } from "lodash";
import PlaceholderImages from "./PlaceholderImages";
import ItemRenderer from "./ItemRenderer";

PlaceholderImages().then(images => {
  function addItems(amount = 10) {
    return new Array(amount).fill("").map(i => {
      const id = uniqueId();
      const image = sample(images);

      const width = 480;
      const height = Math.round((480 / image.width) * image.height);
      const imageUrl = `https://picsum.photos/${width}/${height}?image=${
        image.id
      }`;

      return {
        id,
        key: id,
        ratio: 1 / (image.width / image.height),
        backgroundImage: `url(${imageUrl})`,
        background: `rgb(${Math.ceil(Math.random() * 256)}, ${Math.ceil(
          Math.random() * 256
        )}, ${Math.ceil(Math.random() * 256)})`,
        title: "Lorem ipsum dolor sit amet",
        description:
          "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
      };
    });
  }

  let Items = addItems();

  class App extends React.Component {
    state = {
      columns: 3,
      items: Items,
      gutter: 16,
      outerGutter: true,
      debug: true,
      vertical: true
    };

    addItems() {
      this.setState({
        items: this.state.items.concat(addItems(20))
      });
    }

    render() {
      const {
        items,
        width,
        gutter,
        outerGutter,
        debug,
        vertical,
        fullscreen
      } = this.state;

      const LeComponent = vertical ? Masonry : VerticalMasonry;

      return (
        <div>
          <div
            style={{
              position: fullscreen && "absolute",
              zIndex: 2
            }}
          >
            <label htmlFor="gutter">Gutter</label>
            <input
              id="gutter"
              type="number"
              step={1}
              min={0}
              max={32}
              value={gutter}
              onChange={e => {
                this.setState({
                  gutter: parseInt(e.target.value)
                });
              }}
            />
            <button
              onClick={() => this.setState({ outerGutter: !outerGutter })}
            >
              Outer Gutter: {outerGutter ? "On" : "Off"}
            </button>
            <button onClick={() => this.setState({ debug: !debug })}>
              debug
            </button>
            <button onClick={() => this.setState({ vertical: !vertical })}>
              {vertical ? "Vertical" : "Horizontal"}
            </button>
            <button onClick={() => this.setState({ width: 360 })}>360</button>
            <button onClick={() => this.setState({ width: 480 })}>480</button>
            <button onClick={() => this.setState({ width: 640 })}>640</button>
            <button onClick={() => this.setState({ width: 728 })}>728</button>
            <button onClick={() => this.setState({ width: 960 })}>960</button>
            <button onClick={() => this.setState({ width: "100%" })}>
              100%
            </button>
            <button onClick={() => this.setState({ fullscreen: !fullscreen })}>
              {fullscreen ? "Fullscreen off" : "Fullscreen on"}
            </button>
          </div>
          <div
            style={{
              width,
              height: !fullscreen && 600,
              position: fullscreen ? "initial" : "relative",
              margin: "0 auto"
            }}
          >
            <LeComponent
              infinite
              items={items}
              itemRenderer={ItemRenderer}
              gutter={gutter}
              outerGutter={outerGutter}
              extraPx={0}
              debug={debug}
              rows={{
                0: 1,
                320: 2,
                480: 3,
                640: 4
              }}
              cols={{
                0: 1,
                360: 2,
                640: 2,
                960: 3,
                1280: 4,
                1400: 5,
                1720: 6,
                2040: 7,
                2360: 8
              }}
              onEnd={() => {
                this.addItems();
              }}
            />
            <style>
              {`body {
                background-color:  white;
              }`}
            </style>
          </div>
        </div>
      );
    }
  }

  const rootElement = document.getElementById("root");
  ReactDOM.render(<App />, rootElement);
});

这是 PlaceholderImages.js

import axios from "axios";
import { sampleSize } from "lodash";

export default async () => {
  return new Promise((resolve, reject) => {
    axios.get("https://picsum.photos/list").then(res => {
      console.log(res.data[0]);
      return resolve(sampleSize(res.data, 50));
    });
  });
};
1个回答

PlaceholderImages().then(images => {...

在这里进入你的堆栈的第一件事是方法PlaceholderImages因此,您应该查看它的代码。

您将看到它返回一个带有两个参数的新 Promise:2 个回调函数,一个在成功的情况下(解决),另一个在您的 API 请求失败(拒绝)的情况下。当您使用 GET 方法axios(第三方库)执行 HTTP 请求时,会发生 API 请求。

同样,您有一个异步函数,并且该.then()方法仅在axos.get()返回某些内容时才被调用。如果它从不返回任何内容,则您将永远不会执行该then()函数。

此时,您的堆栈(LIFO 服务规程)将具有以下执行方法:

PlaceholderImages() -> 匿名函数()* -> new Promise() -> axios.get();

PlaceholderImages()在执行所有其他方法之前不会执行。如果该axios.get()方法未能收集到所需的数据,一旦您回到PlaceholderImages().then()代码部分,您将没有任何图像可以渲染。因此,无论如何都不会渲染任何内容。