React 101:每个初学者都应该知道的事情-第1部分

因此,在与同行进行了长时间的讨论之后,甚至是更长的在线研究(Stack Overflow和其他内容)之后,您最终选择了使用React。 经过长时间考虑,您已经成功地忽略了Angular,Vue甚至Jquery等框架和库。 恭喜,您已成功受到影响。

好吧,至少在一定程度上,这就是我的故事。 在意识到Angular.js 1.6并没有太大帮助之后,我开始研究不同的库和框架。 那是两年前。 在对Medium感到沮丧之后,我建立了一个个人博客(是我的钱,对吗?),所以决定使用Angular.js,这当然很容易上手。 该站点已完工并投入生产,只是为了开始发现其中的问题(我们稍后可以讨论问题),因此开始了挖掘工作。

在接下来的几周里,我会深入研究-每篇博客和中篇文章-这就是我得出的初步结论-它将是Angular 2或React。 展望未来,我发现了关于响应方式设计的一些独特之处,例如JS中的HTML? 凉。 最终,我对Angular.js指令和其他框架组件的最初挫败感得到了回报,我决定尝试一下React,毕竟这只是一个博客。 更不用说,Angular 2还不错,那是我当时选择与React一起使用的,而且您知道在线影响力(Dan Abramov仍然继续对他产生积极影响,请务必跟随他)。

现在,回到这篇文章,我讲了这个故事,因为我想让你知道我开始写React应用已经不多了,而且我相信我有足够的资格撰写针对初学者的文章。 本文包含了我希望使用React开始撰写此博客时希望从某人那里获得的提示(是的,它仍然存在很多问题!)。 我根据过去两年的经验写了每一点。 希望对您有所帮助。 让我们开始!

1.将组件保存在专用文件夹中

我可能没有选择Angular(简称ng 2),但是我确实借鉴了它的结构化思想。 在ng 2中,当您使用这样的CLI创建组件时,

  ng生成组件“ component-name” 

您会注意到它为该组件创建了一个文件夹,其中包含.ts, .css, .spec.ts, and .html文件。 我们遵循相同的模式。 组件必须驻留在专用文件夹中,该文件夹带有与该组件相同的名称,并且子组件将在父文件夹内继续相同的模式。 有好处吗? 它使代码组件的组织干净。

我借用的另一件事是为每个组件保留CSS文件或为每个.js文件保持反应的想法。 这样,我们可以专注于样式化组件而不破坏任何其他组件样式。 它带来的另一个好处是我们可以完全忽略一个组件,并且不会增加整个类的大小,即; 我们不会错误地包括未使用的CSS。 整洁吧? 哦,而且, .css文件与js组件位于同一文件夹中。 如果您喜欢这种结构,可以选择养成这种习惯!

2.道具与国家之间的区别

当刚开始使用React时,人们常常会混淆道具和状态。 最简单的答案是,状态是可变的,并且基于组件本身—父级或其他组件无法触摸或更新它。

另一方面,道具是不可变的,无法在组件内部进行更改,更像是最终值(或常量)。 仅在父组件这样做时才更新它们。 道具是父组件将数据传递到子组件或更实际命名的哑组件的一种方式。 让我们通过一个简单的示例了解道具和状态的不同。 这是我们的父母,用两个道具(即名称和年龄)为孩子渲染了孩子,这两个道具分别包含用户的姓名和年龄。

 父类扩展React.Component { 
render(){
return()
}
}

