世界微速讯:每个初级 React 开发人员都会犯的八个错误
2022-09-04 16:05:18来源:今日头条
每个学习 React 的程序员在学习过程中都会犯大量的错误。 有时他们甚至不知道自己犯了这些错误。 如果您精通 React,则需要避免这些错误并根据最佳实践进行编码。 所以,我想展示你们所做的错误并帮助纠正它们。 在此之前,我们需要知道我们要处理什么。
(相关资料图)
什么是 React JS?React 是 Facebook 于 2011 年开发的一个 javascript 库。大多数人将其误解为一个框架。 这是一个非常基础的组件库。 它允许开发人员为网站和应用程序构建快速的用户界面。 让我们看看我们使用 React 的一些关键原因。
虚拟 DOM 增强了高性能。组件的可重用性。庞大的社区。Flux 和 Redux 的强大功能。由于它使用 JSX,任何了解 HTML 的人都可以轻松学习它。独特的反应钩子然后,让我们谈谈大多数开发人员犯的错误以及如何纠正这些错误。
与更新状态相关的错误我要告诉你们两个你们犯错误的场景。 认为您的组件中有一个名为 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 ( <>Name : {this.state.number}
> ); }}
让我们看看你在更新状态时犯的另一个错误。 想想这样的场景。 你有一个名为 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 ( <>Number : {number}
> );}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 ( <>Number : {number}
> );}export default App;
如果需要,您可以将 setNumber 放在 handleClick 中。 那不会有什么不同。
如何正确初始化状态 [对于对象]这也是大多数初级开发人员常犯的错误。 他们初始化一个没有默认值的状态。 对于单个整数或字符串,这不是什么大问题。 但是如果你正在初始化一个对象,你必须提到默认值。 否则,访问该对象的属性时会出错。 让我们获取一个名为 user 的对象。
如果你像这样初始化它。
const [user, setUser] = useState();
之后在其他地方为它分配一个值。
setUser({ name: "kushan", age: 24, friends: ["john", "Anne", "will"]});
之后,如果您像这样访问对象属性,您将收到错误消息。
name : {user.name}
错误会这样说:
您可以进行两项更改来进行此写入。
1.访问前添加&&
name : {user && user.name}
2. 添加?。 访问时
name : {user?.name}
但是,我建议您在初始化时添加一个默认值。 您可以添加具有空值的预期属性。
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 ( <>name : {user.name}
age : {user.age}
friends :
- {user.friends?.map((friend) => (
-
{friend}
))}
首先,我将展示开发人员执行此操作的一些错误方式。
setUser(input);orsetUser({name : input});
这将替换对象并分配我们在此处输入的输入。 那不是我们想要的。 这就是它正确更新的方式。
setUser({...user, name : input});orsetUser((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 函数之后。
你要创建单独的 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 (直接 DOM 操作);}export default App;
你以前写过这样的代码吗:
function App() { const handleClick = () => { const menu = document.querySelector(".menu"); menu.classList.add("color"); } return ( <>Sample Text> );}
问题?
这在新开发人员中很常见。 我们不应该在反应中直接进行 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 ( <>useState 与 useReducer(何时使用?)Sample Text> );}
当我们需要一个状态时,在任何地方都使用 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 ();}export default App;{classRooms.map((classRoom) => ())}{classRoom.className}
{classRoom.studentCount}
Class Name : {selectedClass?.className}
Student No : {selectedClass?.studentCount}
问题?
这将增加学生人数并按预期选择相关课程。 但是如果你在选择教室后尝试增加学生人数,学生人数就会增加。 但所选区域的学生人数不会更新。 我们实现代码的方式就是原因。 大多数开发人员都会犯这个错误。 我们将如何解决这个问题?
您可以将所选教室的唯一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 ();}export default App;{classRooms.map((classRoom) => ())}{classRoom.className}
{classRoom.studentCount}
Class Name : {selectedClass?.className}
Student No : {selectedClass?.studentCount}
所以,本文到此结束。 我已经讨论了8个会出错的点。 大多数初学者开发人员一直在做这些错误的方式。 因此,我认为这将帮助您纠正错误并更上一层楼。