每个初级 React 开发人员都会犯的八个错误

开发 前端
每个学习 React 的程序员在学习过程中都会犯大量的错误。 有时他们甚至不知道自己犯了这些错误。 如果您精通 React,则需要避免这些错误并根据最佳实践进行编码。 所以,我想展示你们所做的错误并帮助纠正它们。 在此之前,我们需要知道我们要处理什么。


每个学习 React 的程序员在学习过程中都会犯大量的错误。 有时他们甚至不知道自己犯了这些错误。 如果您精通 React,则需要避免这些错误并根据最佳实践进行编码。 所以,我想展示你们所做的错误并帮助纠正它们。 在此之前,我们需要知道我们要处理什么。

什么是 React JS?

React 是 Facebook 于 2011 年开发的一个 javascript 库。大多数人将其误解为一个框架。 这是一个非常基础的组件库。 它允许开发人员为网站和应用程序构建快速的用户界面。 让我们看看我们使用 React 的一些关键原因。

  1. 虚拟 DOM 增强了高性能。
  2. 组件的可重用性。
  3. 庞大的社区。
  4. Flux 和 Redux 的强大功能。
  5. 由于它使用 JSX,任何了解 HTML 的人都可以轻松学习它。
  6. 独特的反应钩子

然后,让我们谈谈大多数开发人员犯的错误以及如何纠正这些错误。

与更新状态相关的错误

我要告诉你们两个你们犯错误的场景。 认为您的组件中有一个名为 number 的状态。

const [number, setNumber] = useState(0);

现在,您将更新该状态并在下一行中访问它。

setNumber(5);
console.log(number);

你会认为这会安慰 5。但事实并非如此。 它将先前的值控制台为 0 。

原因?

你应该知道setState函数(这里是setNumber)是一个异步函数。 由于该功能是异步控制器在更新之前不会保持。 它将转到下一行并控制 number 的值(它将控制 0,因为该数字尚未更新 5)。 因此,如果您正在使用 setNumner 语句下方的 number 的更新值编写另一个语句,那么您的逻辑将完全错误。

在类组件中,我们有一种方法可以在更新后立即访问更新的值。 但是对于功能组件,我们不能使用这种方法。

您可以使用 setState 调用回调函数来访问更新的值。

this.setState({ number: 5 }, () => console.log(this.state.number));

现在,它将控制台 5 。 这是完整的代码段。

import React, { Component } from "react";

export default class TestComponent extends Component {
constructor() {
super();
this.state = { number: 0 };
}

handleClick = () => {
this.setState({ number: 5 }, () => console.log(this.state.number));
};

render() {
return (
<>
<h2>Name : {this.state.number}</h2>
<button onClick={this.handleClick}>Click</button>
</>
);
}
}

让我们看看你在更新状态时犯的另一个错误。 想想这样的场景。 你有一个名为 number 的变量和两个按钮来增加这个变量的值。 一个按钮是普通按钮,数字加1。另一个按钮是异步增加数字。 该按钮发生错误。 这是大多数开发人员编写的场景的代码。

import { useState } from "react";

function App() {
const [number, setNumber] = useState(0);

const handleClick = () => {
setNumber(number + 1);
};

const handleClickAsync = () => {
setTimeout(()=> {
setNumber(number + 1);
}, 4000)
};
return (
<>
<h2>Number : {number}</h2>
<button onClick={handleClick}>Increase</button>
<button onClick={handleClickAsync}>IncreaseAsync</button>

</>
);
}

export default App;

问题?

增加按钮没有任何问题。 但是如果我们点击一次IncreaseAsync按钮,然后点击Increase Button 5次,在4秒之前数字会增加到5。但是在4秒之后数字会是1。原因是在handleClickAsync函数中,当数字更新时,setNumber函数获取 单击“IncreaseAsync”按钮时的数字值。 那一刻,数字的值为0。所以,4秒后数字变成了1。

我们可以像这样设置 setNumber 函数来克服这个问题。 然后,它将获取要更新的数字的当前值。

setNumber((prevSate)=> prevSate + 1);

更正后完整的代码将是这样的。

import { useState } from "react";

function App() {
const [number, setNumber] = useState(0);

const handleClick = () => {
setNumber((prevSate) => prevSate + 1);
};

const handleClickAsync = () => {
setTimeout(() => {
setNumber((prevSate) => prevSate + 1);
}, 4000);
};
return (
<>
<h2>Number : {number}</h2>
<button onClick={handleClick}>Increase</button>
<button onClick={handleClickAsync}>IncreaseAsync</button>
</>
);
}

