react学习笔记

xiaoxiao2021-02-28  103

JSX

是js的一种语法扩展,在React中用于描述UI。

在JSX中使用{}嵌入任何js表达式多行JSX最好使用括号wrap编译后,JSX表达式成为常规的JavaScript对象。因此可以在if或者for循环中使用,或者赋值给其他的变量、从函数中返回等等。由于JSX比起HTML更接近JavaScript,所以React DOM使用驼峰命名法为属性命名而不是使用HTML属性名称。 比如,class在JSX中变为className。

JSX可以阻止注入攻击。 在jSX中包含用户输入是安全的,因为默认情况下ReactDOM在渲染JSX之前会将JSX中嵌入的值进行转义,有助于防御XSS攻击。

Babel将JSX编译成对React.createElement()的调用,最终会生成一个描述元素属性的object。这个object就是React元素,React会读取这些object并最终构建为DOM。

渲染

与DOM元素不同,React元素就是纯Object,因此创建它的代价是很低的。 React DOM负责根据React元素来更新DOM。

ReactDOM.render(element,document.getElementById('root'))

组件

最简单的定义组件的方法就是定义一个函数:

接受props为参数返回一个JSX

也可以使用class来定义一个组件

继承React.Component render()用于返回JSXconstructor() 由于是继承了component基类,必须调用基类的constructor,并传入props:super(props)初始化state组件名称首字母大写组件必须只返回一个根元素,一般用一个div来对内部元素进行包裹函数式组件或者组件的render方法返回null,则此组件不会被渲染

props

父组件传递给子组件的数据。

组件永远不能修改props,是只读的。

state

setState 方法由父类 Component 所提供。当我们调用这个函数的时候,React.js 会更新组件的状态 state ,并且重新调用 render 方法,然后再把 render 方法所渲染的最新的内容显示到页面上。

setState异步性

当你调用 setState 的时候,React.js 并不会马上修改 state。而是把这个对象放到一个更新队列里面,稍后才会从队列当中把新的状态提取出来合并到 state 当中,然后再触发组件更新。

由于这种异步性,你不能依赖它们的值去计算下一个状态的state。 如:this.setState({ count: this.state.count + 1})

这里就要用上setState 的第二种使用方式,可以接受一个函数作为参数。React.js 会把上一个 setState 的结果传入这个函数,你就可以使用该结果进行运算、操作,然后返回一个对象作为更新 state 的对象:

this.setState((prevState) => { return { count: prevState.count + 1 } })

自上而下

state只被组件自己拥有,要想传递给其他的组件(子组件),就要使用props向下传递。

一个组件不知道其他组件是有状态的还是无状态的。组件间只是通过props来传递数据。

state与props区别

props是父组件传递进来的数据,是只读的state是组件自己维护的状态,是可变的

共同点:

二者的变化都会触发组件的重新渲染

处理事件

与DOM中处理事件类似,但也有一些区别:

React事件名使用驼峰命名法,而不是DOM中的小写形式在JSX中为事件属性传入一个函数,而不是一个字符串。 <button onClick={activateLasers}> Activate Lasers </button> 不能通过返回false来取消默认行为,必须在事件处理函数中显式调用preventDefault。当使用class来定义组件的时候,一个常用的模式就是定义class的方法来处理事件: class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; // This binding is necessary to make `this` work in the callback this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } 在元素中使用为click事件定义处理函数:onClick={this.handleClick},即class中的handleClick方法在constructor的初始化工作中要注意为事件处理函数绑定this。在js中,class中的方法并不默认绑定this,因此要自己强制绑定,以保证在click发生时handleClick内this指向的是当前组件

也可以使用箭头函数来达到同样的目的:

