React学习
前端
135 ·
0 ·
2022-05-20 23:59:37
最新编辑原因:

React 是一个 JavaScript 库

JSX

JSX,是一个 JavaScript 的语法扩展。我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模板语言,但它具有 JavaScript 的全部功能

为什么使用 JSX?

React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。
React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离

React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。它还可以使 React 显示更多有用的错误和警告消息

JSX 也是一个表达式

在编译之后,JSX 表达式会被转为普通 JavaScript 函数调用,并且对其取值后得到 JavaScript 对象。
也就是说,你可以在 if 语句和 for 循环的代码块中使用 JSX,将 JSX 赋值给变量,把 JSX 当作参数传入,以及从函数中返回 JSX

引号(对于字符串值)或大括号(对于表达式)中的一个,对于同一属性不能同时使用这两种符号。
因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase (小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。
例如,JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex

元素渲染

元素是构成 React 应用的最小砖块。元素描述了你在屏幕上想看到的内容
不要和组件混淆,组件是由元素构成的

将React集成进已有应用
仅使用 React 构建的应用通常只有单一的根 DOM 节点。如果你在将 React 集成进一个已有应用,那么你可以在应用中包含任意多的独立根 DOM 节点。

React 元素是不可变对象。一旦被创建,你就无法更改它的子元素或者属性。一个元素就像电影的单帧:它代表了某个特定时刻的 UI。

React 只更新它需要更新的部分

React DOM 会将元素和它的子元素与它们之前的状态进行比较,并只会进行必要的更新来使 DOM 达到预期的状态。

组件 & Props

组件允许你将 UI 拆分为独立可复用的代码片段,并对每个片段进行独立构思。
组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。

函数组件与 class 组件

定义组件最简单的方式就是编写 JavaScript 函数

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

该函数是一个有效的 React 组件,因为它接收唯一带有数据的 “props”(代表属性)对象与并返回一个 React 元素。这类组件被称为“函数组件”,因为它本质上就是 JavaScript 函数。

你同时还可以使用 ES6 的 class 来定义组件:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

上述两个组件在 React 里是等效的(使用ES6的class来定义,看着好复杂啊)。

渲染组件

之前,我们遇到的 React 元素都只是 DOM 标签:
const element = <div />;
不过,React 元素也可以是用户自定义的组件:
const element = <Welcome name="Sara" />;
当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”。

例如,这段代码会在页面上渲染 “Hello, Sara”:

function Welcome(props) {  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);

上面的代码很重要,自定义组件,可以继续定义属性,例如age,获取就是props.age

注意: 组件名称必须以大写字母开头
React 会将以小写字母开头的组件视为原生 DOM 标签。例如, <div /> 代表 HTML 的 div 标签,而 <Welcome /> 则代表一个组件,并且需在作用域内使用 Welcome

组合组件

组件可以在其输出中引用其他组件
这就可以让我们用同一组件来抽象出任意层次的细节。按钮,表单,对话框,甚至整个屏幕的内容:在 React 应用程序中,这些通常都会以组件的形式表示。
最初看上去,提取组件可能是一件繁重的工作,但是,在大型应用中,构建可复用组件库是完全值得的。(程序本该如此)

Props 的只读性

所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
当然,应用程序的 UI 是动态的,并会伴随着时间的推移而变化。在下一章节中,我们将介绍一种新的概念,称之为 “state”。在不违反上述规则的情况下,state 允许 React 组件随用户操作、网络响应或者其他变化而动态更改输出内容。

State & 生命周期(这个很重要,网络交互时会用到)

State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。

将函数组件转换成 class 组件

Class 组件应该始终使用 props 参数来调用父类的构造函数。
接下来把计时器的 ID 保存在 this 之中( this.timerID )。
尽管 this.propsthis.state 是 React 本身设置的,且都拥有特殊的含义,但是其实你可以向 class 中随意添加不参与数据流(比如计时器 ID)的额外字段

正确地使用 State(重点)

关于 setState() 你应该了解三件事:

// Correct
this.setState({comment: 'Hello'});

构造函数是唯一可以给 this.state 赋值的地方。

数据是向下流动的

这通常会被叫做“自上而下”或是“单向”的数据流。任何的 state 总是所属于特定的组件,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。
如果你把一个以组件构成的树想象成一个 props 的数据瀑布的话,那么每一个组件的 state 就像是在任意一点上给瀑布增加额外的水源,但是它只能向下流动。

事件处理

React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。

  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault

  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 为了在回调中使用 `this`,这个绑定是必不可少的    this.handleClick = this.handleClick.bind(this);  }

你必须谨慎对待 JSX 回调函数中的 this ,在 JavaScript 中,class 的方法默认不会绑定 this 。如果你忘记绑定 this.handleClick 并把它传入了 onClick ,当你调用这个函数的时候 this 的值为 undefined
如果觉得使用 bind 很麻烦,这里有两种方式可以解决。
1、 你可以使用 class fields 正确的绑定回调函数(注意: 这是 实验性 语法。)
handleClick = () => { console.log('this is:', this); }
2.在回调中使用箭头函数