export default App;

如果需要,您可以将 setNumber 放在 handleClick 中。 那不会有什么不同。

如何正确初始化状态 [对于对象]

这也是大多数初级开发人员常犯的错误。 他们初始化一个没有默认值的状态。 对于单个整数或字符串,这不是什么大问题。 但是如果你正在初始化一个对象,你必须提到默认值。 否则,访问该对象的属性时会出错。 让我们获取一个名为 user 的对象。

如果你像这样初始化它。

const [user, setUser] = useState();

之后在其他地方为它分配一个值。

setUser({
name: "kushan",
age: 24,
friends: ["john", "Anne", "will"]
});

之后,如果您像这样访问对象属性,您将收到错误消息。

<h2>name : {user.name}</h2>

错误会这样说:

您可以进行两项更改来进行此写入。

1.访问前添加&&

<h2>name : {user && user.name}</h2>

2. 添加?。 访问时

<h2>name : {user?.name}</h2>

但是,我建议您在初始化时添加一个默认值。 您可以添加具有空值的预期属性。

const [user, setUser] = useState({
name: "",
age: "",
friends: [],
});

更新对象

在这里,我们将讨论如何以适当的方式更新对象。 让我们使用具有初始值的前一个用户对象。

const [user, setUser] = useState({
name: "kushan",
age: 24,
friends: ["john", "Anne", "will"],
});

添加带有按钮的输入字段以更改用户对象的名称。 我已经分别显示了对象属性。

import { useState } from "react";

function App() {
const [user, setUser] = useState({
name: "kushan",
age: 24,
friends: ["john", "Anne", "will"],
});
const [input, setInput] = useState("");
const handleClick = () => {
//
//
// update the object here
//
//
};

return (
<>
<h2>name : {user.name}</h2>
<h2>age : {user.age}</h2>
<h2>friends :</h2>
<ul>
{user.friends?.map((friend) => (
<li key={friend}>
<h4>{friend}</h4>
</li>
))}
</ul>

<input
type="text"
placeholder="Enter new name"
onChange={(e) => setInput(e.target.value)}
/>
<button onClick={handleClick}>Click</button>
</>
);
}

export default App;

首先,我将展示开发人员执行此操作的一些错误方式。

setUser(input);
or
setUser({name : input});

这将替换对象并分配我们在此处输入的输入。 那不是我们想要的。 这就是它正确更新的方式。

setUser({...user, name : input});
or
setUser((prevState) => ({ ...prevState, name: input }));

创建一个对象而不是单独的状态

在每个 Web 应用程序中,我们都使用对象。 一些开发人员为对象的属性定义单独的状态。 这会花费大量时间并降低代码的可读性。 想想,我们的应用程序中有一个用户,我们创建了一个表单来获取用户详细信息。 你打算用什么来存储这些用户详细信息?

在这样的不同状态下:

const [fName, setFName] = useState("");
const [lName, setLName] = useState("");
const [email, setEmail] = useState("");
const [age, aetAge] = useState("");
const [city, setCity] = useState("");
const [gender, setGender] = useState("");
const [password, setPassword] = useState("");

不……您应该使用一种状态来创建它:

const [user, setUser] = useState({
fName: "",
lName: "",
email: "",
age: "",
city: "",
gender: "",
address: "",
password: "",
});

为表单中的所有输入创建单个 onChage 函数

让我们以上面的场景为例。 我们可以创建一个表单来获取该用户的详细信息。 在您将如何为这些输入字段创建 onChange 函数之后。

<input type='text' name="fName" />
<input type='text' name="lName" />
<input type='text' name="email" />
<input type='text' name="age" />
<input type='text' name="city" />
<input type='text' name="gender" />
<input type='text' name="address" />
<input type='password' name="password" />

你要创建单独的 onChange 函数吗?

onChange={(e) => setUser((prevState)=>({ ...prevState, fName: e.target.value }))}onChange={(e) => setUser((prevState)=>({ ...prevState, lName: e.target.value }))}onChange={(e) => setUser((prevState)=>({ ...prevState, email: e.target.value }))}....likewise

情况不妙。 您可以使用更好的方法来执行此操作。 为所有输入字段创建一个 onChange 函数。 您需要将用户的相同属性名称添加到输入标签的名称属性中。

const handleChange = (e) => {
setUser((prevState) => ({...prevState,[e.target.name]:e.target.value }));
};