class LoggingButton extends React.Component { // This syntax ensures `this` is bound within handleClick. handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } }

列表

一般使用map()函数来遍历一个数组并生成对应的React元素: const listItems = numbers.map((number) => <li>{number}</li> );

可以使用{}包含一个元素列表:

ReactDOM.render( <ul>{listItems}</ul>, document.getElementById('root') );

key属性

最好为每一个列表中的元素分配一个key属性。 key属性帮助React识别哪些项被修改了,被添加了或者被移除了。

不要求key属性在全局唯一,只要在兄弟元素中唯一key属性对于React来说是一个重要信息,但是不会传递给你的组件。如果在组件中你需要同一个值,需要自己使用另一个prop属性去传递。

虚拟DOM

在React中,组件render方法得到的结果并不是真正的DOM节点,而是纯粹的js对象,用于描述DOM节点。我们称之为virtual DOM。

React之所以比直接操作DOM的JS库快,原因就是在渲染时,React 会把组件当前的虚拟DOM结构和前一次的虚拟DOM结构做比较,只有存在差异性,React才会把差异的内容同步到实体DOM上。

React速度快的原因,还有一个是它出色的Diff算法。标准的比较两棵树的Diff算法的时间复杂是 O(n3) 。而React基于非常符合实际场景的几个策略,就将Diff算法的时间复杂度降到了接近O(n)。这几个策略是:

DOM 节点跨层级的移动操作特别少,可以忽略不计,因此对两棵树的比较分层进行,只会对同一层次的节点进行比较。 如果发现层内的一个节点已经不存在,则该节点及其子节点会被完全删除掉,不会用于进一步的比较。 如果两个组件或元素类型不同,那么他们就是完全不同的树,不需要再比较他们的子节点。 比如, 如果有个 <Header> 被 <ExampleBlock> 替换掉了,React 会删除掉 Header再创建一个 ExampleBlock.对同一层级的节点,diff算法提供了插入、移动和删除三种节点操作。 可以为组件或元素设置key属性,key用来标识这个组件或元素。一般多用于列表中。列表中key属性的存在,可以让React正确识别新增、修改和删除,从而做出最优的修改。

refs

ref属性用于获取组件的引用。 这里子组件必须是一个React component的实例或者一个DOM元素。

ref的应用场景一般是想要直接调用一个组件实例的方法,而不是通过传递新的props来使组件重新渲染. 一个典型的例子就是使某个input元素获得焦点:

class AutoFocusTextInput extends React.Component { componentDidMount() { this.textInput.focus(); } render () { return ( <input ref={(input) => this.textInput= input} /> ) } }

可以看到我们给 input 元素加了一个 ref 属性,这个属性值是一个函数。当 input 元素在页面上挂载完成以后,React.js 就会调用这个函数,并且把这个挂载以后的 DOM 节点传给这个函数。在函数中我们把这个 DOM 元素设置为组件实例的一个属性,这样以后我们就可以通过 this.input 获取到这个 DOM 元素。

不能在函数式组件中使用refs,因为它们没有实例 但是可以在函数式组件内部的DOM元素或者class组件上可以使用。

props.children

我们可以在组件标签中编写内嵌的结构,就像普通的html标签一样:

<Card> <h2>React.js 小书</h2> <div>开源、免费、专业、简单</div> 订阅:<input /> </Card>

这样我们希望组件Card只是一个包含型的组件,其中的内容是随意的。

在Card组件中我们可以通过props.children获得嵌套在组件内部的JSX结构:

class Card extends Component { render () { return ( <div className='card'> <div className='card-content'> {this.props.children} </div> </div> ) } }

dangerouslySetHTML

根据之前的知识,我们知道在 React.js 当中所有的表达式插入的内容都会被自动转义。但有时我们想不通过转义,直接将传入的内容当做html结构显示在页面中,这时就需要dangerouslySetHTML属性,让我们可以动态设置元素的innerHTML。

render () { return ( <div className='editor-wrapper' dangerouslySetInnerHTML={{__html: this.state.content}} /> ) }

style

React.js 中的元素的 style 属性的用法和 DOM 里面的 style 不大一样。 在React中需要把CSS属性变为一个对象再传给元素:

<h1 style={{fontSize: '12px', color: 'red'}}>React.js 小书</h1>

style 接受一个对象,这个对象里面是这个元素的 CSS 属性键值对,原来 CSS 属性中带 - 的元素都必须要去掉 - 换成驼峰命名,如fontSize、textAlign。

我们可以利用这种方式使用props或者state动态设置元素的样式。

PropTypes

React.js 就提供了一种机制,让你可以给组件的props加上类型验证,这样就能防止传入错误的数据类型导致出错。

PropTypes是一个第三方库,需要单独安装和引入。

class Comment extends Component { static propTypes = { comment: PropTypes.object } render () { const { comment } = this.props return ( <div className='comment'> <div className='comment-user'> <span>{comment.username} </span>: </div> <p>{comment.content}</p> </div> ) } }

并且给 Comment 组件类添加了类属性 propTypes,并规定了comment类型必须为object。此时再传入不是object的值会报错。

通过isRequired也可以要求某一个参数必须传入:

static propTypes = { comment: PropTypes.object.isRequired }

PropTypes 提供了一系列的数据类型可以用来配置组件的参数:

PropTypes.array PropTypes.bool PropTypes.func PropTypes.number PropTypes.object PropTypes.string PropTypes.node PropTypes.element

Element、Component与instance

Element:是一个纯粹的对象,用于描述一个DOM元素。 JSX用于描述Element,而Babel会将其转化为调用React.createElement的方式,最终结果就是生成一个Element。

Component:是一个接受参数并返回Element的函数或者类。

instance:当你调用ReactDOM.render()把一个组件渲染到一个具体的DOM元素中时,返回的值即使一个实例

生命周期

初始化阶段

getDefaultProps与getInitialState

当我们拥有ES6运行环境时,可以通过class语法定义组件。 但是without ES6的时候,就需要通过createReactClass()函数来创建一个组件类。在这个函数中要使用getDefaultProps与getInitialState 来定义props与state的初始值。

var Counter = React.createClass({ getDefaultProps: function() { return { title: 'Basic counter!!!' } }, getInitialState: function() { return { count: 0 } }, render:function(){ …… }, propTypes: { title: React.PropTypes.string } });

挂载阶段

我们把 React.js 将组件渲染,并且构造 DOM 元素然后塞入页面的过程称为组件的挂载。

componentWillMount与componentDidMount

在挂载前后我们可以有机会做一些处理:

-> constructor() -> componentWillMount() -> render() // 构造 DOM 元素插入页面 -> componentDidMount() React会在组件render之前调用componentWillMount,在这个阶段调用this.setState()方法将不会触发重复渲染。React会在组件被渲染成DOM元素插入页面后调用componentDidMount,此时对应的DOM元素已经生成,这意味着这个方法是初始化其他需要访问DOM或操作数据的第三方库的最佳时机。

更新阶段

除了挂载阶段,还有一种“更新阶段”。说白了就是 state或者props更改导致 React.js 重新渲染组件并且把组件的变化应用到 DOM 元素上的过程,这是一个组件的变化过程。

当props更新时,这些生命周期函数会按以下顺序调用:

当state更新时,则会按以下顺序调用:

componentWillReceiveProps(nextProps)

组件从父组件接收到新的 props 之前调用。 在此方法内调用this.setState()将不会导致重复render。

shouldComponentUpdate(nextProps, nextState)

shouldComponentUpdate 允许我们手动地判断是否要进行组件更新,常作为优化React性能使用。 当shouldComponentUpdate返回false时,组件本次的render方法不会被触发。可以通过在这个方法中比较前后两次state或者props,根据实际业务场景决定是否需要触发render方法。

componentWillUpdate

组件重新渲染之前调用。 在这个函数内你不能调用setState改变组件状态。

componentDidUpdate

render()调用完毕,组件重新渲染完成,已经变更到真实的 DOM 以后调用。

卸载阶段

componentWillUnmount

同样在元素被从页面中删除的时候React也控制了这个组件的删除过程:

// 即将从页面中删除 -> componentWillUnmount() // 从页面中删除

在从页面中删除前会调用componentWillUnmount方法。 可以在这个阶段进行一些清理工作,如计数器的清理等等。

转载请注明原文地址: https://www.6miu.com/read-57304.html

最新回复(0)