react中使用构建缓存_如何使用React构建基本版本的Product Hunt

react中使用构建缓存

by Emmanuel Yusufu

通过伊曼纽尔·尤苏夫

如何使用React构建基本版本的Product Hunt (How to build a basic version of Product Hunt using React)

This example and design shares what I’ve learned from the book Fullstack React. I highly recommend it as a good resource for learning React and it’s ecosystem technologies. check it out here: fullstackreact.com.

这个示例和设计分享了我从Fullstack React一书中学到的知识。 我强烈推荐它作为学习React及其生态系统技术的良好资源。 在这里查看: fullstackreact.com

Imagine that as a developer, you have been tasked with creating an MVP for a startup product that needs to be demonstrated to potential investors.

想象一下,作为一名开发人员,您承担了为启动产品创建MVP的任务,该产品需要向潜在投资者展示。

The application is a voting application inspired by Product Hunt and Reddit. In the application, products are displayed in a collection. Users can upvote the best products, and the application will automatically sort them according to the number of votes, placing the highest before the lowest.

该应用程序是一个受Product Hunt和Reddit启发的投票应用程序。 在应用程序中,产品显示在一个集合中。 用户可以对最好的产品进行投票,应用程序将根据票数自动对它们进行排序,将最高的产品放在最低的产品上。

The features of the app we will be building are very simple:

我们将要构建的应用程序的功能非常简单:

  • Users can view the existing/displayed products.

    用户可以查看现有/显示的产品。
  • Users can upvote products that delight them.

    用户可以对令他们满意的产品进行投票。
  • Products are sorted automatically according to vote count.

    产品会根据投票数自动排序。

You can view the demo here.

您可以在此处查看演示

步骤1:首先要做的事 (Step 1: first things first)

Fist of all, head over to Github and download the starter folder I’ve already created with the necessary set up for our application here. Copy the URL provided by the green clone/download button and run in your preferred path on your command line. You must have git already installed.

所有的拳,头部到Github上下载启动文件夹,我必要为我们的应用程序已经创建了这里 。 复制绿色克隆/下载按钮提供的URL ,并在命令行上的首选路径中运行。 您必须已经安装了git。

git clone URL

Once the folder is downloaded, open it in your code editor and observe the folder files and structure. It look like this:

下载文件夹后,在代码编辑器中将其打开,并观察文件夹的文件和结构。 看起来像这样:

├───src
|    ├───app.js
|    ├───seed.js
|    ├───style.css
└───vendor
    ├───bootstrap-3.3.7-dist
    ├───font-awesome-4.7.0
    ├───react.js
    ├───react-dom.js
    └───babel-standalone.js

Note: Your code editor should have a live server. This allows us to serve the files to our browser to view our work. Make sure to install the extension for your preferred code editor.

注意:您的代码编辑器应具有活动服务器。 这使我们可以将文件提供给浏览器以查看我们的工作。 确保为您的首选代码编辑器安装扩展。

Under the src folder there are app.js and seed.js files. The app.js file is where we will write most of the code for our application. The seed.js file already contains the data collection of the products to be displayed.

在src文件夹下,有app.jsseed.js文件。 在app.js文件中,我们将为应用程序编写大部分代码。 seed.js文件已经包含要显示的产品的数据收集。

Our seed.js file contains the following code

我们的seed.js文件包含以下代码

window.Seed = (function () {
    function generateVoteCount() {
      return Math.floor((Math.random() * 50) + 15);
    }
    
    const products = [
      {
        id: 1,
        title: 'Yellow Pail',
        description: 'On-demand sand castle construction expertise.',
        url: '#',
        votes: generateVoteCount(),
        submitterAvatarUrl: 'images/avatars/daniel.jpg',
        productImageUrl: 'images/products/image-aqua.png',
      },
                                ...
    ];
    
    return { products: products };
    
  }());

This code creates a function generateVoteCount() which we will explain later and a products array that contains the data of our products. They are wrapped as a self-invoking function, and are attached to the window object of our browser. This way we can access them anywhere we want them.

这段代码创建了一个函数generateVoteCount() (我们将在后面解释)以及一个包含我们产品数据的products数组。 它们被包装为自调用函数,并附加到浏览器的window对象。 这样,我们可以在任何需要它们的地方访问它们。