这里的完整代码:

import { useState } from "react";

function App() {
const [user, setUser] = useState({
fName: "",
lName: "",
email: "",
age: "",
city: "",
gender: "",
address: "",
password: "",
});

const handleChange = (e) => {
setUser((prevState) => ({ ...prevState, [e.target.name]: e.target.value }));

};

return (
<div>
<form>
<input type="text" onChange={handleChange} name="fName" placeholder="fName" />
<input type="text" onChange={handleChange} name="lName" placeholder="lName" />
<input type="text" onChange={handleChange} name="email" placeholder="email" />
<input type="text" onChange={handleChange} name="age" placeholder="age" />
<input type="text" onChange={handleChange} name="city" placeholder="city" />
<input type="text" onChange={handleChange} name="gender" placeholder="gender" />
<input type="text" onChange={handleChange} name="address" placeholder="address" />
<input type="password" onChange={handleChange} name="password" placeholder="password" />
</form>
<button >Submit</button>
</div>
);
}

export default App;

直接 DOM 操作

你以前写过这样的代码吗:

function App() {
const handleClick = () => {
const menu = document.querySelector(".menu");
menu.classList.add("color");
}
return (
<>
<div className="menu">Sample Text</div>
<button onClick={handleClick}>Click</button>
</>
);
}

问题?

这在新开发人员中很常见。 我们不应该在反应中直接进行 DOM 操作。 为此,我们可以在我们的 react 组件中使用状态,而不是访问 DOM 元素并向它们添加类。 如果应用程序混淆了 DOM 内部的状态,它将变得更难测试、更难调试并且更难推理。

在这里,一个可能的解决方案。 我在没有使用 document.querySelector 的情况下完成了任务。

import { useState } from 'react';
import './App.css'function App() {
const [isColored, setIsColored] = useState(false);
const handleClick = () => {
setIsColored(true);
}
return (
<>
<div className={isColored ? "color": "" + "menu" }>Sample Text</div>
<button onClick={handleClick}>Click</button>
</>
);
}

useState 与 useReducer(何时使用?)

当我们需要一个状态时,在任何地方都使用 useState 是不是一个常量? 答案是不。 有时我们有更好的选择,而不是使用 useSate。 它是 useReducer 。 当然,没有规定你应该使用 useReducer 而不是 useState,如果你仍然使用它也没有错。 但在某些特定情况下,useReducer 更有优势。

例如,假设您有一个更复杂的对象,它具有不同的属性,如数组和嵌套对象。

const [post, setPost] = useState({
title: "",
description: "",
date: "",
category: "",
image: [],
tag: [],
owner: {
name: "",
email: "",
}
});

然后,最好使用 reducer,因为当你更新不同的属性时,这里会很乱。 因为这里的所有元素都不是前面示例中的字符串或数字。 所以我们不能在一个函数中更新它们。 因此,在这里创建一个 useReducer 并为每个属性使用不同的操作可能会更有用。 因为最好使用 useReducer 。

小心 React 派生的状态

为了理解这一点,我创建了一个小场景。 假设我们有一个名为 classRooms 的状态,它是一个对象数组。

const [classRooms, setClassRooms] = useState([
{ id: 1, className: "Sons of Sun", studentCount: 12 },
{ id: 2, className: "Blooming Volcanoes", studentCount: 10 },
{ id: 3, className: "Pillaging Pirates", studentCount: 20 },
{ id: 4, className: "Ping Bombs", studentCount: 8 },
]);

我们要做的是,我们将在屏幕上显示这个数组,并给出一个选择按钮和一个增加按钮(用于增加学生)。 所选的班级也将显示出来。

这是代码。 但我做错了。

import { useState } from "react";
import "./App.css";

function App() {
const [classRooms, setClassRooms] = useState([
{ id: 1, className: "Sons of Sun", studentCount: 12 },
{ id: 2, className: "Blooming Volcanoes", studentCount: 10 },
{ id: 3, className: "Pillaging Pirates", studentCount: 20 },
{ id: 4, className: "Ping Bombs", studentCount: 8 },
]);

const [selectedClass, setSelectedClass] = useState(null);

const handleSelect = (id) => {
setSelectedClass(classRooms.find((classRoom) => classRoom.id === id));
};
const handleIncrease = (id) => {
setClassRooms((prevState) => {
return prevState.map((classRoom) => {
if (classRoom.id === id) {
return { ...classRoom, studentCount: classRoom.studentCount + 1 };
} else return classRoom;
});
});
};

return (
<div className="container">
<div className="classRooms">
{classRooms.map((classRoom) => (
<div className="classRoom">
<div className="text">
<h4>{classRoom.className}</h4>
<h2>{classRoom.studentCount}</h2>
</div>
<button onClick={() => handleSelect(classRoom.id)}>Select</button>
<button onClick={() => handleIncrease(classRoom.id)}>
Increase Student
</button>
</div>
))}
</div>

<div className="selectedRoom">
<div className="classRoom">
<h4>Class Name : {selectedClass?.className}</h4>
<h2> Student No : {selectedClass?.studentCount}</h2>
</div>
</div>
</div>
);
}