render() {
    // 此语法确保 `handleClick` 内的 `this` 已被绑定。    return (      <button onClick={() => this.handleClick()}>        Click me
      </button>
    );
  }

此语法问题在于每次渲染 LoggingButton 时都会创建不同的回调函数。在大多数情况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题总结,在构造器中绑定

向事件处理程序传递参数

在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

上述两种方式是等价的,分别通过箭头函数Function.prototype.bind 来实现。

在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

条件渲染

{unreadMessages.length > 0 &amp;&amp; <h2> You have {unreadMessages.length} unread messages. </h2> }
之所以能这样做,是因为在 JavaScript 中, true &amp;&amp; expression 总是会返回 expression , 而 false &amp;&amp; expression 总是会返回 false
因此,如果条件是 true&amp;&amp; 右侧的元素就会被渲染,如果是 false ,React 会忽略并跳过它。

阻止组件渲染

在极少数情况下,你可能希望能隐藏组件,即使它已经被其他组件渲染。若要完成此操作,你可以让 render 方法直接返回 null ,而不进行任何渲染。

function WarningBanner(props) {
  if (!props.warn) {    return null;  }
  return (
    <div className="warning">
      Warning!
    </div>
  );
}

列表 & Key

key

key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。
key 会传递信息给 React ,但不会传递给你的组件。如果你的组件中需要使用 key 属性的值,请用其他属性名显式传递这个值

表单

受控组件

在 HTML 中,表单元素(如 <input><textarea><select> )通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。
我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

对于受控组件来说,输入的值始终由 React 的 state 驱动。你也可以将 value 传递给其他 UI 元素,或者通过其他事件处理函数重置,但这意味着你需要编写更多的代码。

总的来说,这使得 <input type="text"> , <textarea><select> 之类的标签都非常相似—它们都接受一个 value 属性,你可以使用它来实现受控组件。

注意
你可以将数组传递到 value 属性中,以支持在 select 标签中选择多个选项:
<select multiple={true} value={['B', 'C']}>

文件 input 标签

在 HTML 中, <input type="file"> 允许用户从存储设备中选择一个或多个文件,将其上传到服务器,或通过使用 JavaScript 的 File API 进行控制。
<input type="file" />
因为它的 value 只读,所以它是 React 中的一个非受控组件

处理多个输入(重点,通常一个表单可以输入多个值)

当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作。

受控输入空值

受控组件的替代品

有时使用受控组件会很麻烦,因为你需要为数据变化的每种方式都编写事件处理函数,并通过一个 React 组件传递所有的输入 state。当你将之前的代码库转换为 React 或将 React 应用程序与非 React 库集成时,这可能会令人厌烦。在这些情况下,你可能希望使用非受控组件, 这是实现输入表单的另一种方式。

成熟的解决方案

如果你想寻找包含验证、追踪访问字段以及处理表单提交的完整解决方案,使用 Formik 是不错的选择。然而,它也是建立在受控组件和管理 state 的基础之上 —— 所以不要忽视学习它们。

状态提升(共享有点复杂,要好好看看)

https://zh-hans.reactjs.org/docs/lifting-state-up.html
通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。让我们看看它是如何运作的。
太复杂了,可以使用Context来实现 https://zh-hans.reactjs.org/docs/context.html
写Java程序也是使用简单,学React这个状态提升估计也用不大到。用到时在看。但这里显然有一个更加简便的Context可以使用

 

组合 vs 继承

你可以将任何东西作为 props 进行传递。

那么继承呢?

在 Facebook,我们在成百上千个组件中使用 React。我们并没有发现需要使用继承来构建组件层次的情况。
Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。注意:组件可以接受任意 props,包括基本数据类型,React 元素以及函数。
如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们

React 哲学

我们认为,React 是用 JavaScript 构建快速响应的大型 Web 应用程序的首选方式。它在 Facebook 和 Instagram 上表现优秀。
React 最棒的部分之一是引导我们思考如何构建一个应用。
https://zh-hans.reactjs.org/docs/thinking-in-react.html

 

高阶的要关注

https://zh-hans.reactjs.org/docs/context.html
https://zh-hans.reactjs.org/docs/forwarding-refs.html
https://zh-hans.reactjs.org/docs/fragments.html
https://zh-hans.reactjs.org/docs/higher-order-components.html
https://zh-hans.reactjs.org/docs/refs-and-the-dom.html


本作品系原创,采用《署名-非商业性使用-禁止演绎4.0 国际》许可协议.转载请说明出处
本文链接:https://www.upupor.com/u/22052006492281873408 复制

无内容

推荐阅读
暗淡蓝点 · 响应时间: 65ms · 版本:2022-06-22T08:41:16.737 · 备案号: 皖ICP备17015935号-2 · upupor.com©2022 · 项目始于2019