The Seed function eventually returns an object with a property of products and a value of products. This means that, if we execute Seed.products, we should have every product object returned to us.

Seed功能最终会返回一个对象与产品的属性和值products 。 这意味着,如果我们执行Seed.products ,我们应该将每个产品对象都返回给我们。

The react.js file is the code containing the React core itself. Also, react-dom.js is the code that helps us render out React components we’ve created in HTML DOM. Finally, babel-standalone.js is the Babel code that transpiles the advanced JSX and ES6 code we will be working with into ES5 code (the most common JavaScript specification that most old and current browsers support today).

react.js文件是包含React核心本身的代码。 另外, react-dom.js是帮助我们渲染在HTML DOM中创建的React组件的代码。 最后, babel-standalone.js是将我们将使用的高级JSX和ES6代码转换为ES5代码(当今大多数旧版本和当前浏览器都支持的最常见JavaScript规范)的Babel代码。

步骤2:建立元件 (Step 2: create components)

We need to create two React components. We will call the parent component ProductList , and the collection of children components it houses will be Procuct .

我们需要创建两个React组件。 我们将把父组件称为ProductList ,并将其包含的子组件的集合称为Procuct

Inside the app.js file, create the parent component by doing this:

在app.js文件中,通过执行以下操作创建父组件:

class ProductList extends React.Component {
    render() {
        const products = Seed.products.map((product) => (
            <Product 
            id={product.id}
            title={product.title}
            description={product.description}
            url={product.url}
            votes={product.votes}
            submitterAvatarUrl={product.submitterAvatarUrl}
            productImageUrl={product.productImageUrl}
            />
        ));
        return (
            <div className="container">
                <h1>Popular products</h1>
                <hr />
                {products}
            </div>
        );
    }
}
ReactDOM.render(<ProductList />, document.getElementById('content'));

In the parent component, we intend to create a child component based on each object accessible from Seed.products . So we set up some props. Now let’s actually declare the child component still in the same file called Product :

在父组件中,我们打算基于从Seed.products可访问的每个对象创建子组件。 因此,我们设置了一些道具。 现在,让我们实际声明子组件仍在名为Product的同一文件中:

class Product extends React.Component {
    render() {
        return (
          <div className='container'>
            <div className="row">
            <div className='col-md-12'>
                <div className="main">
                <div className="image">  
                    <img src={this.props.productImageUrl} />
                </div> 
                <div className='header'>
                    <a>
                        <i className='fa fa-2x fa-caret-up' />
                    </a>
                    {this.props.votes}
                </div>
                <div className='description'>
                    <a href={this.props.url}>
                        {this.props.title}
                    </a>
                    <p>{this.props.description}
                    </p>
                </div>
              <div className='extra'>
                <span>Submitted by:</span>
                <img
                  className='avatar'
                  src={this.props.submitterAvatarUrl}
                />
              </div>
              </div>
            </div>
            </div>
          </div>
        );
      }
}

We are able to reference React.Component and ReactDOM.render because we have already loaded the react.js and react-dom.js files. They are available for use even though we’re currently in the app.js file. Having created the component, ReactDOM.render(whatComponent, where) renders it to the DOM.

我们能够引用React.ComponentReactDOM.render因为我们已经加载了react.js和react-dom.js文件。 即使我们当前在app.js文件中,它们也可以使用。 创建组件后, ReactDOM.render(whatComponent, where)将其呈现到DOM。

Running your live server, you should have the following screen:

运行实时服务器,您应该具有以下屏幕:

步骤3:添加互动 (Step 3: add interactivity)

So far, we have been able to code the components of our app — but they are still static. How can we make them interactive?

到目前为止,我们已经能够对应用程序的组件进行编码,但是它们仍然是静态的。 我们如何使它们互动?

In coding React apps, follow this general process:

在编写React应用程序的代码时,请遵循以下一般过程:

  • Divide the app UI into components

    将应用程序用户界面分为组件
  • Build a static version of the app

    构建该应用程序的静态版本
  • Determine what data is a state

    确定什么数据是状态
  • Determine in what components each piece of the state should live

    确定每个状态应包含在哪些组件中
  • Hard code initial states

    硬代码初始状态
  • Add inverse data flow from child to parent via props

    通过道具添加从子级到父级的逆向数据流
  • Add server communication

    添加服务器通信