另一方面,子组件看起来像这样,

 子类扩展React.Component { 
render(){
返回(

用户名:{this.props.name}
年龄:{this.props.age}


}
}

注意子组件中props的使用吗? 道具不过是父级在渲染过程中设置的子级组件的特殊属性。 子级可以利用这些子级在渲染期间设置数据值。 一旦将道具传递到层次结构中,子对象就不能对其进行突变。

正如我之前所说,状态被设计为具有可变性,因此组件本身可以处理更改而无需父级更新道具。 组件可以处理其内部更改的状态,例如,单击“子”组件中的按钮,用户名应从“ Nilesh Singh”更改为“ John Doe”,而我们无法使用props因为它们在子级是不变的。 因此我们像这样在Child中定义一个状态,

 子类扩展React.Component { 
构造函数(道具){
超级(道具)
this.state = {用户名:'Nilesh Singh'}
}
}

是的,状态只是一个JavaScript对象,该对象将所有值保存为键和值。 同样,状态应该始终在构造函数中定义,以便React可以在构造过程中建立状态以避免在渲染过程中出现null或未定义的值。

一旦完成状态初始化,就可以在组件中的任何地方使用它。 让我们将此用户名状态设置为渲染中的用户名,然后在单击按钮时手动更改它。

  handleClick(e){ 
this.setState(prevState => {return {用户名:'John Doe'}})
}
  render(){ 
返回(

用户名:{this.state.username}
年龄:{this.props.age}



}

请注意,单击按钮后,将调用handleClick函数,该函数随后使用特殊方法setState(…)更新当前状态。 那么,为什么我称其为特殊方法呢? 通过执行此操作,我们可以简单地在不使用方法的情况下更新状态对象的username属性,

  this.state.username ='John Doe' 

当然可以,但是这不会在UI端更改任何内容,即,在中,所有文本都不会更改为“ John Doe”。 它只会更改值,而无需重新渲染。 为了重新渲染,我们应该调用setState(…)方法,然后将用户名更新为“ John Doe”,然后再调用组件的render(…)方法,以反映该值的变化。用户界面。

但是,您会注意到,用户名值仅在第一次更改,然后保持不变,因此,这里的反应是什么—毕竟,无论每次点击,我们都在每次调用setState(…)方法值是否改变。 好吧,这是React真正发挥作用的部分。 当然,每次调用setState时都会触发render方法,但是React首先通过建立虚拟DOM来检查实际值更改,将其与本机DOM匹配,然后在检测到差异时更新本机DOM。 您可以在此处阅读有关虚拟DOM的更多信息。

另外,Props和State都可以用于将值彼此设置,但这并不意味着它们可以在彼此的位置使用。 将它们分开,并尝试最小化状态更新,因为每次状态更新都会触发重新渲染,并且即使本机DOM由于值不变也不会更改,但值得注意的是虚拟DOM本身会占用一些周期建立并匹配(差异化)。 一个简单的状态和道具相互建立的例子是,

  render(){ 
return()
}

要么

 子类扩展React.Component { 
构造函数(道具){
this.state = {
用户名:this.props.name
}
}
}

哦,是的,请始终记住,状态的改变不仅会导致组件的重新渲染,而且道具的改变也会触发该组件。

3.避免使用无用的容器,改用Fragments

有时候,我们需要在React应用程序中具有组件的层次结构。 尽管在React中这样做很容易,但我们经常忽略的一件事是HTML调用的结构,即; 我们经常保留无用的容器HTML标记,这些标记甚至在层次结构中都没有作用。 例如,

g假设我们有一个父类,它调用名为Child的子组件。 父母的结构是这样的,

  


现在,我们的子组件只做一件事,就是说是一个孩子。 该文本周围的div将被证明是无用的,因为它无法控制其中的文本,如果它具有绑定到类甚至样式的文本,则在某种程度上将被证明是有用的,但是在这里它并没有。

  

嗨,这是一个孩子!

因此,在父HTML呈现内部带有子HTML的情况下,最终的HTML看起来像这样,

  


嗨,这是一个孩子!

瞧,第二个div是没用的-无法控制下一个孩子。 文本。 我们可能忽略了这一点,但是再次需要将每个组件包装在标签中,对吗? 当然可以,但是我们可以使用内部React组件替换此

或任何其他HTML标记,以确保当父对象调用子组件时,该特殊react组件的内部子组件将被呈现而无需组件本身。 这个特殊的组件称为Fragment

现在,带有该Fragment的子组件将如下所示:

   
嗨,这是一个孩子!

或者,如果您对上述语法有误,则可以将此语法用于片段。 不过,请记住,首先要在模块中导入Fragment。

 从'react'导入{片段}; 
   
嗨,这是一个孩子!

现在,当我们的这个新的更新子级被父级调用时,它完全呈现后会看起来像这样,

  

嗨,这是一个孩子!

看,无用的div已成功消除。 在将虚拟DOM更改为真实DOM时,React所做的是,它仅返回Fragment组件的子代,如下所示:

  render(){ 
返回this.props.children
}

这可能看起来有点费劲,要识别无用的容器标签并用Fragments代替它们,但是从长远来看,当接口的层次结构规模很大并开始受苦时,它将获得回报。

4.总是退订组件中的事件和处理程序

通过提供等效的合成事件,React使得处理组件中的事件变得更加容易,例如, onclick成为React中的onClick,需要回调函数,

   

这看起来简单易用,不是吗? 好吧,如果您有一个综合事件,这很简单,因为React会解决这个问题,但是如果我们没有得到一个综合事件,该怎么办?

例如, Window大小调整更改事件在React中不可用,因此我们需要依赖文档事件侦听器。 组件装入后,我们可以像这样使用侦听器,

  componentDidMount(){ 
window.addEventListener('resize',this.sizeChanged);
}
  sizeChanged(){ 
//大小已更改console.log(window.innerWidth,window.innerHeight)
}

并且只要浏览器窗口大小发生变化,便能够读取屏幕大小。 但是始终选择在事件的目的在上下文中结束后才删除事件侦听器,或者仅完成(或销毁)组件以避免内存泄漏。 我们可以通过调用componentWillUnmount中的removeEventListener来删除事件侦听器,这表明组件将被删除或销毁。

  componentWillUnmount(){ 
window.removeEventListener('resize',this.sizeChanged)
}

超时或间隔也是如此。 一旦认为它们不再有用,请始终确保在componentWillUnmount或任何其他生命周期方法中将其删除。 这是程序员在构建应用程序时忽略应用程序内存泄漏的可能性时常犯的错误。

5.避免无用的课程

初学者通常会犯的另一个错误是,假设每个组件都必须是一个类。 不必要。 如果您的组件除了基于传递的属性返回(或不返回)一堆HTML之外,仅使用函数。 这种设置也称为功能性无状态组件,因为这样的组件不能具有状态,因为它只是简单的javascript函数返回的HTML。

需要记住的另一件事是,除了状态之外,您还没有使用功能组件的生命周期方法,因此,如果组件依赖于生命周期挂钩或必须具有局部状态,则选择使用基于类的组件。

功能性无状态组件的一个简单示例是,

 功能Child(props){ 
返回(
您好,来自无状态组件:{props.name}


}

6.利用代理

很有可能您将不得不查询可能在同一台计算机上开发的本地API。 没问题,如果您在端口8080上运行开发服务器,则可以使用http://localhost:8080进行查询。示例请求如下所示,

 提取('http:// localhost:8080 / api / my-endpoint') 
.then(res => res.json())
.then(data => {
console.log('Received:',data);
})

在您开始构建用于生产的应用程序或需要完全查询其他端点URL之前,这种设置才有意义。 这就是代理的来源。React为我们提供了代理功能,通过它我们可以定义一个替代端点,react内部的请求需要到达该端点。 整洁,不是吗?

可以通过在package.json文件中添加proxy属性,然后将备用URL设置为其值,来使用React设置代理,

  { 
“ name”:“ my-react-app”,
“ version”:“ 0.0.1”,
“私人”:是的,
“ proxy”:“ http:// localhost:6000”,//这是发生魔术的地方
“依赖项”:{...}
}

这对于维护仅到代理端点的干净,有组织的请求结构很有帮助。 将其视为拦截器(如Ng 2拦截器),其中React使用基本路径将请求重定向到代理端点,而不是自身。 设置完上述代理后,我们可以执行此操作

 提取('/ api / my-endpoint') 
.then(res => res.json())
.then(data => {
console.log('Received:',data);
})

并且我们的请求将开始进入http://localhost:6000 。 哦,是的,在将代理添加到package.json之后,请确保您重新启动react(使用npm start)。

7.更好地使用Create-React-App

大多数在线教程(通常是旧教程)建议您通过设置所有配置(例如webpack,babel和其他内容)从最基础的内容开始React学习。 我同意,对于一个项目而言,这似乎还可以-您对使魔术发生的事情有了了解,但是一旦您从一个项目转移到多个项目,复制相同的配置和文件就变得很痛苦一遍又一遍到不同的目录。 同样,您也增加了在这样的组织中重用过时的代码的机会。

为了避免此类问题,现在建议使用Create-React-App CLI(命令行界面)来创建新的React应用程序。 使用Create-React-App工具,我们可以获得React项目的完整初始结构,webpack和babel的设置以及其他依赖项的安装。 只需运行以下npm命令(带有全局标志),您就可以全局使用该工具。

  npm install -g create-react-app 

完成后,运行以下命令以(1)使用名称my-react-app创建您的应用,然后(2)移动该工具刚刚创建的项目目录,然后最后(3)使用npm start React应用。

 创建反应应用程序我反应应用程序my-react-app / 
  npm开始 

无需配置任何内容,该工具可以处理所有内容。 但是,这也带来了一个问题-使用这种设置,您实际上无法更改webpack或预设(babel),除非您返回到正常的设置,而该项目被视为样板和webpack,而其他依赖项却the肿了。 package.json文件。

Create-react-app确实使您能够移动。 您可以返回到常规设置,

  npm运行弹出 

但是,我建议否则-只能使用create-react-app工具。 不要每次都要管理多个配置文件,也不要进行更新反应,甚至不保持package.json干净并加载有用的元数据的开销,而让系统(该工具)处理其他事情。

# 接下来是什么?

这7种做法中有6种是可选的,但强烈建议您记住这些原则,并在常规使用中构建更高效的React应用。 这些一开始可能看起来很多,但请相信我,一旦习惯了,就会发现它们为您节省了大量时间和资源。

这样,我们完成了本文。 我知道,这只是每个初学者都应该了解的更多的7种实践,但是,使一篇文章不必要地冗长,并给初学者投入很多东西是不公平的。 在接下来的几周内,我们将针对React开发初学者发布更多此类文章。 请务必订阅我们的新闻通讯,以获取最新动态,并获取我们在此处发布的最新文章。