- 参照React官方文档(https://react.docschina.org/docs/hello-world.html)
- JavaScript 新语法需要注意的三点:(这三点应该让您有足够的知识来阅读React文档)
- 我们用let和const语句定义变量。出于React文档的目的,您可以将它们视为等效于var。
- 我们使用class关键字来定义JavaScript类。有两件事值得记住。首先,与对象不同,您不需要在类方法定义之间放置逗号。其次,与许多其他类的语言不同,在JavaScript中this,方法的值取决于它的调用方式。
- 我们有时会=>用来定义“箭头函数”。它们就像常规功能一样,但更短。例如,x => x * 2大致相当于function(x) { return x * 2; }。重要的是,箭头函数没有自己的this值,因此当您想要保留this外部方法定义中的值时,它们很方便。
- JSX tips
- JSX,是一个 JavaScript 的语法扩展。我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能。
- JSX 可以生成 React “元素”。
- React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。它还可以使 React 显示更多有用的错误和警告消息。
- 为了便于阅读,我们会将 JSX 拆分为多行。同时,我们建议将内容包裹在括号中,虽然这样做不是强制要求的,但是这可以避免遇到自动插入分号陷阱。
- 在属性中嵌入 JavaScript 表达式时,不要在大括号外面加上引号。你应该仅使用引号(对于字符串值)或大括号(对于表达式)中的一个,对于同一属性不能同时使用这两种符号。
- 因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。
- Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。React.createElement() 会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个对象,这些对象被称为 “React 元素”。它们描述了你希望在屏幕上看到的内容。React 通过读取这些对象,然后使用它们来构建 DOM 以及保持随时更新。
- 元素渲染
- 元素是构成 React 应用的最小砖块,描述了你在屏幕上想看到的内容。与浏览器的 DOM 元素不同,React 元素是创建开销极小的普通对象。React DOM 会负责更新 DOM 来与 React 元素保持一致。
- 将一个元素渲染为 DOM:
- 仅使用 React 构建的应用通常只有单一的根 DOM 节点。如果你在将 React 集成进一个已有应用,那么你可以在应用中包含任意多的独立根 DOM 节点。
- 想要将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入 ReactDOM.render()
const element = <hello>world</hl>;
ReactDOM.render(element, document. getElementById(' root' ));
- 更新已渲染的元素:
- React 元素是不可变对象。一旦被创建,你就无法更改它的子元素或者属性。一个元素就像电影的单帧:它代表了某个特定时刻的 UI。
- 根据我们已有的知识,更新 UI 唯一的方式是创建一个全新的元素,并将其传入 ReactDOM.render()。
- 组件&Props
- 渲染组件:
之前遇到的 React 元素都只是 DOM 标签(如<div />),不过,React 元素也可以是用户自定义的组件:
const element = <Welcome name = "Sara" />;
当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)转换为单个对象传递给组件,这个对象被称之为 “props”。
- 我们调用 ReactDOM.render() 函数,并传入 <Welcome name="Sara" /> 作为参数。
- React 调用 Welcome 组件,并将 {name: 'Sara'} 作为 props 传入。
- Welcome 组件将 <h1>Hello, Sara</h1> 元素作为返回值。
- React DOM 将 DOM 高效地更新为 <h1>Hello, Sara</h1>。
- 组件名称必须以大写字母开头:
React 会将以小写字母开头的组件视为原生 DOM 标签。例如,<div /> 代表 HTML 的 div 标签,而 <Welcome /> 则代表一个组件,并且需在作用域内使用 Welcome。
- 组合组件:
组件可以在其输出中引用其他组件。这就可以让我们用同一组件来抽象出任意层次的细节。按钮,表单,对话框,甚至整个屏幕的内容:在 React 应用程序中,这些通常都会以组件的形式表示。
- 通常来说,每个新的 React 应用程序的顶层组件都是 App 组件。但是,如果你将 React 集成到现有的应用程序中,你可能需要使用像 Button 这样的小组件,并自下而上地将这类组件逐步应用到视图层的每一处。
- 命名:我们建议从组件自身的角度命名 props,而不是依赖于调用组件的上下文命名。
- 提取组件:最初看上去,提取组件可能是一件繁重的工作,但是,在大型应用中,构建可复用组件库是完全值得的。根据经验来看,如果 UI 中有一部分被多次使用(Button,Panel,Avatar),或者组件本身就足够复杂(App,FeedStory,Comment),那么它就是一个可复用组件的候选项。
- Props 的只读性:组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props。“纯函数”不会尝试更改入参,且多次调用下相同的入参始终返回相同的结果。所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
- State & 生命周期(state详解参见 https://blog.csdn.net/b954960630/article/details/79822639)
- state是什么?
- React 的核心思想是组件化,而组件中最重要的概念是State(状态),State是一个组件的UI数据模型,是组件渲染时的数据依据。
- 状态(state) 和 属性(props) 类似,都是一个组件所需要的一些数据集合,但是state是私有的,可以认为state是组件的“私有属性(或者是局部属性)”。
- 如何判断是否为State ?
组件中用到的一个变量是不是应该作为组件State,可以通过下面的4条依据进行判断:
- 这个变量是否是通过Props从父组件中获取?如果是,那么它不是一个状态。
- 这个变量是否在组件的整个生命周期中都保持不变?如果是,那么它不是一个状态。
- 这个变量是否可以通过其他状态(State)或者属性(Props)计算得到?如果是,那么它不是一个状态。
- 这个变量是否在组件的render方法中使用?如果不是,那么它不是一个状态。这种情况下,这个变量更适合定义为组件的一个普通属性,例如组件中用到的定时器,就应该直接定义为this.timer,而不是this.state.timer。
- 将函数组件转换成 class 组件
通过以下五步将 Clock 的函数组件转成 class 组件:
- 创建一个同名的 ES6 class,并且继承于 React.Component。
- 添加一个空的 render() 方法。
- 将函数体移动到 render() 方法之中。
- 在 render() 方法中使用 this.props 替换 props。
- 删除剩余的空函数声明。
- 向 class 组件中添加局部的 state
(具体参考react官网教程时钟例子:https://react.docschina.org/docs/state-and-lifecycle.html)
- 关于setstate():
- 不要直接修改 State,而是应该使用 setState(),构造函数是唯一可以给 this.state 赋值的地方。
- State 的更新可能是异步的,出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态
- State 的更新会被合并,当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state。
- State与Props的区别:
props 是组件对外的接口,state 是组件对内的接口。
组件内可以引用其他组件,组件之间的引用形成了一个树状结构(组件树),如果下层组件需要使用上层组件的数据或方法,上层组件就可以通过下层组件的props属性进行传递,因此props是组件对外的接口。组件除了使用上层组件传递的数据外,自身也可能需要维护管理数据,这就是组件对内的接口state。根据对外接口props 和对内接口state,组件计算出对应界面的UI。
主要区别:
- State是可变的,是一组用于反映组件UI变化的状态集合;
- 而Props对于使用它的组件来说,是只读的,要想修改Props,只能通过该组件的父组件修改。在组件状态上移的场景中,父组件正是通过子组件的Props, 传递给子组件其所需要的状态。
- 事件处理
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
- 在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault。
- 使用 React 时,你一般不需要使用 addEventListener 为已创建的 DOM 元素添加监听器。React恰恰与之相反,你仅需要在该元素初始渲染的时候添加一个监听器。
- 必须谨慎对待 JSX 回调函数中的 this,在 JavaScript 中,class 的方法默认不会绑定 this。如果你忘记绑定 this.handleClick 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined。
这并不是 React 特有的行为;这其实与 JavaScript 函数工作原理有关。通常情况下,如果你没有在方法后面添加 (),例如 onClick={this.handleClick},你应该为这个方法绑定 this。
- 条件渲染
- React 中的条件渲染和 JavaScript 中的一样,使用 JavaScript 运算符 if 或者条件运算符去创建元素来表现当前的状态,然后让 React 根据它们来更新 UI。
- 元素变量:你可以使用变量来储存元素。 它可以帮助你有条件地渲染组件的一部分,而其他的渲染部分并不会因此而改变。
- 与运算符 &&:通过花括号包裹代码,你可以在 JSX 中嵌入任何表达式。这也包括 JavaScript 中的逻辑与 (&&) 运算符。它可以很方便地进行元素的条件渲染。
之所以能这样做,是因为在 JavaScript 中,true && expression 总是会返回 expression, 而 false && expression 总是会返回 false。
因此,如果条件是 true,&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。
- 三目运算符:另一种内联条件渲染的方法是使用 JavaScript 中的三目运算符
condition ? true : false
- 阻止组件渲染:在极少数情况下,你可能希望能隐藏组件,即使它已经被其他组件渲染。若要完成此操作,你可以让 render 方法直接返回 null,而不进行任何渲染。在组件的 render 方法中返回 null 并不会影响组件的生命周期。
- 列表&Key
- Key:当你创建一个元素时,必须包括一个特殊的 key 属性。key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据 id 来作为元素的 key。当元素没有确定 id 的时候,万不得已你可以使用元素索引 index 作为 key。
<li key={index}>
{todo.text}
</li>
如果列表项目的顺序可能会变化,我们不建议使用索引来用作 key 值,因为这样做会导致性能变差,还可能引起组件状态的问题。如果你选择不指定显式的 key 值,那么 React 将默认使用索引用作为列表项目的 key 值。
- 用key提取组件:
元素的 key 只有放在就近的数组上下文中才有意义。
比方说,如果你提取 出一个 ListItem 组件,你应该把 key 保留在数组中的这个 <ListItem /> 元素上,而不是放在 ListItem 组件中的 <li> 元素上。
- 受控组件:
在 HTML 中,表单元素(如<input>、 <textarea> 和 <select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。
我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
- 状态提升
- 通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
- 在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升”。
- 小结:在 React 应用中,任何可变数据应当只有一个相对应的唯一“数据源”。通常,state 都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个 state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。
- 好处:虽然提升 state 方式比双向绑定方式需要编写更多的“样板”代码,但带来的好处是,排查和隔离 bug 所需的工作量将会变少。由于“存在”于组件中的任何 state,仅有组件自己能够修改它,因此 bug 的排查范围被大大缩减了。此外,你也可以使用自定义逻辑来拒绝或转换用户的输入。
- 组合VS继承
- React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。
- Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。注意:组件可以接受任意 props,包括基本数据类型,React 元素以及函数。
- 如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们。
- React哲学
- 第一步:将设计好的 UI 划分为组件层级
- 第二步:用 React 创建一个静态版本
- 第三步:确定 UI state 的最小(且完整)表示
- 第四步:确定 state 放置的位置
- 第五步:添加反向数据流
- 关于React高、低版本的整理
React在2013年5月份开源以来,版本就一直在更新。13-17年主要是低版的(15版),17年9月份出的高版(16版),两个版本之间差别还是蛮大的,改动的小细节也不少,本文就这些改动做一个整理。
- 先说高版
1.引入的基本文件
- react.production.min.js
- react-dom.production.min.js
- browser.min.js
2.定义组件的方式
用class Demo extends React.Component{}来定义组件
3.属性之间的传值用法
能使用组件defaultProps构造器传值,在组件构造和组件渲染之间用。
4.状态state方法
在constructor中通过this.state={}来设置初始状态,在事件中调用this.setState()需要在构造器中通过bind绑定this,this指向不一样。
5.生命周期函数
其生命周期整体流程钩子函数只有三个:componentWillMount(){}、render、componentDidMount(){}
注:getDefaultProps、getInitialState只在低版中有效,在高版本无效
6.新增
新增了componentDidCatch这个生命周期函数,它可以捕获自身及子树上的错误并对错误做优雅处理,包括上报错误日志、展示出错提示,而不是卸载整个组件树,使用Error Boundary处理错误组件。但是,15版本,一旦某个组件发生错误,整个组件树将会从根节点被unmount下来。
Render方法新增了返回类型,16版本render方法支持直接返回string,number,boolean,null,portal,以及fragments(带有key属性的数组),这可以在一定程度上减少页面的DOM层级。
setState传入null时不会再触发更新等等。
再说低版
1.引入的基本文件
- react.min.js
- react-dom.min.js
- browser.min.js;
2.定义组件的方式
react是通过var Demo = React.createClass{}来定义组件的;
3.属性之间的传值用法
可以使用钩子函数getDefaultProps实现参数的传递,高版本不存在此函数;
4.状态state方法
用getInitialState()来定义初始状态,用this.setState()更新组件的状态;
5.生命周期函数
生命周期整体流程钩子函数总体有五个:getDefaultProps、getInitialState、componentWillMount(){}、render、componentDidMount(){}
注:定义组件的方式,高版本创建语法能在低版本中写,但是低版本创建语法不能在高版本中写,因为高版本废弃createClass(),但是react是用原生JS开发的,所以低版里面是可以用ES6的语法来定义组件的。