We wont be doing all of the above, but lets get going with state. The only piece of data in our app that can be considered stateful or ever-changing is the number of votes. Remember: that is a property in the collection of products in our seed.js file. Votes are in each product object, so it represents our state.

我们不会做上述所有事情,但是让我们开始吧state 。 我们应用程序中唯一可以被认为是有状态或不断变化的数据是投票数。 请记住:那是我们seed.js文件中产品集合的一个属性。 投票存在于每个product对象中,因此代表了我们的状态。

Knowing our state, where do we initialize it? States in React are self-contained in certain components, unlike props that are passed down. The number of votes as a state is owned by <Product /> , but since the collection of products we have are generated from <ProductList />, we initialize the state there. In <ProductList />, do this before the render() method:

知道我们的状态,我们应该在哪里初始化它? React中的状态是独立的,包含在某些组件中,这与传递的props不同。 作为状态的投票数由<Product />拥有,但是由于我们拥有的产品集合是从<ProductList />生成的,因此我们在此处初始化状态。 在<ProductList /> ,在render()方法之前执行此操作:

constructor() {
        super();
        this.state = {
            products: []
        }
    }

When initializing state in a component, we try to define what it should look like while keeping it empty. Our products are an array, so we use an empty array. We initialize it inside constructor() {} , because that's the piece of code that runs when our component is created.

在初始化组件中的状态时,我们尝试定义其外观,同时使其保持空白。 我们的产品是一个数组,因此我们使用一个空数组。 我们在constructor() {}对其进行初始化,因为这是在创建组件时运行的代码。

Lets make our component read products from its own state instead of from a file. Add:

让我们的组件从其自身的状态而不是从文件中读取products 。 加:

componentDidMount() { 
   this.setState({ products: Seed.products }) 
 }

to set the state to use. Also update const products = Seed.products to const products = this.state.products. To make JavaScript sort it according to the highest number of votes, write this instead:

设置要使用的状态。 const products = Seed.products const products = this.state.products更新为const products = this.state.products 。 要使JavaScript根据最高投票数对它进行排序,请编写以下代码:

const products = this.state.products.sort((a, b) {
    b.votes - a.votes
});

The JavaScript sort(); uses a compare function inside. You could find out about this in a documentation.

JavaScript sort(); 在内部使用比较功能 。 您可以在文档中找到有关此内容的信息。

第4步:处理投票 (Step 4: handle upvoting)

Let’s head over to the hyperlink surrounding the font-awesome, caret-up icon and create a function using onClick.

让我们转到字体真棒的尖号图标周围的超链接,并使用onClick创建函数。

<a onClick={passTheId}>
    <i className='fa fa-2x fa-caret-up' />
 </a>

After we’ve defined the function, lets actually create it. Inside the Product component, create a passTheId(); function:

定义函数后,让我们实际创建它。 在产品组件内部,创建一个passTheId(); 功能:

constructor() {
        super();
        this.passTheId = this.passTheId.bind(this);
    }
    passTheId() {
        console.log('Id will be passed');
    }

We bound the function to the this keyword, because only in-built functions like render() have access to use that word.

我们将函数绑定到this关键字,因为只有诸如render()之类的内置函数才能使用该词。

Lets create another function in the ProductList component. This one will update the state working with the handleUpVote function of the Product component.

让我们在ProductList组件中创建另一个函数。 这将使用Product组件的handleUpVote函数更新状态。

handleProductUpVote = (productId) => {
    const nextProducts = this.state.products.map((product) => {
      if (product.id === productId) {
        return Object.assign({}, product, {
          votes: product.votes + 1,
        });
      } else {
        return product;
      }
    });
    this.setState({
      products: nextProducts,
    });
  }

States in React should be treated as immutable. That is, they should not be modified directly. The above function will do that using JavaScript’s Object.assign();by creating a seemingly new array called nextProducts . This is similar to the existing state, but has a change in the number of votes. nextProductsis then set as the new state. It seems weird to do things this way, but this is what the React team recommends to improve performance.