export default App;

问题?

这将增加学生人数并按预期选择相关课程。 但是如果你在选择教室后尝试增加学生人数,学生人数就会增加。 但所选区域的学生人数不会更新。 我们实现代码的方式就是原因。 大多数开发人员都会犯这个错误。 我们将如何解决这个问题?

您可以将所选教室的唯一ID存储在该州中。 然后取一个名为 selectedClassID 的变量并将选定的教室分配给它。

const [selectedClass, setSelectedClass] = useState(null);// not thisconst [selectedClassID, setSelectedClassID] = useState(null);//do like this

声明并赋值给 selectedClassID

const selectedClass = classRooms.find((classRoom) => classRoom.id === selectedClassID);

接下来,改变handleSelect函数

const handleSelect = (id) => {
setSelectedClassID(id);
};

这是修正后的完整代码:

import { useState } from "react";
import "./App.css";

function App() {
const [classRooms, setClassRooms] = useState([
{ id: 1, className: "Sons of Sun", studentCount: 12 },
{ id: 2, className: "Blooming Volcanoes", studentCount: 10 },
{ id: 3, className: "Pillaging Pirates", studentCount: 20 },
{ id: 4, className: "Ping Bombs", studentCount: 8 },
]);

const [selectedClassID, setSelectedClassID] = useState(null);
const selectedClass = classRooms.find(
(classRoom) => classRoom.id === selectedClassID
);

const handleSelect = (id) => {
setSelectedClassID(id);
};
const handleIncrease = (id) => {
setClassRooms((prevState) => {
return prevState.map((classRoom) => {
if (classRoom.id === id) {
return { ...classRoom, studentCount: classRoom.studentCount + 1 };
} else return classRoom;
});
});
};

return (
<div className="container">
<div className="classRooms">
{classRooms.map((classRoom) => (
<div className="classRoom">
<div className="text">
<h4>{classRoom.className}</h4>
<h2>{classRoom.studentCount}</h2>
</div>
<button onClick={() => handleSelect(classRoom.id)}>Select</button>
<button onClick={() => handleIncrease(classRoom.id)}>
Increase Student
</button>
</div>
))}
</div>

<div className="selectedRoom">
<div className="classRoom">
<h4>Class Name : {selectedClass?.className}</h4>
<h2> Student No : {selectedClass?.studentCount}</h2>
</div>
</div>
</div>
);
}

export default App;

所以,本文到此结束。 我已经讨论了8个会出错的点。 大多数初学者开发人员一直在做这些错误的方式。 因此,我认为这将帮助您纠正错误并更上一层楼。

责任编辑:华轩 来源: 今日头条
相关推荐

2022-12-29 08:27:03

Java开发人员编码

2020-05-25 16:36:19

开发工具编码

2019-04-24 08:56:34

Java开发人员常犯错误

2021-12-10 13:06:37

低代码无代码开发人员

2009-06-25 09:04:22

.NET开发人员

2020-04-20 18:15:46

开发自信技术

2015-03-10 10:35:41

2020-05-17 16:10:36

开发人员软件开发开发

2015-09-21 09:34:57

2019-08-13 14:32:28

JavaScriptjQuery浏览器

2019-08-13 16:34:55

开发jQueryJavaScript

2022-06-05 23:47:06

开发无代码低代码

2022-09-12 15:51:38

JavaScrip开发编程语言

2017-10-11 13:20:56

Linux命令工程师

2020-09-23 22:40:31

Python 开发编程语言

2020-12-22 13:49:23

开发编码框架

2023-10-13 18:10:14

编程语言Rust

2024-02-14 08:00:00

ChatGPTReact人工智能

2024-06-04 14:31:16

2019-08-07 11:00:07

程序员技能开发者
点赞
收藏

51CTO技术栈公众号