react中使用构建缓存

by Matthew Choi

由Matthew Choi

使用React构建Tesla的电池范围计算器(第1部分) (Building Tesla’s Battery Range Calculator with React (Part 1))

In this series of articles, I will walk you through the process of building Tesla’s battery range calculator with React.

在本系列文章中,我将引导您完成使用React构建Tesla电池范围计算器的过程。

In this tutorial, we’ll build the React version of Todd Motto’s Building Tesla’s battery range calculator with Angular 2 reactive forms.

在本教程中,我们将使用Angular 2React形式构建 Todd Motto的Building Tesla电池范围计算器的React版本。

So this post will reuse some materials (data, images, and css style). We will focus on rebuilding it in React way.

因此,本文将重用一些资料(数据,图像和CSS样式)。 我们将专注于以React方式对其进行重建。

This is the final GIF image of our application.

这是我们应用程序的最终GIF图像。

? Check out the live version before we get started.

? 在开始之前,请先检查一下最新版本 。

? You can also check out the source code.

? 您也可以签出我们的代码。

Now let’s create the application step by step.

现在,让我们逐步创建应用程序。

Note that you may need some basic React knowledge to follow this tutorial. See the following resources:

请注意,您可能需要一些基本的React知识才能遵循本教程。 请参阅以下资源:

  • React Official Documentation

    React官方文档

  • React: Getting Started and Concepts

    React:入门和概念

1.项目设置和create-react-app (1. Project Setup and create-react-app)

1.1要求 (1.1 Requirements)

The tools and versions I used during the implementation of this app:

我在实现此应用程序时使用的工具和版本:

node v7.3.0npm v3.10.10

1.2创建React应用 (1.2 create-react-app)

creat-react-app is a new tool open-sourced by Facebook for fast react application development, which allows you to easily start React applications without complex setups. You can easily install our project react-tesla-range-calculator and start the application right away with the following command:

creat-react-app是Facebook开源的用于快速React应用程序开发的新工具,它使您无需复杂的设置即可轻松启动React应用程序。 您可以轻松安装我们的项目react-tesla-range-calculator并使用以下命令立即启动应用程序:

  • npm install -g create-react-app
    npm install -g create-react-app
  • create-react-app react-tesla-range-calculator
    创建React应用程序React特斯拉范围计算器
  • cd react-tesla-range-calculator
    cd react-tesla-range-calculator
  • npm start
    npm开始

Create a new application through creat-react-app and open http://localhost:3000/ to check the generated application.

通过creat-react-app创建一个新应用creat-react-app然后打开http://localhost:3000/来检查生成的应用程序。

If you see the screen below, the project has been successfully set up.

如果您看到下面的屏幕,则说明项目已成功设置。

Before we start the project, we need to touch the project source structure. Just leave the files we need for the project and delete the rest. (Delete App.test.js, logo.svg)

在开始项目之前,我们需要触摸项目源代码结构。 只需保留项目所需的文件,然后删除其余文件即可。 (删除App.test.js,logo.svg)

Now our src directory should look like this:

现在,我们的src目录应如下所示:

src - App.css - App.js - index.css - index.js

Here is project source structure :

这是项目源代码结构:

1.3项目入口点 (1.3 Project Entry Point)

First we need to set the entry point to start our Tesla app. Thankfully it’s already created by create-react-app.

首先,我们需要设置入口点以启动我们的Tesla应用程序。 幸运的是,它已经由create-react-app

src/App.js is the entry point for our app.

src/App.js是我们应用程序的切入点。

First up, change your App.js to this:

首先,将您的App.js更改为:

