React 项目实践——搭建一个温度控制 App
我们将搭建一个温度控制 App,帮助初学者学习 React state hook、handle 事件等等。
尝试自己搭建
如果你想先自己试着写这个项目,可以对照下列项目需求(你也可以参考下方的初始代码):
当用户点击“+”按钮的时候,温度上升 温度不能高于 30℃ 当用户点击“-”按钮的时候,温度降低 温度不能低于 0℃ 当温度高于 15℃ 的时候,背景色变成红色(我创建了一个样式“hot”) 当温度高于 15℃ 的时候,背景色变成蓝色(我创建了一个样式“cold”)
初始代码
注:本文默认你已经安装好 React 开发环境。
首先在终端运行 create-react-app:
npx create-react-app temperature-control
同时在 VS Code(或者别的编辑器)打开项目。删除 index.js 里的内容,然后将以下代码粘贴进这个文件:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
React.StrictMode>,
document.getElementById('root')
);
同样,删除 index.css 的内容,粘贴以下内容:
body {
font-family: sans-serif;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
min-height: 100vh;
}
.app-container {
height: 400px;
width: 300px;
background: #2b5870;
border-radius: 20px;
box-shadow: 10px 10px 38px 0px rgba(0, 0, 0, 0.75);
}
.temperature-display-container {
display: flex;
justify-content: center;
align-items: center;
height: 70%;
}
.temperature-display {
display: flex;
border-radius: 50%;
color: #ffffff;
height: 220px;
width: 220px;
text-align: center;
justify-content: center;
align-items: center;
font-size: 48px;
border: 3px #ffffff solid;
transition: background 0.5s;
}
button {
border-radius: 100px;
height: 80px;
width: 80px;
font-size: 32px;
color: #ffffff;
background: rgb(105, 104, 104);
border: 2px #ffffff solid;
}
button:hover {
background: rgb(184, 184, 184);
cursor: pointer;
}
button:focus {
outline: 0;
}
.button-container {
display: flex;
justify-content: space-evenly;
align-items: center;
}
.neutral {
background: rgb(184, 184, 184);
}
.cold {
background: #035aa6;
}
.hot {
background: #ff5200;
}
最后,删除 App.js 的内容,粘贴以下代码:
import React from 'react';
const App = () => {
return (
<div className='app-container'>
<div className='temperature-display-container'>
<div className='temperature-display'>10°Cdiv>
div>
<div className='button-container'>
<button>+button>
<button>-button>
div>
div>
);
};
export default App;
现在我们可以在 VS Code 打开终端,运行:
npm start
如果一切无误,将显示:
好棒!接下来我们可以基于这个模版搭建了,不用担心 CSS 部分。
动态显示温度值——使用 State
首先我们让温度值动态显示。将温度值存储在 state 内,便于我们稍后读取数据,并用于逻辑呈现。
建议把引起 UI 改变的东西都放在 state 里。
在 App.js 文件开头导入 useState hook:
import React, { useState } from 'react';
在 App function 函数内添加:
const [temperatureValue, setTemperatureValue] = useState(10);
我们通过 useState 进行组件状态管理。useState hook 包含两个参数:
一个表示状态初始值的变量 一个更新状态值的函数
在这个例子中,我们调用了状态变量 temperatureValue 和函数 setTemperatureValue,将 10 这个值传递给 useState hook,作为 temperatureValue 的初始值。
现在我们把这个状态值用到代码里。记住了,我们从 useState 获取的值的用法和其他 JavaScript 变量和函数的用法一样。
将 JSX 里的固定的温度值改为状态变量。这是原来的值:
<div className='temperature-display'>10°Cdiv>
改成这样:
<div className='temperature-display'>{temperatureValue}°Cdiv>
注意我们使用 {} 来渲染 temperatureValue 变量。现在,如果温度值改变,组件将重新渲染,显示新的温度值。
App.js 文件目前是这样的:
import React, { useState } from 'react';
const App = () => {
const [temperatureValue, setTemperatureValue] = useState(10);
return (
<div className='app-container'>
<div className='temperature-display-container'>
<div className='temperature-display'>{temperatureValue}°Cdiv>
div>
<div className='button-container'>
<button>+button>
<button>-button>
div>
div>
);
};
export default App;
现在,如果你运行 app,浏览器中的一切好像跟之前一样。
但是,如果你将传递给 useState hook 的初始值从 10 改为其他(比如 15),你会看到 app 更新了,也就是说状态钩子起作用了!
按键时更改状态
接下来,我们要在按按钮时升高或降低温度。
useState hook 有一个 setTemperatureValue 函数,可以修改温度值,所以我们可以在按钮的 onClick 事件中用到它。
首先把“+”按钮的代码修改成:
<button onClick={() => setTemperatureValue(temperatureValue + 1)}>+button>
注意它是怎么调用 setTemperatureValue 函数的。获得当前温度值,加上 1,然后将其作为参数传递。
因为温度初始值是 10,加上 1 的话状态值就变成 11。再按一次按钮,状态值变成 12......
将“-”按钮的代码修改成:
<button onClick={() => setTemperatureValue(temperatureValue - 1)}>-button>
和对“+”按钮的操作类似,不过这次是降低温度值。
现在我们的代码是这样的:
import React, { useState } from 'react';
const App = () => {
const [temperatureValue, setTemperatureValue] = useState(10);
return (
<div className='app-container'>
<div className='temperature-display-container'>
<div className='temperature-display'>{temperatureValue}°Cdiv>
div>
<div className='button-container'>
<button onClick={() => setTemperatureValue(temperatureValue + 1)}>+button>
<button onClick={() => setTemperatureValue(temperatureValue - 1)}>-button>
div>
div>
);
};
export default App;
试着在浏览器运行代码,点击按钮,温度值会升高或降低。
基于状态修改颜色
接下来我们做点有意思的东西——根据温度的高低显示不同的背景色。
如果温度是 15℃ 或以上,背景色是红色;反之,背景色是蓝色。
在 CSS 里,我写了这两个类:
.cold
将背景色设置为蓝色.hot
将背景色设置为红色
将其中一个类添加至 temperature display div,会改变背景色,比如:
<div className='temperature-display cold'>{temperatureValue}°Cdiv>
背景色是蓝色
<div className='temperature-display hot'>{temperatureValue}°Cdiv>
背景色是红色
那么,怎么基于状态动态地应用这两个类呢?
创建另一个状态钩子,存放 temperatureColor:
const [temperatureColor, setTemperatureColor] = useState('cold');
注意我们给 temperatureColor 状态对象设置初始值为 “cold”(因为初始温度值为 10,我们希望背景色是蓝色)。
然后我们使用模板常量动态地添加需要的类:
<div className={`temperature-display ${temperatureColor}`}>{temperatureValue}°Cdiv>
这样一来,创建一个字符串,动态应用 temperatureColor 变量。当 temperatureColor 变成 “hot” 的时候,组件会重新渲染,给 className 字符串添加 “hot” 类。
我们的代码目前是这样的:
import React, { useState } from 'react';
const App = () => {
const [temperatureValue, setTemperatureValue] = useState(10);
const [temperatureColor, setTemperatureColor] = useState('cold');
return (
<div className='app-container'>
<div className='temperature-display-container'>
<div className={`temperature-display ${temperatureColor}`}>{temperatureValue}°Cdiv>
div>
<div className='button-container'>
<button onClick={() => setTemperatureValue(temperatureValue + 1)}>+button>
<button onClick={() => setTemperatureValue(temperatureValue - 1)}>-button>
div>
div>
);
};
export default App;
将初始 temperatureColor 状态变量改为 “hot” 或 “cold”,显示板的背景色随之改变。
我们已经有一个 onClick 事件可更改 temperatureValue 的值,现在我们给这个事件增加新的逻辑。
目前 onClick 事件有一个内联函数。对于单行函数来说用内联函数比较好。但是如果是有不同逻辑的多行函数,最好是将函数放到 JSX 外面,让代码更清晰。
将下列代码粘贴到状态下面:
const increaseTemperature = () => {
setTemperatureValue(temperatureValue + 1);
};
const decreaseTemperature = () => {
setTemperatureValue(temperatureValue - 1);
};
这里我们定义了两个函数,用于升高或降低温度。
接下来,修改按钮的 onClick 属性,调用这些函数:
<button onClick={increaseTemperature}>+button>
<button onClick={decreaseTemperature}>-button>
我们的代码目前是这样:
import React, { useState } from 'react';
const App = () => {
const [temperatureValue, setTemperatureValue] = useState(10);
const [temperatureColor, setTemperatureColor] = useState('cold');
const increaseTemperature = () => {
setTemperatureValue(temperatureValue + 1);
};
const decreaseTemperature = () => {
setTemperatureValue(temperatureValue - 1);
};
return (
<div className='app-container'>
<div className='temperature-display-container'>
<div className={`temperature-display ${temperatureColor}`}>{temperatureValue}°Cdiv>
div>
<div className='button-container'>
<button onClick={increaseTemperature}>+button>
<button onClick={decreaseTemperature}>-button>
div>
div>
);
};
export default App;
注意其实没啥改变,我们只是重新构造了代码,为接下来的工作做准备。
现在就更容易为点击按钮事件添加逻辑了。
给 increaseTemperature 函数添加逻辑:
const increaseTemperature = () => {
const newTemperature = temperatureValue + 1;
setTemperatureValue(newTemperature);
if (newTemperature >= 15) {
setTemperatureColor('hot');
}
};
当我们点击按钮若干次,temperatureValue 等于或大于 15℃ 时,temperatureColor 变量会更改,组件重新渲染,给显示板添加 “hot” 类。
降低温度时的逻辑是类似的:
const decreaseTemperature = () => {
const newTemperature = temperatureValue - 1;
setTemperatureValue(newTemperature);
if (newTemperature < 15) {
setTemperatureColor('cold');
}
};
app 最终的代码如下:
import React, { useState } from 'react';
const App = () => {
const [temperatureValue, setTemperatureValue] = useState(10);
const [temperatureColor, setTemperatureColor] = useState('cold');
const increaseTemperature = () => {
const newTemperature = temperatureValue + 1;
setTemperatureValue(newTemperature);
if (newTemperature >= 15) {
setTemperatureColor('hot');
}
};
const decreaseTemperature = () => {
const newTemperature = temperatureValue - 1;
setTemperatureValue(newTemperature);
if (newTemperature < 15) {
setTemperatureColor('cold');
}
};
return (
<div className='app-container'>
<div className='temperature-display-container'>
<div className={`temperature-display ${temperatureColor}`}>{temperatureValue}°Cdiv>
div>
<div className='button-container'>
<button onClick={increaseTemperature}>+button>
<button onClick={decreaseTemperature}>-button>
div>
div>
);
};
export default App;
运行 App,检查是不是一切 ok——太棒了!
扫码关注公众号,订阅更多精彩内容。