React中的状态应被视为不可变的。 也就是说,不应直接修改它们。 上面的函数将使用JavaScript的Object.assign();完成此操作Object.assign(); 通过创建一个看似新的数组nextProducts 。 这与现有状态相似,但票数有所变化。 然后将nextProducts设置为新状态。 这样做似乎很奇怪,但这是React团队建议提高性能的建议。

We want to pass the ID of the product from the child Product component to the parent ProductList component, so lets make handleProductUpVote available to the child as props:

我们希望将产品的ID从子Product组件传递到父ProductList组件,因此让handleProductUpVote作为道具可用于子:

const productComponents = products.map((product) => (
      <Product
        key={'product-' + product.id}
        id={product.id}
        title={product.title}
        description={product.description}
        url={product.url}
        votes={product.votes}
        submitterAvatarUrl={product.submitterAvatarUrl}
        productImageUrl={product.productImageUrl}
        onVote={this.handleProductUpVote}
      />
    ));

We added onVote={this.handleProductUpVote}. So at the child level, we can access it through this.props

我们添加了onVote={this.handleProductUpVote} 。 因此,在子级,我们可以通过this.props访问它

passTheId() {
        console.log('Id will be passed');
        this.props.onVote(this.props.id)
    }

Your entire app.js file should look like this:

您的整个app.js文件应如下所示:

class ProductList extends React.Component {
    state = {
        products: [],
      };
      componentDidMount() {
        this.setState({ products: Seed.products });
      }
      handleProductUpVote = (productId) => {
        const nextProducts = this.state.products.map((product) => {
          if (product.id === productId) {
            return Object.assign({}, product, {
              votes: product.votes + 1,
            });
          } else {
            return product;
          }
        });
        this.setState({
          products: nextProducts,
        });
      }
    render() {
        const products = this.state.products.sort((a, b) => (
            b.votes - a.votes
        ));
        const productComponents = products.map((product) => (
            <Product
              key={'product-' + product.id}
              id={product.id}
              title={product.title}
              description={product.description}
              url={product.url}
              votes={product.votes}
              submitterAvatarUrl={product.submitterAvatarUrl}
              productImageUrl={product.productImageUrl}
              onVote={this.handleProductUpVote}
            />
          ));
        return (
            <div className="container">
                <h1>Popular products</h1>
                <hr />
                {productComponents}
            </div>
        );
    }
}
class Product extends React.Component {
    constructor() {
        super();
        this.passTheId = this.passTheId.bind(this);
    }
    passTheId() {
        console.log('Id will be passed');
        this.props.onVote(this.props.id);
    }
    render() {
        return (
          <div className='container'>
            <div className="row">
            <div className='col-md-12'>
                <div className="main">
                <div className="image">  
                    <img src={this.props.productImageUrl} />
                </div> 
                <div className='header'>
                    <a onClick={this.passTheId}>
                        <i className='fa fa-2x fa-caret-up' />
                    </a>
                    {this.props.votes}
                </div>
                <div className='description'>
                    <a href={this.props.url}>
                        {this.props.title}
                    </a>
                    <p>
                        {this.props.description}
                    </p>
                </div>
              <div className='extra'>
                <span>Submitted by:</span>
                <img
                  className='avatar'
                  src={this.props.submitterAvatarUrl}
                />
              </div>
              </div>
            </div>
            </div>
          </div>
        );
      }
}
ReactDOM.render(<ProductList />, document.getElementById('content'));

Refresh your browser and you should see the working app. View demo.

刷新浏览器,您应该会看到正在运行的应用程序。 查看演示

Feel free to share, comment or ask questions. For the final code, visit this github link and clone to your computer.

随时分享,评论或提问。 对于最终代码,请访问此github链接并克隆到您的计算机。

If you enjoyed this article, give me some claps so more people see it. Thank you for reading.

如果您喜欢这篇文章,请给我一些鼓掌,以便更多的人看到。 感谢您的阅读。

You can read more of my writing on my blog: Stellar Code.

您可以在我的博客: Stellar Code上阅读更多我的作品。

翻译自: https://www.freecodecamp.org/news/how-to-build-a-basic-version-of-product-hunt-using-react-f87d016fedae/

react中使用构建缓存

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值