import React, { Component } from 'react';import './App.css';
class App extends Component {  render() {    return (      <div>        <h2>Let's get started</h2>      &lt;/div>    );  }}
export default App;

When you save the file, it will be automatically compiled and you can see the updated screen.

保存文件时,将自动编译该文件,您可以看到更新的屏幕。

1.4项目图像/资产 (1.4 Project images/assets)

All images required for this project can be downloaded from:

该项目所需的所有图像都可以从以下网站下载:

  • images Download

    图片下载

  • favicon.ico Download

    favicon.ico 下载

Unpack assets.zip and place all images in the src/assets directory and place the downloaded favicon.ico in the source root.

解压缩assets.zip并将所有图像放在src/assets目录中,并将下载的favicon.ico放在源根目录中。

react-tesla-range-calculator/src/assets

Any time you feel like if you’ve missed something or unsure if you’re doing right, you can refer to the source code as a reference.

任何时候,如果您想错过某件事或不确定自己做得是否正确,都可以参考源代码作为参考。

1.5数据服务 (1.5 Data service)

The data you can get from Tesla site is hard-coded and very large, so we’ll use Todd’s new version of the data to make it easier to use. link

您可以从Tesla站点获得的数据是硬编码的,并且非常大,因此我们将使用Todd的新版本数据来简化使用。 链接

We do not use the Injectable decorator used in Angular2, so we will copy only the export part, just save it in src/services/BatteryService.js for now. Later, we will use import it in TeslaBattery container.

我们不使用Angular2中使用的Injectable decorator ,因此我们仅复制export部分,仅将其保存在src/services/BatteryService.js中。 稍后,我们将在TeslaBattery容器中使用import

We will revisit this data service later.

我们稍后将重新访问该数据服务。

2.分解UI (2. Breaking Down the UI)

Almost all React application UIs consist of a composition of components. For example, a weather app consists of a component that displays a local name, a component that displays the current temperature, and a graph component that represents a five-day forecast. For this reason, it is a good idea to decompose the UI into component units before developing the React app.

几乎所有的React应用程序UI都由组件组成。 例如,天气应用程序由显示本地名称的组件,显示当前温度的组件和表示五天天气预报的图形组件组成。 因此,在开发React应用程序之前,最好将UI分解为组件单元。

See Thinking in React for an approach to looking at an application as a combination of components.

有关将应用程序视为组件组合的方法,请参见React中的思考 。

The layout of this application is shown below

该应用程序的布局如下所示

The UI is represented by a component tree as follows.

UI由组件树表示,如下所示。

<App> -- Application entry point <Header></Header>  <TeslaBattery> -- Container   <TeslaCar />     -- Presentational Component  <TeslaStats />   -- Presentational Component      <TeslaCounter /> -- Presentational Component  <TeslaClimate /> -- Presentational Component  <TeslaWheels />  -- Presentational Component  <TeslaNotice />  -- Presentational Component  </TeslaBattery></App>

2.1容器和演示组件 (2.1 Container and Presentational Components)

In the above mentioned component tree, we can see that it is classified as Container Component and Presentational Component.

在上面提到的组件树中,我们可以看到它被分类为Container ComponentPresentational Component

This is a useful pattern that can be used when developing an application with React. It is easier to reuse by dividing components into two categories.

这是一个有用的模式,可以在使用React开发应用程序时使用。 通过将组件分为两类,可以更轻松地重用。

* Container Component (stateful component): - Are concerned with how things work. - In general, except for some wrapping divs, they do not have their   own DOM markup and have no style. - Provide data and actions to presentational or other container components. - Are often stateful, as they tend to serve as data sources.
* Presentational Component (stateless component): - Are concerned with how things look. - Usually have some DOM markup and styles of their own. - Receive data and callbacks exclusively via props. - Rarely have their own state (when they do, it’s UI state rather than data).

What are the benefits of using these patterns?

使用这些模式有什么好处?

  • Better separation of concerns
    更好地分离关注点
  • Better reusability
    更好的可重用性
  • Extract layout components to prevent duplication
    提取布局组件以防止重复

For more details, see Presentational and Container Components

有关更多详细信息,请参见外观和容器组件。

3.标头组件 (3. Header component)

Let’s create our first React component, Header. The Header component is simply a black bar with the Tesla logo and text.

让我们创建第一个React组件HeaderHeader组件只是带有特斯拉徽标和文字的黑条。

Create the src/components/Header directory, create a Header.js file in it, and enter the following code:

创建src/components/Header目录,在其中创建Header.js文件,然后输入以下代码:

import React from 'react';import './Header.css';import logoUrl from '../../assets/logo.svg';
const Header = () => (  <div className="header">    <img src={logoUrl} alt="Tesla" />  </div>)
export default Header;

Here, the component is in the form of a function (ES6 Arrow Function). A component declared in this form is called a functional component. If there is no state and the lifecyclemethod is not needed, it is a good pattern to declare it as a function type. Functional components are suitable for Presentational Component because they have no state and they depend only on the props that is received from higher components.

在此,组件采用函数形式( ES6 Arrow Function )。 以这种形式声明的组件称为functional component 。 如果没有state并且不需要lifecycle方法,则将其声明为函数类型是一个很好的模式。 功能组件适用于Presentational Component因为它们没有状态,并且仅取决于从更高组件接收到的props

3.1标头组件样式 (3.1 Header Component Style)

Create a Header.css file in the src/components/Header directory and type the following style:

src/components/Header目录中创建一个Header.css文件,然后键入以下样式:

.header {  padding: 25px 0;  text-align: center;  background: #222;}
.header img {  width: 100px;  height: 13px;}

There are a number of ways to apply styles to components, but here we will create each component directory in the src/components directory and pair js and css files each time we create a component.

有多种将样式应用于组件的方法,但是在这里,我们将在src/components目录中创建每个组件目录,并在每次创建组件时将jscss文件配对。

3.2在App Container中导入Header组件 (3.2 Import Header component in App Container)

Now that you’ve created the Header component, let’s use import in the entry point App.js.

现在,您已经创建了Header组件,让我们在入口点App.js使用import

import React, { Component } from 'react';import './App.css';import Header from './components/Header/Header';
class App extends Component {  render() {    return (      <div className="App">        <Header />          </div>    );  }}
export default App;

When you save all the modified files, they will be updated automatically and you should see the Tesla logo as follows:

保存所有修改后的文件后,它们将自动更新,您应该看到Tesla徽标,如下所示:

4. Tesla电池容器 (4. TeslaBattery Container)

In our app, the TeslaBattery component is responsible for creating and managing data and state as Container Component, passing it to other Presentational Components, performing a callback function and changing its state.

在我们的应用程序中, TeslaBattery组件负责创建和管理数据和状态(作为Container Component ,将其传递给其他Presentational Components ,执行回调函数并更改其状态。

By inheriting React.Component, TeslaBattery must have a render method, optionally it can initialize its state through the constructor, and implement other methods such as lifecycle callbacks.

通过继承React.ComponentTeslaBattery必须具有render方法,可以选择通过constructor初始化其状态,并实现其他方法,例如生命周期回调。

lifecycle callbacks are useful when you want to render or update components, or to receive notifications at different stages of lifecycle.

当您要呈现或更新组件,或在lifecycle不同阶段接收通知时, lifecycle lifecycle callbacks非常有用。

Create the src/containers directory, create a TeslaBattery.js file in it, and enter the following code:

创建src/containers目录,在其中创建一个TeslaBattery.js文件,然后输入以下代码:

import React from 'react';import './TeslaBattery.css';
class TeslaBattery extends React.Component {  render() {    return (      <form className="tesla-battery">        <h1>Range Per Charge</h1>      &lt;/form>    )  }}
export default TeslaBattery;

4.1 Tesla电池容器样式 (4.1 TeslaBattery Container Style)

TeslaBattery.css only holds a minimal style.

TeslaBattery.css仅具有最小风格。

.tesla-battery {  width: 1050px;  margin: 0 auto;}
.tesla-battery h1 {  font-family: 'RobotoNormal';  font-weight: 100;  font-size: 38px;  text-align: center;  letter-spacing: 3px;}

The components to be created in the future will be configured in the TeslaBattery container sequentially.

将来要创建的组件将在TeslaBattery容器中依次配置。

5. TeslaNotice组件 (5. TeslaNotice Component)

Let’s create a static text part with a TeslaNotice component.

让我们用TeslaNotice组件创建一个静态文本部分。

Create the src/components/TeslaNotice directory, create a TeslaNotice.js file in it, and enter the following code:

创建src/components/TeslaNotice目录,在其中创建一个TeslaNotice.js文件,然后输入以下代码:

import React from 'react';import './TeslaNotice.css';
const TeslaNotice = () => (  <div className="tesla-battery__notice">    <p>      The actual amount of range that you experience will vary based      on your particular use conditions. See how particular use conditions      may affect your range in our simulation model.    </p>    <p>      Vehicle range may vary depending on the vehicle configuration,      battery age and condition, driving style and operating, environmental      and climate conditions.    </p>  </div>)
export default TeslaNotice;

5.1 TeslaNotice组件样式 (5.1 TeslaNotice Component Style)

Next up, create src/components/TeslaNotice directory, create TeslaNotice.cssin it and add these styles to your TeslaNotice.css file:

接下来,创建src/components/TeslaNotice目录,在其中创建TeslaNotice.css并将以下样式添加到您的TeslaNotice.css文件中:

.tesla-battery__notice {    margin: 20px 0;    font-size: 15px;    color: #666;    line-height: 20px;}

5.2在TeslaBattery容器中导入TeslaNotice组件 (5.2 Import TeslaNotice component in TeslaBattery Container)

Next, import TeslaNotice component in TeslaBattery.js:

接下来,在TeslaBattery.js导入TeslaNotice组件:

...import TeslaNotice from '../components/TeslaNotice/TeslaNotice';
class TeslaBattery extends React.Component {  render() {    return (      <form className="tesla-battery">        <h1>Range Per Charge</h1>        <TeslaNotice />      </form>    )  }}...

We will continue in such a way that components are created in this pattern and imported from the TeslaBattery container.

我们将继续以这种方式创建组件并从TeslaBattery容器导入组件的方式。

6. TeslaCar组件 (6. TeslaCar Component)

Now let’s render a nice Tesla car image with wheel animation.

现在,让我们用车轮动画渲染漂亮的特斯拉汽车图像。

Create the src/components/TeslaCar directory, create a TeslaCar.js file in it, and inside your TeslaCar.js file :

创建src/components/TeslaCar目录,在其中创建一个TeslaCar.js文件,并在您的TeslaCar.js文件内部:

import React from 'react';import './TeslaCar.css';
const TeslaCar = (props) => (  <div className="tesla-car">    <div className="tesla-wheels">      <div className={`tesla-wheel tesla-wheel--front tesla-wheel--${props.wheelsize}`}></div>      <div className={`tesla-wheel tesla-wheel--rear tesla-wheel--${props.wheelsize}`}></div>    </div>  </div>);
TeslaCar.propTypes = {  wheelsize: React.PropTypes.number}
export default TeslaCar;

Here we specify propTypes using the React built-in typechecking. In development mode, React checks props passed to the component. (Only in development mode for performance reasons)

在这里,我们使用React内置的类型propTypes来指定propTypes 。 在开发模式下,React检查传递给组件的props 。 (仅出于性能考虑处于开发模式)

For each props attribute, React attempts to find it in the component’s propType object to determine whether (1) prop is expected (2) prop is the correct type. In this case, the TeslaCar component expects the props attribute wheelsize and specifies that it is a number type. If the wrong value is provided, a warning appears in the JavaScript console, which is useful for fixing potential bugs in early stage.

对于每个props属性,React尝试在组件的propType对象中找到它,以确定是否(1)prop是期望的(2)prop是正确的类型。 在这种情况下, TeslaCar组件希望props属性的wheelsize并指定它是number类型。 如果提供了错误的值,则会在JavaScript控制台中显示一条警告,这对于在早期修复潜在的错误很有用。

More information on React.PropTypes can be found here

有关React.PropTypes更多信息可以在这里找到

Update: New Deprecation Warnings in React 15.5

更新:React 15.5中的新弃用警告

In 15.5, instead of accessing PropTypes from the main React object, install the prop-typespackage and import them from there:

在15.5中,安装prop-types包并从那里导入它们,而不是从主React对象访问PropTypes

https://facebook.github.io/react/blog/2017/04/07/react-v15.5.0.html#migrating-from-react.proptypes

https://facebook.github.io/react/blog/2017/04/07/react-v15.5.0.html#migrating-from-react.proptypes

// Before (15.4 and below) import React from 'react';
import React from 'react';import './TeslaCar.css';
.........................
TeslaCar.propTypes = {  wheelsize: React.PropTypes.number}
export default TeslaCar;
// After (15.5) import React from 'react'; import PropTypes from 'prop-types';import './TeslaCar.css';
...........................
TeslaCar.propTypes = {   wheelsize: PropTypes.number} export default TeslaCar;

6.1 TeslaCar组件样式 (6.1 TeslaCar Component Style)

Next, create a TeslaCar.css file in the src/components/TeslaCar directory and give it the following style. Since the code is long and omitted here, let’s check the source code.

接下来,在src/components/TeslaCar目录中创建TeslaCar.css文件,并为其指定以下样式。 由于代码很长,在这里省略了,让我们检查源代码 。

.tesla-car {  width: 100%;  min-height: 350px;  background: #fff url(../../assets/tesla.jpg) no-repeat top center;  background-size: contain; }
.tesla-wheels {  height: 247px;  width: 555px;  position: relative;  margin: 0 auto; }
...

This gives us our animations and the component base for the car, which is displayed as background images.

这为我们提供了动画和汽车的零部件库,将其显示为背景图像。

6.2在TeslaBattery容器中导入TeslaCar组件 (6.2 Import TeslaCar component in TeslaBattery Container)

Next, we need to add this component to our container again. Import TeslaNotice component in TeslaBattery.js:

接下来,我们需要再次将此组件添加到我们的容器中。 在TeslaBattery.js导入TeslaNotice组件:

...import TeslaCar from '../components/TeslaCar/TeslaCar';
class TeslaBattery extends React.Component {  render() {    return (      <form className="tesla-battery">        <h1>Range Per Charge</h1>        <TeslaCar />        <TeslaNotice />      </form>    )  }}...

Here’s what you should be seeing:

这是您应该看到的:

7.道具和React开发人员工具 (7. Props and React Developer Tools)

Wow! It’s nice but something is missing. The wheels are not shown. Let’s look for the cause. According to the source code, TeslaCar should be passed to props and class name changed based on props.wheelsize.

哇! 很好,但是缺少某些东西。 车轮未显示。 让我们寻找原因。 根据源代码, TeslaCar应该传递给props并且基于props.wheelsize更改类名。

In other words, you need to receive some data (in this case, wheelsize) from the parent component and render it properly, and there must be a communication method that can receive the data.

换句话说,您需要从父组件接收一些数据(在这种情况下为wheelsize)并正确渲染它,并且必须有一种可以接收数据的通信方法。

React is composed of a component tree, which consists of a container for delivering data and state, and a component for passively receiving data and state from a container. The tool that delivers this state to the subcomponents is a single object, props.

React由一个组件树组成,该树由一个用于传递数据和状态的容器,以及一个用于从容器被动接收数据和状态的组件组成。 将此状态传递给子组件的工具是单个对象props

You can easily understand this by checking the component tree using React Developer Tools in Chrome.

您可以通过使用Chrome中的React Developer Tools检查组件树来轻松理解这一点。

props is a JavaScript single object, in this case an empty object. This is because we did not pass props in the parent component TeslaBattery.

props是JavaScript单个对象,在这种情况下为空对象。 这是因为我们没有在父组件TeslaBattery传递props

8.申请状态 (8. State of Application)

We need to think about what state is required to be managed in our app. If you look at the final app GIF image at the top of this article, the state values ​​are:

我们需要考虑在我们的应用程序中需要管理什么state 。 如果您查看本文顶部的最终应用GIF图像,则状态值为:

  • carstats (object array) : An array of battery numerical value objects ​​by car model according to the currently selected condition value (speed, temperature, climate, wheel)

    carstats(对象数组) :根据当前选择的条件值(速度,温度,气候,车轮)按汽车模型排列的电池数值对象数组

  • config (object): Currently selected conditions object (speed: 55, temperature: 20, climate: aricon on, wheel: 19)

    配置(对象) :当前选择的条件对象(速度:55,温度:20,气候:aricon开,滚轮:19)

That is the single source of truth for our app. Now we will add the constructor method to the TeslaBattery container and set the initial value so that we can manage this state value and pass it to the subcomponent. The TeslaCar component accepts the wheelsize input through props and renders the Tesla car image and spins the wheels.

这是我们应用程序的唯一事实来源。 现在,我们将构造函数方法添加到TeslaBattery容器并设置初始值,以便我们可以管理该状态值并将其传递给子组件。 TeslaCar组件通过props接受wheelsize输入,并渲染Tesla汽车图像并旋转车轮。

Both the parent component and the child component do not know whether a particular component is stateful or stateless and do not care whether it is defined as a function or a class. This is why the state is often called local or encapsulated. This state can not be accessed by components other than the component that owns and sets the state. So this state value can be passed to the sub-component as props. This is commonly referred to as a “top-down” or “unidirectional” data flow. Every state is always owned by a particular component, and any data or UI derived from that state only affects the “downward” component of the tree.

父组件和子组件都不知道特定组件是有状态的还是无状态的,并且不在乎将其定义为function还是class 。 这就是为什么状态通常被称为局部状态或封装状态的原因。 除拥有和设置状态的组件外,其他组件无法访问此状态。 因此,该状态值可以作为props传递给子组件。 这通常称为“自上而下”或“单向”数据流。 每个状态始终由特定组件拥有,并且从该状态派生的任何数据或UI仅会影响树的“向下”组件。

...class TeslaBattery extends React.Component {  constructor(props) {    super(props);
this.state = {      carstats: [],      config: {        speed: 55,        temperature: 20,        climate: true,        wheels: 19      }    }  }    render() {    // ES6 Object destructuring Syntax,    // takes out required values and create references to them    const { config } = this.state;    return (      <form className="tesla-battery">        <h1>Range Per Charge</h1>        <TeslaCar wheelsize={config.wheels}/>        <TeslaNotice />      </form>    )  }}...

In render(), the code in the form const {a, b} = c is ES6 Object Destructuring. It takes the required value out of the object and makes a reference to it.

render() ,形式为const {a, b} = cES6 Object Destructuring 。 它从对象中取出所需的值并对其进行引用。

Conceptually, the React component is like a JavaScript function and receives an arbitrary input called ‘props’ and returns a React element that describes what should be shown.

从概念上讲,React组件就像一个JavaScript函数,它接收称为“ props”的任意输入,并返回描述应显示内容的React元素。

In a word, this concept can be expressed by the following formula.

总之,可以通过以下公式来表达该概念。

fn(d) = V

fn(d)= V

A function that receives data as input and returns a view.

接收数据作为输入并返回视图的函数。

If you save files, you can see that the rendered Tesla car and wheel animation work well on the updated screen. You can also see that props is passed well in the component tree.

如果保存文件,则可以在更新的屏幕上看到渲染的特斯拉汽车和车轮动画效果良好。 您还可以看到props在组件树中传递得很好。

Some functions are called “pure” in the sense that they always return the same output value if they have the same input value without changing the input value. (Pure function) One important React strict rule here is that all React components should behave like pure functions with respect to props. props must be read-only.

在某些函数被称为“纯”的意义上,如果它们具有相同的输入值而不更改输入值,它们总是会返回相同的输出值。 ( Pure function )一个重要的React严格规则是,所有React组件的行为都应与props的纯函数类似。 props必须是只读的。

9. TeslaStats组件 (9. TeslaStats Component)

Now we are going to build the TeslaStats component. Create the src/components/TeslaStats directory, create a TeslaStats.js file in it, and enter the following code:

现在,我们将构建TeslaStats组件。 创建src/components/TeslaStats目录,在其中创建一个TeslaStats.js文件,然后输入以下代码:

import React from 'react';import './TeslaStats.css';
const TeslaStats = (props) => {  const listItems = props.carstats.map((stat) => (    <li key={stat.model}>      <div className={`tesla-stats-icon tesla-stats-icon--${stat.model.toLowerCase()}`}></div>      <p>{stat.miles}</p>    </li>  ));  return (    <div className="tesla-stats">    &lt;ul>      {listItems}      </ul>  </div>  )};
TeslaStats.propTypes = {  carstats: React.PropTypes.array}
export default TeslaStats;

TeslaStats is also a presentational component that receives state, and it takes a list of arrays containing model values ​​by props and renders them.

TeslaStats也是一个接收状态的presentational component ,它通过props包含模型值的数组列表并进行渲染。

First, let’s consider how to transform a list in JavaScript. The following code uses the map() function to take a numbers array and return a double value.

首先,让我们考虑如何在JavaScript中转换列表。 以下代码使用map()函数获取一个numbers数组并返回一个双精度值。

This code prints [2, 4, 6, 8, 10] to the console.

此代码将[2, 4, 6, 8, 10] 2、4、6、8、10]打印到控制台。

const numbers = [1, 2, 3, 4, 5];const doubled = numbers.map((number) => number * 2);console.log(doubled);

Converting an array to a list in React is almost identical. Here we use the JavaScript map function to iterate through the props.carstats array.

在React中将数组转换为列表几乎相同。 在这里,我们使用JavaScript map函数来遍历props.carstats数组。

For each iteration, it returns a <li> element containing the model and a <li>element surrounding the <p&gt; tag containing miles.

对于每次迭代,它返回一个< LI>元件containin g the模型and一个<LI>元件SURR oun丁的<宝洁t; ta t; ta包含英里。

Finally, it returns the listItems array in the <ul> element.

最后,它在< ul>元素中返回listItems数组。

9.1 TeslaStats组件样式 (9.1 TeslaStats Component Style)

Next, create a TeslaStats.css file in the src/components/TeslaStats directory and type the following style. Since the code is long and omitted here, let’s check the source code

接下来,在src/components/TeslaStats目录中创建TeslaStats.css文件,然后键入以下样式。 由于代码很长,这里省略了,让我们检查一下源代码

....tesla-stats {  margin: -70px 0 30px; }.tesla-stats ul {  text-align: center; }...

The task that this component performs is to iterate through the props.carstatsarray and bind a particular class to an element based on stat.model. You can then replace the background image to display the Tesla model.

该组件执行的任务是遍历props.carstats数组,并将特定类绑定到基于stat.model的元素。 然后,您可以替换背景图像以显示Tesla模型。

9.2在TeslaBattery容器中导入TeslaStats组件 (9.2 Import TeslaStats component in TeslaBattery Container)

Then add following import to use the TeslaStats component in TeslaBattery.js.

然后添加以下import使用TeslaStats成分TeslaBattery.js

...import TeslaStats from '../components/TeslaStats/TeslaStats';...render() {  const { config, carstats } = this.state;  return (    <form className="tesla-battery">      <h1>Range Per Charge</h1>      <TeslaCar wheelsize={config.wheels}/>      <TeslaStats carstats={carstats}/>      <TeslaNotice />    </form>  )}...

We need to pass the carstats array to props, so let’s set the value using BatteryService we’ve already implemented.

我们需要将carstats数组传递给props ,所以让我们使用已经实现的BatteryService设置值。

9.3 CalculateStats和setState (9.3 CalculateStats and setState)

Add import getModelData first.

首先添加导入getModelData

After the component is mounted via componentDidMount(), it calls the statsUpdate() function. When calculateStats() function that receives carModels and the current state value as the input is executed, the object with the matching model and miles values ​​is returned, and the return value is passed through the setState() and then state object is updated.

通过componentDidMount()挂载componentDidMount() ,它将调用statsUpdate()函数。 当执行接收carModels和当前状态值作为输入的calculateStats()函数时,将返回具有匹配modelmiles值的对象,并将返回值通过setState()传递,然后更新状态对象。

...import { getModelData } from '../services/BatteryService';...
calculateStats = (models, value) => {  const dataModels = getModelData();  return models.map(model => {    // ES6 Object destructuring Syntax,    // takes out required values and create references to them    const { speed, temperature, climate, wheels } = value;    const miles = dataModels[model][wheels][climate ? 'on' : 'off'].speed[speed][temperature];    return {      model,      miles    };  });}  statsUpdate() {  const carModels = ['60', '60D', '75', '75D', '90D', 'P100D'];  // Fetch model info from BatteryService and calculate then update state  this.setState({    carstats: this.calculateStats(carModels, this.state.config)  })  }  componentDidMount() {  this.statsUpdate(); }...

One caveat is that explicit binding in the TeslaBattery constructor function is required to access this in the class.

一个需要注意的是,明确结合在TeslaBattery构造函数才能访问this班上。

...this.calculateStats = this.calculateStats.bind(this);this.statsUpdate = this.statsUpdate.bind(this);...

9.4添加其他样式 (9.4 Add Additional Style)

Additional styling is required for a nice layout here.

这里的布局不错,还需要其他样式。

First open the src/index.css file and delete all existing code and add the following:

首先打开src/index.css文件并删除所有现有代码并添加以下内容:

@font-face {  font-family: 'RobotoNormal';  src: url('./assets/fonts/Roboto-Regular-webfont.eot');  src: url('./assets/fonts/Roboto-Regular-webfont.eot?#iefix') format('embedded-opentype'),       url('./assets/fonts/Roboto-Regular-webfont.woff') format('woff'),       url('./assets/fonts/Roboto-Regular-webfont.ttf') format('truetype'),       url('./assets/fonts/Roboto-Regular-webfont.svg#RobotoRegular') format('svg');  font-weight: normal;  font-style: normal;}
*, *:before, *:after {  box-sizing: border-box;  margin: 0;  padding: 0;  font: 300 14px/1.4 'Helvetica Neue', Helvetica, Arial, sans-serif;  -webkit-font-smoothing: antialiased;}
.cf:before,.cf:after {    content: '';    display: table;}.cf:after {    clear: both;}.cf {  *zoom: 1;}

Next, open the src/App.css file and delete all existing code and add the following:

接下来,打开src/App.css文件并删除所有现有代码并添加以下内容:

.wrapper {  margin: 100px 0 150px;}

The work result screen so far is as follows.

到目前为止的工作结果画面如下。

10.可重复使用的TeslaCounter组件 (10. Reusable TeslaCounter Component)

Tesla’s speed and external temperature controls should be reusable components, so I’ll make them a generic Counter component that allows for other metadata such as step, minimum, maximum, and title and units (mph / degrees).

特斯拉的速度和外部温度控制应该是可重用的组件,因此我将使它们成为通用的Counter组件,该组件允许其他元数据,例如步长,最小,最大以及标题和单位(英里/度)。

Also, unlike the components we have created so far, we need an action to change the state value in response to user input (button click, checkbox selection, etc.). Let’s look at how to handle events that occur in a subcomponent.

此外,与我们到目前为止创建的组件不同,我们需要一个操作来响应用户输入(按钮单击,复选框选择等)来更改状态值。 让我们看一下如何处理子组件中发生的事件。

Create the src/components/TeslaCounter directory as before, create a TeslaCounter.js file in it, and enter the following code:

像以前一样创建src/components/TeslaCounter目录,在其中创建一个TeslaCounter.js文件,然后输入以下代码:

import React from 'react';import './TeslaCounter.css';
const TeslaCounter = (props) => (  <div className="tesla-counter">    <p className="tesla-counter__title">{props.initValues.title}</p>    <div className="tesla-counter__container cf">      <div className="tesla-counter__item">        <p className="tesla-counter__number">          { props.currentValue }          <span>{ props.initValues.unit }</span>        </p>        <div className="tesla-counter__controls">          <button             onClick={(e) => props.increment(e, props.initValues.title)}             disabled={props.currentValue >= props.initValues.max}           >          </button>          <button             onClick={(e) => props.decrement(e, props.initValues.title)}             disabled={props.currentValue <= props.initValues.min}           >          </button>        </div>      </div>    </div>  </div>  );
TeslaCounter.propTypes = {  currentValue: React.PropTypes.number,  increment: React.PropTypes.func,  decrement: React.PropTypes.func,  initValues: React.PropTypes.object}
export default TeslaCounter;

Let’s think about what we want here. Each time you click and change the speed and temperature, you must update the state so that the value is reflected between the maximum and minimum values.

让我们考虑一下我们想要什么。 每次单击并更改速度和温度时,都必须更新状态,以使该值反映在最大值和最小值之间。

Since the component only needs to update its own state, TeslaBattery passes the callback (increment, decrement) to the TeslaCounter each time it needs to update its state. You can use the onClick event on a button to notify the event. The callback passed by TeslaBattery calls setState() and the app is updated.

由于该组件仅需要更新其自身的状态, TeslaBatteryTeslaBattery需要更新其状态时, TeslaBattery将回调( incrementdecrement )传递给TeslaCounter 。 您可以在按钮上使用onClick事件来通知该事件。 TeslaBattery传递的回调调用setState() ,并且应用程序已更新。

We will implement a callback that will be passed by TeslaBattery in a few moments.

我们将实现一个回调,该回调将在几分钟后由TeslaBattery通过。

10.1 TeslaCounter组件样式 (10.1 TeslaCounter Component Style)

Let’s implement the style first. Create a TeslaCounter.css file in the src/components/TeslaCounter directory and specify the following styles. Since the code is long and omitted here, let’s check the source code

让我们首先实现样式。 在src/components/TeslaCounter目录中创建一个TeslaCounter.css文件,并指定以下样式。 由于代码很长,这里省略了,让我们检查源代码

.tesla-counter {  float: left;  width: 230px; }.tesla-counter__title {  letter-spacing: 2px;  font-size: 16px; }...

10.2在TeslaBattery容器中导入TeslaCounter组件 (10.2 Import TeslaCounter Component in TeslaBattery Container)

Now, we will implement callback in TeslaBattery and pass it to the TeslaCounter component.

现在,我们将在TeslaBattery实现callback并将其传递给TeslaCounter组件。

First, add import to use the TeslaCounter component in TeslaBattery.js.

首先,添加import使用TeslaCounter成分TeslaBattery.js

We also implement the callback functions increment() and decrement(), and the internal function updateCounterState() and bind it in the constructor. Then pass the callback function to the TeslaCounter component with props.

我们还实现了回调函数increment()decrement() ,以及内部函数updateCounterState()并将其绑定到constructor 。 然后使用propscallback函数传递给TeslaCounter组件。

...constructor(props) {    super(props);
this.calculateStats = this.calculateStats.bind(this);    this.statsUpdate = this.statsUpdate.bind(this);    this.increment = this.increment.bind(this);    this.decrement = this.decrement.bind(this);    this.updateCounterState = this.updateCounterState.bind(this);
this.state = {      carstats: [],      config: {        speed: 55,        temperature: 20,        climate: true,        wheels: 19      }    }  }...updateCounterState(title, newValue) {    const config = { ...this.state.config };    // update config state with new value    title === 'Speed' ? config['speed'] = newValue : config['temperature'] = newValue;    // update our state    this.setState({ config });  }
increment(e, title) {    e.preventDefault();    let currentValue, maxValue, step;    const { speed, temperature } = this.props.counterDefaultVal;    if (title === 'Speed') {      currentValue = this.state.config.speed;      maxValue = speed.max;      step = speed.step;    } else {      currentValue = this.state.config.temperature;      maxValue = temperature.max;      step = temperature.step;    }
if (currentValue < maxValue) {      const newValue = currentValue + step;      this.updateCounterState(title, newValue);    }  }
decrement(e, title) {    e.preventDefault();    let currentValue, minValue, step;    const { speed, temperature } = this.props.counterDefaultVal;    if (title === 'Speed') {      currentValue = this.state.config.speed;      minValue = speed.min;      step = speed.step;    } else {      currentValue = this.state.config.temperature;      minValue = temperature.min;      step = temperature.step;    }
if (currentValue > minValue) {      const newValue = currentValue - step;      this.updateCounterState(title, newValue);    }  }  ...render() {      return (      <form className="tesla-battery">        <h1>Range Per Charge</h1>        <TeslaCar wheelsize={config.wheels} />        <TeslaStats carstats={carstats} />        <div className="tesla-controls cf">          <TeslaCounter            currentValue={this.state.config.speed}            initValues={this.props.counterDefaultVal.speed}            increment={this.increment}            decrement={this.decrement}          />          <div className="tesla-climate-container cf">            <TeslaCounter              currentValue={this.state.config.temperature}              initValues={this.props.counterDefaultVal.temperature}              increment={this.increment}              decrement={this.decrement}            />          </div>        </div>        <TeslaNotice />    </form>  )}

10.3 Tesla电池容器样式 (10.3 TeslaBattery Container Style)

An additional style is required for TeslaBattery as soon as the TeslaCounter component is added. Open the TeslaBattery.css file and add the following:

添加TeslaCounter组件后, TeslaBattery需要其他样式。 打开TeslaBattery.css文件并添加以下内容:

.tesla-climate-container {  float: left;  width: 420px;  padding: 0 40px;  margin: 0 40px 0 0;  border-left: 1px solid #ccc;  border-right: 1px solid #ccc;}.tesla-controls {  display: block;  width: 100%;}

10.4默认值道具 (10.4 Default Value Props)

Here, initValues passed to TeslaCounter is a constant value and is passed from App which is a parent component of TeslaBattery.

在这里,传递给TeslaCounter initValues是一个常量值,并从作为TeslaBattery父组件的App传递。

Open App.js and pass the counterDefaultVal object to the TeslaBattery component as follows:

开放App.js和传递counterDefaultVal对象到TeslaBattery组分如下:

import React, { Component } from 'react';import './App.css';import Header from './components/Header/Header';import TeslaBattery from './containers/TeslaBattery';
const counterDefaultVal = {  speed: {    title: "Speed",    unit: "mph",    step: 5,    min: 45,    max: 70  },  temperature: {    title: "Outside Temperature",    unit: "°",    step: 10,    min: -10,    max: 40  }};
class App extends Component {  render() {    return (      <div className="App">        <Header />        <TeslaBattery counterDefaultVal={counterDefaultVal}/>      &lt;/div>    );  }}
export default App;

Now, when you click Speed ​​and Temperature, you can see that the changed values ​​are updated and re-rendered in the state object through the React Developer Tool.

现在,当您单击``速度和温度''时,您可以看到通过React Developer Tool在状态对象中更新并重新渲染了更改的值。

10.5虚拟DOM (10.5 Virtual DOM)

What a single-page application can give us is a seamless user experience and smooth interaction.

单页应用程序可以为我们提供无缝的用户体验和流畅的交互。

In our app, car model values ​​are updated without having to reload the entire page every time the user changes speed or temperature. Even if you need to connect to the server to get the data. To provide this user experience, you need to know which part of the DOM you need to update when changes or interactions occur.

在我们的应用程序中,汽车模型值得以更新,而无需每次用户更改速度或温度时都重新加载整个页面。 即使您需要连接到服务器来获取数据。 为了提供这种用户体验,您需要知道在发生更改或交互时需要更新DOM哪一部分。

Each JavaScript framework uses a different strategy: Ember uses data-binding, Angular1 uses dirty checking, and React uses Virtual DOM.

每个JavaScript框架使用不同的策略: Ember使用data-bindingAngular1使用脏检查 , React使用虚拟DOM 。

In React, the first time the component’s rendering method is called, it prints a virtual DOM model, rather than the actual DOM element itself. The virtual DOM is a JavaScript data structure that represents the appearance of DOM. React then takes this model and creates the actual DOM element.

在React中,第一次调用组件的呈现方法时,它将打印virtual DOM模型,而不是实际的DOM元素本身。 virtual DOM是表示DOM外观JavaScript数据结构。 然后,React采用此模型并创建实际的DOM元素。

Then, whenever the component’s state changes (eg, setState is called), the rendering method of the component is called and a new virtual DOM is created, and this new virtual DOM is compared with the previous virtual DOM. The result of this comparison is to show the actual DOM changes and the DOM will be ‘patched’ with the changes and the screen will change.

然后,只要组件的状态发生变化(例如,调用setState ),就会调用组件的呈现方法并创建一个新的virtual DOM ,并将此新的virtual DOM与先前的virtual DOM 。 比较的结果是显示实际的DOM更改,并且DOM将随更改进行“修补”,并且屏幕也会更改。

The car model information does not change yet as the speed and temperature change. This will eventually be implemented later.

汽车型号信息不会随速度和温度的变化而变化。 最终将在以后实现。

11.空调和加热控制 (11. Aircon and Heating Controls)

We monitor the temperature and change the heating to aircon when it is more than 20 degrees, and heating when it is below 20 degrees.

我们监测温度和改变heatingaircon当其大于20度,并heating时,它是20度以下。

First create a directory src/components/TeslaClimate, create a TeslaClimate.jsfile in it, and enter the following code:

首先创建目录src/components/TeslaClimate ,在其中创建一个TeslaClimate.js文件,然后输入以下代码:

import React from 'react';import './TeslaClimate.css';
const TeslaClimate = (props) => (  <div className="tesla-climate">    <label      className={`tesla-climate__item ${props.value ? 'tesla-climate__item--active' : '' }  ${!props.limit ? 'tesla-heat':''}`}    >      <p>{props.limit ? 'ac' : 'heat'} {props.value ? 'on' : 'off'}</p>      <i className="tesla-climate__icon"></i>      <input        type="checkbox"        name="climate"        checked={props.value}        onChange={() => {props.handleChangeClimate()}}      />    </label>  </div>);
TeslaClimate.propTypes = {  value: React.PropTypes.bool,  limit: React.PropTypes.bool,  handleChangeClimate: React.PropTypes.func}
export default TeslaClimate;

This component changes the style class according to the props.value passed in, and changes the text according to props.limit.

此组件根据传入的props.value更改样式类,并根据props.limit更改文本。

TeslaBattery passes callback(handleChangeClimate in this case) to TeslaClimate, which is executed whenever the state needs to be updated. onChangeevent can be used to notify the event. The callback passed by TeslaBattery is called with setState() to update its state and re-render.

TeslaBattery通过回调( handleChangeClimate在这种情况下),以TeslaClimate ,每当要更新的状态需要被执行。 onChange事件可用于通知该事件。 通过setState()调用TeslaBattery传递的callback以更新其状态并重新呈现。

11.1 TeslaClimate组件样式 (11.1 TeslaClimate Component Style)

Create a TeslaClimate.css file in the src/components/TeslaClimate directory and specify the following styles. Since the code is long and omitted here, let’s check the source code.

src/components/TeslaClimate目录中创建TeslaClimate.css文件,并指定以下样式。 由于代码很长,在这里省略了,让我们检查源代码 。

.tesla-climate {     float: left;   }  .tesla-climate__item {    cursor: pointer;    display: block;    width: 100px;    height: 100px;    border: 6px solid #f7f7f7;    border-radius: 50%;    box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.3);    color: #666;    background: #fff;   }  ...

11.2在Tesla电池容器中导入TeslaClimate组件 (11.2 Import TeslaClimate Component in TeslaBattery Container)

Now we will implement callback in TeslaBattery and pass it to the TeslaClimatecomponent.

现在,我们将在TeslaBattery实现callback并将其传递给TeslaClimate组件。

First, add import to use the TeslaClimate component in TeslaBattery.js. We implement callback function handleChangeClimate() and bind it in constructor(). Then pass the callback function to the TeslaClimate component as props.

首先,添加import使用TeslaClimate成分TeslaBattery.js 。 我们实现回调函数handleChangeClimate()并将其绑定到constructor() 。 然后将回调函数作为props传递给TeslaClimate组件。

...import TeslaClimate from '../components/TeslaClimate/TeslaClimate';...constructor(props) {  super(props);  ...  this.handleChangeClimate = this.handleChangeClimate.bind(this);  ...}// handle aircon & heating click event handlerhandleChangeClimate() {  const config = {...this.state.config};  config['climate'] = !this.state.config.climate;  this.setState({ config });}
...<TeslaClimate  value={this.state.config.climate}  limit={this.state.config.temperature > 10}  handleChangeClimate={this.handleChangeClimate}/&gt;  ...

Now the state value changes according to the temperature change, and when the changed value is passed to the TeslaClimate component, the style class and text are changed according to the value.

现在状态值根据温度变化而变化,并且将更改后的值传递给TeslaClimate组件时,样式类和文本也会根据该值而变化。

12. TeslaWheels组件 (12. TeslaWheels Component)

Finally, let’s make the final component TeslaWheels. As always, create a directory src/components/TeslaWheels, create a TeslaWheels file in it, and enter the following code.

最后,让我们制作最终组件TeslaWheels 。 与往常一样,创建目录src/components/TeslaWheels ,在其中创建一个TeslaWheels文件,然后输入以下代码。

import React from 'react';import './TeslaWheels.css';
const LabelLists = (props) => {  const value = props.wheels.value;  const changeHandler = props.wheels.handleChangeWheels;  const sizes = [19, 21];  const LabelItems = sizes.map(size => (    <label key={size} className={`tesla-wheels__item tesla-wheels__item--${size} ${value === size ? 'tesla-wheels__item--active' : '' }`}>      <input        type="radio"        name="wheelsize"        value={size}        checked={value === size}         onChange={() => {changeHandler(size)}} />      <p>        {size}"      </p>    </label>     )  );  return (    <div>      {LabelItems}    </div>  );}const TeslaWheels = (props) => (  <div className="tesla-wheels__component">    <p className="tesla-wheels__title">Wheels</p>    <div className="tesla-wheels__container cf">      <LabelLists wheels={props}/>    </div>  </div>);TeslaWheels.propTypes = {  value: React.PropTypes.number,  handleChangeWheels: React.PropTypes.func}export default TeslaWheels;

Our implementation here is similar to the conversion of the props array object to a list in the TeslaStats component. Repeat the props.sizes array using the javascript map() function.

我们此处的实现类似于将props数组对象转换为TeslaStats组件中的列表。 使用javascript map()函数重复props.sizes数组。

For each iteration, it returns the <label> elements containing size. Finally, the LabelItems list is built into the TeslaWheels component and rendered.

对于每次迭代,它返回<lab EL>元素CONTA inin克大小。 最后, the Labe o the Tesla Wheels组件内部构建并渲染, the Labe lItems列表。

In the <label> element, the effect of wheel animation is shown by changing the class according to the transmitted wheel size.

<lab el>元素中,通过根据传输的车轮大小更改类来显示车轮动画的效果。

12.1 TeslaWheels组件样式 (12.1 TeslaWheels Component Style)

Create a TeslaWheels.css file in the src/components/TeslaWheels directory and specify the following styles. Since the code is long and omitted here, let’s check the source code.

src/components/TeslaWheels目录中创建TeslaWheels.css文件,并指定以下样式。 由于代码很长,在这里省略了,让我们检查源代码 。

.tesla-wheels__component {  float: left;  width: 355px;}.tesla-wheels__title {  letter-spacing: 2px;  font-size: 16px;}...

12.2在Tesla电池容器中导入TeslaWheels组件 (12.2 Import TeslaWheels Component in TeslaBattery Container)

Finally, implement callback in TeslaBattery and pass it to the TeslaWheels component.

最后,在TeslaBattery实现callback并将其传递给TeslaWheels组件。

Add import to use the TeslaWheels component in TeslaBattery.js. We then implement callback function handleChangeWheels() and bind it in constructor. Then pass the callback function to the TeslaWheels component as props.

添加import使用TeslaWheels在组件TeslaBattery.js 。 然后,我们实现回调函数handleChangeWheels()并将其绑定到constructor 。 然后将回调函数作为props传递给TeslaWheels组件。

...import TeslaWheels from '../components/TeslaWheels';...constructor(props) {    super(props);    this.calculateStats = this.calculateStats.bind(this);    this.increment = this.increment.bind(this);    this.decrement = this.decrement.bind(this);    this.handleChangeClimate = this.handleChangeClimate.bind(this);    this.handleChangeWheels = this.handleChangeWheels.bind(this);    this.statsUpdate = this.statsUpdate.bind(this);...handleChangeWheels(size) {  const config = {...this.state.config};  config['wheels'] = size;  this.setState({ config });}...<TeslaWheels  value={this.state.config.wheels}  handleChangeWheels={this.handleChangeWheels}/&gt;...

The result of the completion of the wheels animation is as follows.

车轮动画的完成结果如下。

13.状态更新 (13. State Update)

Are we finally done? Even if the user changes several condition values, the difference value of the vehicle model does not change properly.

我们终于完成了吗? 即使用户改变多个条件值,车辆模型的差值也不会适当地改变。

So far, we’ve only updated a part of our app’s status each time an event occurs.

到目前为止,每次事件发生时,我们仅更新了部分应用程序状态。

this.setState({ config });

Now let’s change the carstats state whenever the config state value changes.

现在,只要配置状态值更改,就可以更改carstats状态。

statsUpdate() {  const carModels = ['60', '60D', '75', '75D', '90D', 'P100D'];  // Fetch model info from BatteryService and calculate then update state  this.setState({  carstats: this.calculateStats(carModels, this.state.config)  })}

Now we create a function that take the carModels and the current state value as inputs and reflects the changed carStats in the app state and pass it to this.setState as a callback.

现在,我们创建一个函数,将carModels和当前状态值作为输入,并在应用程序状态中反映更改后的carStats ,并将其作为回调传递给this.setState

By doing this, it is possible to update the config object first in setState(), which operates asynchronous method, and to render the changed stats on the screen based on this.

通过这样做,可以首先在操作异步方法的setState()更新config对象,并基于此在屏幕上呈现更改的stats

this.setState({ config }, () => {this.statsUpdate()});

This completes all the puzzles. The complete code for TeslaBattery is:

这就完成了所有的难题。 TeslaBattery的完整代码是:

import React from 'react';import './TeslaBattery.css';import TeslaNotice from '../components/TeslaNotice/TeslaNotice';import TeslaCar from '../components/TeslaCar/TeslaCar';import TeslaStats from '../components/TeslaStats/TeslaStats';import TeslaCounter from '../components/TeslaCounter/TeslaCounter';import TeslaClimate from '../components/TeslaClimate/TeslaClimate';import TeslaWheels from '../components/TeslaWheels/TeslaWheels';import { getModelData } from '../services/BatteryService';
class TeslaBattery extends React.Component {  constructor(props) {    super(props);
this.calculateStats = this.calculateStats.bind(this);    this.statsUpdate = this.statsUpdate.bind(this);    this.increment = this.increment.bind(this);    this.decrement = this.decrement.bind(this);    this.updateCounterState = this.updateCounterState.bind(this);    this.handleChangeClimate = this.handleChangeClimate.bind(this);    this.handleChangeWheels = this.handleChangeWheels.bind(this);
this.state = {      carstats: [],      config: {        speed: 55,        temperature: 20,        climate: true,        wheels: 19      }    }  }
calculateStats = (models, value) => {    const dataModels = getModelData();    return models.map(model => {      const { speed, temperature, climate, wheels } = value;      const miles = dataModels[model][wheels][climate ? 'on' : 'off'].speed[speed][temperature];      return {        model,        miles      };    });  }
statsUpdate() {    const carModels = ['60', '60D', '75', '75D', '90D', 'P100D'];    // Fetch model info from BatteryService and calculate then update state    this.setState({      carstats: this.calculateStats(carModels, this.state.config)    })  }
componentDidMount() {    this.statsUpdate();  }
updateCounterState(title, newValue) {    const config = { ...this.state.config };    // update config state with new value    title === 'Speed' ? config['speed'] = newValue : config['temperature'] = newValue;    // update our state    this.setState({ config }, () => {this.statsUpdate()});  }
increment(e, title) {    e.preventDefault();    let currentValue, maxValue, step;    const { speed, temperature } = this.props.counterDefaultVal;    if (title === 'Speed') {      currentValue = this.state.config.speed;      maxValue = speed.max;      step = speed.step;    } else {      currentValue = this.state.config.temperature;      maxValue = temperature.max;      step = temperature.step;    }
if (currentValue < maxValue) {      const newValue = currentValue + step;      this.updateCounterState(title, newValue);    }  }
decrement(e, title) {    e.preventDefault();    let currentValue, minValue, step;    const { speed, temperature } = this.props.counterDefaultVal;    if (title === 'Speed') {      currentValue = this.state.config.speed;      minValue = speed.min;      step = speed.step;    } else {      currentValue = this.state.config.temperature;      minValue = temperature.min;      step = temperature.step;    }
if (currentValue > minValue) {      const newValue = currentValue - step;      this.updateCounterState(title, newValue);    }  }
// handle aircon & heating click event handler  handleChangeClimate() {    const config = {...this.state.config};    config['climate'] = !this.state.config.climate;    this.setState({ config }, () => {this.statsUpdate()});  }
// handle Wheels click event handler  handleChangeWheels(size) {    const config = {...this.state.config};    config['wheels'] = size;    this.setState({ config }, () => {this.statsUpdate()});  }
render() {        const { config, carstats } = this.state;    return (      <form className="tesla-battery">        <h1>Range Per Charge</h1>        <TeslaCar wheelsize={config.wheels} />        <TeslaStats carstats={carstats} />        <div className="tesla-controls cf">          <TeslaCounter            currentValue={this.state.config.speed}            initValues={this.props.counterDefaultVal.speed}            increment={this.increment}            decrement={this.decrement}          />          <div className="tesla-climate-container cf">            <TeslaCounter              currentValue={this.state.config.temperature}              initValues={this.props.counterDefaultVal.temperature}              increment={this.increment}              decrement={this.decrement}            />            <TeslaClimate              value={this.state.config.climate}              limit={this.state.config.temperature > 10}              handleChangeClimate={this.handleChangeClimate}            />          </div>          <TeslaWheels            value={this.state.config.wheels}            handleChangeWheels={this.handleChangeWheels}          />        </div>        <TeslaNotice />      </form>    )  }}
export default TeslaBattery;

Check out final project code

查看最终项目代码

14.建造 (14. Build)

It’s time to build our app.

现在该构建我们的应用程序了。

npm run build

If the build succeeds, the build folder will be created in our project directory and the following message will be displayed.

如果构建成功,将在我们的项目目录中创建构建文件夹,并显示以下消息。

Now our build is ready to be deployed.

现在我们的构建就可以部署了。

15.部署 (15. Deploy)

With tools like Surge, we can really easily deploy our built app.

使用Surge之类的工具,我们可以真正轻松地部署构建的应用程序。

Surge is simple, single-command web publishing. It publishes HTML, CSS, and JS for free, without leaving the command line.

Surge是简单的单命令Web发布。 它免费发布HTML,CSS和JS,而无需离开命令行。

First, install the tool with npm and run the surge command in the build directory.

首先,安装该工具npm和运行surge的命令build目录。

$ npm install -global surge$ cd build$ surge

If this is your first time running, you will need to enter your email and password to register a new account.

如果这是您第一次运行,则需要输入电子邮件和密码来注册新帐户。

The deployment is finished in an instant.

部署立即完成。

Let’s connect to our deployed project.

让我们连接到我们已部署的项目。

react-tesla-charge-calculator.surge.sh

react-tesla-charge-calculator.surge.sh

结论 (Conclusion)

In this post, we learned some points of creating React components and composing them to create a front-end app through rebuilding Tesla's Battery Range Calculator. If you’ve followed along until now, then congratulations on getting a React app up and running.

在这篇文章中,我们了解了创建React组件并通过重建Tesla's Battery Range Calculator来构成它们以创建前端应用程序的一些要点。 如果您到目前为止一直都在遵循,那么恭喜您启动并运行了React应用。

In the next installment, we’ll explore how to improve our state management with the Redux library. In the meantime, if you have any comments, suggestions, or corrections, please feel free to post them in the comments section.

在下一部分中,我们将探索如何使用Redux库改善状态管理。 同时,如果您有任何评论,建议或更正,请随时在评论部分中发表。

Thanks for your feedback in advance.

感谢您的提前反馈。

翻译自: https://www.freecodecamp.org/news/building-teslas-battery-range-calculator-with-react-part-1-2cb7abd8c1ee/

react中使用构建缓存

react中使用构建缓存_使用React构建Tesla的电池范围计算器(第1部分)相关推荐

  1. react中使用构建缓存_使用React和Netlify从头开始构建电子商务网站

    react中使用构建缓存 In this step-by-step, 6-hour tutorial from Coding Addict, you will learn to build an e- ...

  2. 使用React构建Tesla的电池范围计算器(第2部分:Redux版本)

    by Matthew Choi 由Matthew Choi 使用React构建Tesla的电池范围计算器(第2部分:Redux版本) (Building Tesla's Battery Range C ...

  3. react 中 Warning A future version of React will block javascript 异常解决

    react 中 Warning A future version of React will block javascript 异常解决 问题描述 <a href="javascrip ...

  4. 【前端部署第四篇】使用 Docker 构建缓存及多阶段构建优化单页应用

    大家好,我是山月,这是我最近新开的专栏:前端部署系列.包括 Docker.CICD 等内容,大纲图示如下: 示例代码开源,置于 Github 中,演示如何对真实项目进行部署上线. simple-dep ...

  5. react中使用构建缓存_通过在React中构建Tic Tac Toe来学习ReasonML

    react中使用构建缓存 3. 7. 2018: UPDATED to ReasonReact v0.4.2 3. 7. 2018:更新为ReasonReact v0.4.2 You may have ...

  6. react中使用构建缓存_如何在React中构建热图

    react中使用构建缓存 Heat maps are a great way of visualizing correlations among two data sets.  With colors ...

  7. react中使用构建缓存_通过构建海滩度假胜地网站,了解如何使用React,Contentful和Netlify...

    react中使用构建缓存 In this full course from John Smilga you will learn React by building a beach resort we ...

  8. react中使用构建缓存_完整的React课程:如何使用React构建聊天室应用

    react中使用构建缓存 In this video course, you'll learn React by building a chat room app. 在本视频课程中,您将通过构建聊天室 ...

  9. react中使用构建缓存_如何使用React构建Chatbot

    react中使用构建缓存 My philosophy is simple. To become good at something, you need to do it a lot. 我的哲学很简单. ...

最新文章

  1. ceph osd 由于“No space left on device” 异常down,通过扩容文件系统或者显式运行osd进程解决
  2. oracle 序列号同步,关于序列同步的问题
  3. 12月31日写成13月1日引发重大 Bug,程序员新年就要被“祭天”?
  4. html中如何消除左边界,元素的局中对齐问题,CSS盒属性使用技巧,前端开发必备...
  5. 安装 | 手把手教你Android studio 3.5.2安装(安装教程)
  6. 404 – File or directory not found.
  7. Java --- 常用API
  8. 这些新技术你们都知道吗?看这一篇就够了!
  9. 罗永浩:因为要烧投资人的钱 所以没有勇气再做手机了
  10. LoadRunner 11安装Micosoft Visual C++ 2005 SP1时提示命令行选项语法错误
  11. JavaScript生成随机颜色的代码
  12. Proteus 8.4软件安装教程
  13. 华硕笔记本怎么关闭触控板,禁用按钮是灰色的
  14. 支持udp转发的云服务器,云服务器转发udp原理
  15. Prometheus 结合cAdvisor、AlertManager、node-exporter 监控容器并实现邮箱告警
  16. C# object 转 int
  17. 【CSS】制作ICO图标
  18. Boost库系列:asio总结
  19. IPHONE屏幕大小,分辨率解析
  20. 由筷子被嘲讽来谈AM中的【价值观】

热门文章

  1. win2016开启smb服务器_Windows7系统怎么启用smb服务
  2. C&C++语言之可变参数传递
  3. IOT物联网系统架构
  4. window.onresize和window.addEventListener
  5. java.lang.IllegalStateException: No host
  6. Android sdk 生成api doc文档
  7. 2021研发大数据报告发布,腾讯研发人员增长四成
  8. ERP进销存软件系统 电脑端 手机端 小程序通用 (教程)
  9. 程序员在外打工怎么样才算活得精彩?你知道吗?
  10. 双11狂欢节模板 让大屏“闪电”起来