JSX
-
1.为什么要使用jsx
- jsx可以很好地描述UI应该呈现出来它应有交互的本质形式。
- react并没有采用标记与逻辑进行分离到不同文件这种人为地分离方式,而是将二者共同存放在称之为组件的松散耦合单元之中,来实现关注点分离
-
2.在jsx语法中,可以在大括号中放任何有效的js表达式
-
3.函数的返回值和对象想值都是可以放在大括号中的
-
4.如果变量是undefined null 布尔值会把它忽略掉
-
5.如果变量是数组,jsx会把他们当做列表进行渲染。数组里面可以放任意东西
-
6.便于阅读可以将jsx才分为多行。但是要讲括号包起来,防止自动添加分号报错。
-
7.jsx表达式会被普通的javaScript函数调用,对它取值后得到一个普通的js对象
-
8.jsx特定属性
-
可以使用字符串
-
可以在后面使用大括号并将表达式放入,切记不能在大括号外加引号
-
const element =<div tabIndex="0"></div> const element =<div tabIndex={user.url}></div>
-
-
9.jsx里面react DOM 的属性要使用小驼峰的格式
-
10.jsx定义的标签如果没有内容可以使用单闭合标签
-
11.jsx可以放注入攻击
-
12.Jsx表示对象
- Babel会把JSX转译成为一个名为React.createElement()函数来调用
//两种代码完全相等
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
-
13.React.createElement()会预先执行一些检查,会帮你创建一个对象,这些对象就被成为React元素
-
14.浏览器不支持Jsx,所以jsx语法必须使用@babel/preset-react进行编译,
- 实例:
<div> Hello</div>===>@babel/preset-react===>React.createElement('div',{},'Hello')
-
15.JSX三个不一样的属性
- className(相当于html中的class)
- htmlFor(相当于html中for属性)
- tabIndex(相当于html中的tabindex)
-
16.Jsx语法新增三个属性
- key渲染一个列表时,或者渲染一个数组时,都要加key,为了让“diff”运算更高效
- ref 用于快速地访问DOM对象或者访问JSX实例对象
- dangerouslySetInnerHTML向JSX节点中插入一段可以参与渲染的HTML字符串
-
17.JSX注释{//}**
-
18.ReactElement,列如
<div/> <Modal/>
凡是被<>包起来的变量都叫做ReactElement -
19.ReactNode,也俗称React节点,包括ReactElement、undefuned\null.布尔值、string、函数调用
-
20.动态属性的值与声明式变量(state)有关系的
-
21.静态属性:一个属性的值与声明式变量无关
-
1.什么是元素
- 元素是构成React应用的最小砖块
-
2.React元素是创建开销极小的普通对象。React DOM会负责更新DOM来与React元素保持一致
-
3.如何将一个元素渲染成DOM
-
React只有一个根的DOM节点
-
如果想要将React元素渲染到DOM节点中,需要把他们传入ReactDOM.render()
const element = <h1>Hello, world</h1>; ReactDOM.render(element, document.getElementById('root'));
-
-
4.更新已经渲染的元素
- React是不可变对象。想要更新UI就得创建一个全新的元素传入ReactDom.render(),React进而对他两进行“协调运算”找出两者最小的差异,然后一次性提交更新DOM,
-
5.我们调用
ReactDOM.render()
函数,并传入<Welcome name="Sara" />
作为参数。 -
6.React 调用
Welcome
组件,并将{name: 'Sara'}
作为 props 传入。 -
7.
Welcome
组件将<h1>Hello, Sara</h1>
元素作为返回值。 -
8.React DOM 将 DOM 高效地更新为
<h1>Hello, Sara</h1>
。function Welcome(props){ return <h1>Hellp, {props.name}</h1> } const element=<Welcome name="Sara"/> ReactDOM.render( element , document.getElementById('root') )
组件&Props
组件,他接受任意的入参,并返回用于描述页面内容的JSX元素。React组件都是一个纯函数,入参不能修改但是能参与运算
-
4.函数组件
-
无状态组件
-
函数式组件没有state状态、也没有this、生命周期、ref上下文等特点。性能好
-
提示自React v16.8以后,我们可以通过过 Hooks API来模拟上述确实的React特性
-
函数组件接收一个唯一带有数据的"props"(代表属性),对象返回一个React元素。
function Welcome(props){ return <h1>Hello, {prop.name}</h1> }
-
-
2.类式组件
-
有状态组件
-
类式组件有state状态、this、生命周期、ref上下文等特性。相对于函数式组件性能较差。
-
提示:自React 16.8以后,类组件越来越少。现在市场中主流是Hools函数式组件
-
class Welcome extends React.component{ render(){ return <h1>hello,{this.props.name }</h1> } }
-
Props
-
props 是React基础中最重要的一个技术点
-
props是父组件之间通信的纽带,他表示的是父组件传递过来的自定义属性和children。props是一个对象,通过props可以访问到父组件传递过来的自定义属性和children。
-
props是只读的(不能修改它)
-
通过Propos可以向子组件传递ReactNode (ReactElement、基本数据类型、数组JSX对象)、普通对象、函数等。
-
组件无论是函数式声明还是类式声明都无法修改自身的props
父子组件
- 父组件通过props.children,我们给它定义是自定义组件内部嵌套的ReactNde列表
- 在自定义属性时,不要把属性名命名children
- 在props.children向子组件传递children时,建议传递ReactNode列表,保护药传递普通数据。如果要传递数据,建议使用自定义props
父子组件通信(数据)
- 父传子使用自定义属性
- 子传父通过自定义事件
- 父组件给的proos如果是“普通数据”用于渲染,用于逻辑操作
- 父组件如果给的是“函数”,在子组件
State&生命周期
- state是React组件自身的数据,具有响应式的特性(当state变量被this.setState()修改时,视图自动更新)
- state变量只能是一些基本类型、数组、普通对象。不能定义其他数据类型
正确的使用State
-
1**.不要直接修改 State,而是应该使用
setState()
,这会触发render()运行并返回新的"Fiber",进一步执行“协调运算”,一次性提交更新DOM,构造函数是唯一可以给this.state
赋值的地方:** -
2.State 的更新可能是异步的
-
出于性能考虑,React 可能会把多个
setState()
调用合并成一个调用。 -
因为
this.props
和this.state
可能会异步更新,所以你不要依赖他们的值来更新下一个状态。// Wrong this.setState({ counter: this.state.counter + this.props.increment, });
- 要解决这个问题,可以让
setState()
接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:
// Correct this.setState((state, props) => ({ counter: state.counter + props.increment })); //或者 // Correct this.setState(function(state, props) { return { counter: state.counter + props.increment }; });
- 要解决这个问题,可以让
-
-
State 的更新会被合并
- 当你调用
setState()
的时候,React 会把你提供的对象合并到当前的 state。
- 当你调用
-
this.setState()异步性
- 在合成事件(on*开头的事件、生命周期钩子)中,this.setState()是异步的
- 在宏任务函数体中,this.setState()是同步的
- 在微任务函数中(Promise.then)中,this.setState是同步的。
- 开发者在同一个合成事件中有可能多次调用this.setState()。如果它同步的,这会导致多次render()。为了避免产生性能损耗。所以React在此设计将其设置为浅合并
- this.setState(fn|{}, callback) 在callback被调用时说明异步任务完成了。
- componentDidUpdate()当这个生命周期触发了说明异步任务完成了
-
合成事件
- on事件处理器
- 生命周期钩子
- 合成事件是React官方专门封装一组Api,这些合成事件是“可控的”,React就可以放心的把事件合成事件中的this.seState()变成异步的,目的是为了对多个this.setState进行浅合并。
-
在非合成事件之中,this.setState是同步的。React无法操控“非合成事件中”,所以没有办法把this.setState()变成异步的,所以不存在性能优化
数据流是单向流动的
-
在组件中我们可以将父组件的state作为props传入到子组件中
-
<FormattedDate date={this.state.date} /> //FormattedDate 组件会在其 props 中接收参数 date,但是组件本身无法知道它是来自于 Clock 的 state,或是 Clock 的 props,还是手动输入的: function FormattedDate(props) { return <h2>It is {props.date.toLocaleTimeString()}.</h2>; }
-
任何的 state 总是所属于特定的组件,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。这通常会被叫做“自上而下”或是“单向”的数据流。
事件处理
-
React事件命名是小驼峰的形式
-
使用jsx语法时你需要传入一个函数作为事件处理函数,而不是一个字符串
-
<button onClick={activateLasers}> Activate Lasers </button>
-
-
阻止默认行为的方式必须是显示使用preventDefault
function ActionLink() { function handleClick(e) { e.preventDefault(); } return ( <a href="#" onClick={handleClick}> Click me </a> ); }
-
如何绑定事件
- 语法一:使用ES5的语法 onClick={this.handel.bind(this)}
- 语法二:使用箭头函数:onClick={()=>this.handel()}
-
如何拿到事件对象
- ES5方式绑定事件,事件处理器的最后一个参数就是事件对象
- ES6方式需要手动传递事件对象。:onClick={(e)=>this.handel(e)}
- 事件处理器如何自定义传递参数?
- ES5方式,onClick={this.handle.bind(参数,参数)}
- 在ES6中传递参数,onClick={(ev)=>this.handle(‘参数’,e)}
-
如何阻止事件冒泡,默认事件
-
如何监听键盘事件
- e.keyCode
条件渲染
-
单一元素的显示与影藏
- 语法:{bol&&}
-
两个元素的显示与影藏
-
语法: { bol ? jsx1 :jsx2}
-
多元素的条件渲染:通常命名以render开头
- 语法:建议封装 自定义渲染函数 function renderSomething(){
return }
- 语法:建议封装 自定义渲染函数 function renderSomething(){
-
动态class
- 语法:className={‘类名的拼接’}
-
动态style :style={ css样式的键值值 }
列表&Key
- 列表渲染官方建议使用map方法
表单
-
两类表单
- 受控表单,表单/类表单的value或checked由state控制着
- 非受控表单,表单/类表单的value或checked与state完全无关。
- 文件上传永远都是非受控表单,其他表单都必须是受控表单
- 对于普通文本表单、select表单,用value属性来受控,用onChange取值
- 对于radio/checkbox表单,用checked属性来受控,用onChange取值
- 对于自定义的“类表单”,我们建议用自定义属性value来受控,用自定义onChange取值
-
ref可以直接操作DOM this.refs.age.value
-
受控组件
- 渲染表单的React组件还控制着用户输入过程中表单发生的操作。被React以这种方式控制取值的表单输入元素就叫做“受控组件”
生命周期
-
生命周期
-
生命周期描述的是组件从生到死的过程
-
挂载阶段
- constructor
- constructor()构造器,它的入参是props(由父组件传递过来的自定义属性和children)
- 第一行代码必须是调用super(props),调用父类的构造器函数
- state只能在这里定义,state就是所谓的声明式变量
- 在这里不能修改props也不能使用props做运算。
- 在此处不要使用props和state交叉赋值(运算),
- 不要使用this,setState()修改state
- 一般不在此处写业务逻辑,比如DOM、BOM操作等都不要在这里做
- 有时候需要改变this可以在这里做
- render
- React所有的生命周期必须要有的
- 这个生命周期横跨两个阶段,在挂载阶段和更新阶段都执行、
- 组件初始化时,this.setstate()、this.forceUpdate时、props变化时,它会执行
- 如果当前有shouldComponentUpdate()并返回false时,render()将不执行
- 在挂载阶段render()一定会执行,shouldComponentUpdate()影响不了
- 特别提醒:在render()内部不能在“自定义渲染方法中”使用this.setState(),
- 在render()内部,return()之前不能使用this.setState()
- 在jsx中不能直接调用this.setState()
- componentDidMount
- 表示挂载阶段已完成
- 各种业务逻辑(DOM操作、ref操作、调接口,开定时器等都可以在这里做)
-
更新阶段
- render
- componentDidUpdate
- 表示更新状态已经完成
- 有三种方式触发更新阶段:props变化、this.setState()、this.forceUpdate()
- 使用场景:this.setState()这个异步工作完成时,我们去做另一件非render的事件。
- 在这里可以使用this.setState(),但必须给终止条件。
-
卸载阶段
- componentWillUnmount
- 表示组件即将被销毁
- 在这里一般用于清除定时器、长连接、清缓存等。
-
一个特殊的生命周期shouldComponentUpdate
- shouldComponentUpdate()这个生命周期相当于一个用于控制更新的“开关”,这个生命周期只会影响更新阶段,不会影响其他阶段。
- 注意:如果你用到了这个生命周期,无论逻辑对么复杂都得返回一个布尔值。
- 使用场景:举个例子,state中有10个声明式变量,但只有9个变量参与了视图渲染,还有1个变量与视图渲染没有任何关系。当有t使用this.setstate()来修改这个与视图渲染无关的变量时,染没有任何关系。这将也会触发render()返回新的JSx,白白浪费性能。所以这个生命周期是React给出的一种性能优化方案。
- 这个优化方案要考虑props和state两重数据流对视图渲染的影响,这个优化方案异常复杂,承以实践工作中几乎没人用。
- PureComponent组件
-
状态提升
- 状态提升:当两个组件之间需要共享一个状态时,我们的做法是把这个状态(变量)定义它们共同的最近的一个父组件
组合
- 意义:组合是React封装组件的基础思想。背后的语法基础: props children / render props。