React入门基础总结

8 篇文章 0 订阅

学一门框架,首先要熟悉官方文档,不然框架总会学得有所欠缺。尤其当使用过React一段时候后,对此深有体会。于是便依据官方文档做了以下的学习笔记。建议大家也去官方文档学习,毕竟每个人对文档的理解都有所不同。

一、简介

JSX是什么

JSX是一个JavaScript的语法扩展,可以很好地呈现页面的交互形式,而且还具有JavaScript的全部功能。 使用JSX可以生成React元素。 浏览器默认是不支持JSX的,所以jsx语法必须使用@babel/preset-react进行编译,编译的结果React.createElement()这种Api的代码

为什么使用JSX

使用JSX能给人在视觉上带来辅助作用,还可以让React显示更多的信息,以便于进行页面的开发。

JSX的使用

我们可以在JSX中使用任何有效的JavaScript表达式。
JSX的表达式在经过编译后会被转换为普通的JavaScript函数

JSX的特定属性

JSX中的DOM建议使用 驼峰式 的命名规则来定义属性的名称,例如:

 class => className
   tabindex => tabIndex

在JSX中可以通过使用引号来指定字符串的字面量,例如:

    const element = <div tabIndex="0"></div>;

还可以使用大括号插入一个JavaScript的表达式

const element = <img src={user.avatarUrl}></img>;

注意不要在大括号外面加上引号,对于同一个属性不能同时使用这两个符号。 当一个dom便签中不需要内容时,我们可以使用单闭合标签。 JSX可以防止 XSS注入攻击,其原理是在J会在ReactDom渲染之前进行转义为字符串。

JSX表示对象

JSX会被Babel转义为React.createElement()函数调用

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

可以写成

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

代码会通过React.createElement()预先执行一些检查,以便不会出现错误。

二、React组件、元素渲染与Props

1、什么是props?

定义:props是父子组件之间通信的纽带,它表示的是父组件传递过来的自定义属性和children。

props是一个对象,通过props可以访问到父组件传递过来的自定义属性和children。

props是只读的(不能修改它)

通过props,可以向子组件传递ReactNode(ReactElement、基本数据类型、数组、JSX对象)、普通对象、函数等。

2.ReactDOM元素的渲染

ReactDOM元素负责更新DOM使其与React元素保持一致。 将一个React元素渲染到根DOM节点,使用的是ReactDOM.render()方法,将需要渲染的元素传入即可。

React元素是不可变对象,一旦被创建后就不可以被修改。 因此,当我们需要更新页面是需要重新调用ReactDOM.render()方法,对之前状态与新状态进行合并比较生成出最小差异树最后改变DOM。即:React只更新它需要更新的部分

DOM inspector showing granular updates

3.React两种组件的写法

什么组件?组件就是一个段可以被复用的代码块。组件化的意义:封装、快速开发。

函数组件(无状态组件)

特点:它只有props,没有state状态,也没有this、生命周期、ref、上下文等特性。所以它的性能较好。

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

class组件(有状态组件)

特点:它有props,也有state状态、this、生命周期、ref、上下文等特性。相对于函数式组件其性能较差。

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

注意:组件名称必须为大写字母开头 React会将小写字母开头的标签视为原生DOM便签。 所有React组件都必须保护它们的props不被更改。 但是,可以使用state对数据进行操作。

React v16.8 以后,现在市场中主流是Hooks+函数式组件

三、State & 生命周期

简单来说就是组件从生到死的过程。

挂载阶段【3】constructor / render / componentDidMount

更新阶段【2】render / componentDidUpdate

卸载阶段【1】componentWillUnmount

constructor()

构造器函数,它的入参是props(由父组件传递过来的自定义属性和children)

第一行代码必须是 super(props),调用父类的构造器函数

组件自有的state只能在这里定义(先定义后使用),state就是所谓的声明式变量

在这里不能修改props,在这里也不能用props来做运算。

在这里不要把props和state交叉赋值(运行),在React代码逻辑,永远要保持props和state的独立性。

在这里不要使用this.setState()修改state。

一般情况下,不要在这里写业务逻辑,比如DOM、BOM操作等都不要在这里做。

但,有时候我们需要改变this指向时,可以这里做。

componentDidMount()

 相当于vue中mounted(),表示挂载阶段已完成。

 各种业务逻辑(DOM操作、ref操作、调接口、开定时器)等都可以在这个做。

 在这里可以this.setState(),默认还是异步的。

componentDidUpdate()

  相当于vue中的updated(),表示更新阶段已完成。

  在当前组件中,有三种方式触发更新阶段:props变化、this.setState()、this.forceUpdate()

  使用场景:this.setState()这个异步工作完成时,我们去做另一件非render的事件。

  在这里可以使用this.setState(),但必须给终止条件。(你可以想一想递归)

  这个生命周期,是更新阶段的,发生在render()之后。

componentWillUnmount()

 相当于vue中beforeDestroy(),表示当前组件即将被销毁。

 在这里一般用于清除定时器、长连接、清缓存等。

 在这里可以调用this.setState(),但毫无意义。

shouldComponentUpdate()   // 该知识点常用出现在面试期间

这个生命周期相当于一个用于控制更新的“开关”

this.forceUpdate()它会绕过这个生命周期。shouldComponentUpdate对this.forceUpdate()不影响。

适用于要考虑props和state两重数据流对视图渲染的影响的优化,但这个优化方案异常复杂,所以实践工作中几乎没人用。React官方提供了一个 PureComponent 构造类,彻底地解决上述这个难以解决的优化问题。

render() //DOM渲染

 这个生命周期,是React所有生命周期中必须要有的。

  这个生命周期横跨两个阶段,在挂载阶段和更新阶段都执行。

  组件初始化、this.setState时、this.forceUpdate时、props变化时,它会执行。

  在更新阶段,如果当前有shouldComponentUpdate并返回false时,render()将不执行。

  在挂载阶段,render()一定会执行,shouldComponentUpdate不影响render()。

  特别提醒:

    1、在“自定义渲染方法”中不能使用this.setState()。

    2、在render()内部、return()之间,不能使用到this.setState()。

    3、在JSX中不能调用this.setState()方法。

  render() 方法一定要返回 ReactNode,不能返回void。

注意事项:

1、不要直接修改State,因为这样不会让组件被重新渲染,而要在函数方法中调用setState()方法。

2、State的更新可能是异步的,React会把多个setState()方法调用合并成为一个调用

例如:this.setState({num:1,age:1});
this.setState({age:2});
//会被合并成为
this.setState({num:1,age:2});
//最后进行DOM渲染

3、不要直接操作state中的值,例如:++this.stete.num这样虽然会更新页面,但是不建议这么做。我们可以使用this.stete.num+1更新数据。

4、State的更新会被合并,this.setState()方法会将state中的数据进行浅合并,即会将state中的数据进行替换。

this.state = {
  a: {
    aa:1,
    ab:2
  }
};
//对上述state进行如下的更新操作
this.setState({a:{aa:123}})
//state的数据会变为如下数据
this.state = {
  a: {
    aa:123
  }
};

因此,我们需要先将复杂的数据进行展开,然后对要处理的值进行改变.

this.state = {
  a: {
    aa:1,
    ab:2
  }
};
//对上述state进行如下的更新操作
this.setState({a:{...a,aa:123}})
//state的数据会变为如下数据
this.state = {
  a: {
    aa:123,
    ab:2
  }
};

5、this.setState()方法的异同步情况

  • 合成事件(on*开头的系列事件、生命周期钩子)中,this.setState()是异步的。
  • 微任务函数体中(Promise.then)中,this.setState()是同步的。
  •  在非合成事件中(定时器、DOM事件)中,this.setState()是同步的。

数据是向下流动的(单向数据流) state中的数据除了拥有并设置了他的组件外,其他组件都无法访问。 即从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。

 四、事件处理

React 事件的命名采用小驼峰式(camelCase),而不是纯小写。例如:onclick ==> onClick

使用 React 时,你一般不需要使用 addEventListener 为已创建的 DOM 元素添加监听器。事实上,你只需要在该元素初始渲染的时候添加监听器即可。

1、如何绑定事件?

  语法一:使用ES5的方式来绑定事件 onClick={this.handle.bind(this)}

        事件处理器的最后一个参数永远都事件对象。

  语法二:使用ES6的方式来绑定事件 onClick={()=>this.handle()}

        需要手动传递事件对象。

  建议:使用“语法二”来绑定事件。

注意:必须谨慎对待 JSX 回调函数中的 thisclass 的方法默认不会绑定this。如果你忘记绑定 this.handleClick 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined

 handleClick(){    
    console.log('this is:', this);  //“this is: undefined”
} 
  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }

五、条件渲染

React中条件渲染主要以下几种方案

条件渲染:元素的显示与隐藏,这里巧用的都是JSX语法。

1、单一元素的条件渲染

  通过花括号包裹代码,然后使用逻辑与 (&&) 运算符进行短路操作

  语法:{ bol && <jsx> }

2、两个元素的条件渲染

三目运算符

  语法: { bol ? <jsx1> : <jsx2> }

3、多个元素的条件渲染

  语法:建议封装“自定义的渲染函数”  function renderThing() { return <jsx> }

4、动态class

  语法:className={'类名的拼接'}

5、动态style

  语法:style={ css样式的键值值 }

6、阻止组件的渲染

 render 方法直接返回 null,组件可以不进行任何渲染。

例如:官方的示例

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    <div className="warning">
      Warning!
    </div>
  );
}

class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = {showWarning: true};
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }

  handleToggleClick() {
    this.setState(state => ({
      showWarning: !state.showWarning
    }));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? 'Hide' : 'Show'}
        </button>
      </div>
    );
  }
}
ReactDOM.render(
  <Page />,
  document.getElementById('root')
);

 在组件的 render 方法中返回 null 并不会影响组件的生命周期

六、列表 & Key

1.列表渲染:

React官方建议使用map()进行渲染。因为map数组方法在React中能对源数据进行处理,返回一个新的jsx数组。

在使用map生成一个jsx列表元素时,我们需要对其分配一个唯一的 key 属性,以确保当列表能正确的进行更新操作。

当map嵌套过多时,我们可以对其进行封装提取成为一个组件。

2.注意:

key 只是在兄弟节点之间必须唯一,在不同组件之间可以有相同的key。key 会传递信息给 React ,但不会传递给你的组件,因此,我们无法通过props读取到key,我们可以使用其他的属性对key进行传值。

七、表单

在React中使用表单控件时,建议使用受控表单组件,即:表单/类表单的value或checked由state控制着,其value数据通常保存在组件的 state 属性中,并且只能通过使用setState()来更新。

例如:

<input type='text' value={this.state.a} onChange={(e) => this.setState({ a: e.target.value })}></input>

存在多个受控组件时,我们可以使用给每个组件设置一个name值,然后通过event.target.name的值进行对应的操作。

原则:除了文件上传以外,都要使用受控表单。

八、状态提升

当两个组件之间需要共享一个状态(数据)时,我们的做法是把这个状态(变量)定义它们共同的最近的一个父组件中。依靠自上而下的数据流,而不是尝试在不同组件间同步 state。

对于状态提升,我们一般都是使用“受控组件”来进行操作。

例如:

import React, { PureComponent } from 'react'

const Aitem = props => {
    const { value, onValue } = props
    return (
        <div>
            <span>A</span>
            <input
                type="text"
                value={value}
                onChange={ev => onValue(Number(ev.target.value))}
            />
        </div>
    )
}

const Bitem = props => {
    const { value, onValue } = props
    return (
        <div>
            <span>B</span>
            <input
                type="text"
                value={value*2}
                onChange={ev => onValue(Number(ev.target.value)/2)}
            />
        </div>
    )
}
export default class Class extends PureComponent {
    constructor(props) {
        super(props)
        this.state = {
            a:1
        }
    }
    render() {
        const {a} = this.state
        return (
            <>
                <Aitem value={a} onValue={a=>this.setState({a})} />
                <Bitem value={a} onValue={a=>this.setState({a})} />
            </>
        )
    }
}

九、组合&继承

React 有十分强大的组合模式。React推荐使用组合非继承来实现组件间的代码重用

React有一个特殊的children,可以将他们的子组件传递到渲染结果中。这与vue的slot插件十分类似。如果理解了vue的插槽,那么React的props.children也能够理解清楚。

例如:

import React, { PureComponent } from "react";

const Comp = (props) => {
    return (
        <div>
            {props.children}
        </div>
    )
}
export default class Composition extends PureComponent {
    render() {
        return (
            <>
                <div>Composition</div>
                <Comp>
                    <div>这是children1</div>
                    <div>这是children2</div>
                </Comp>
            </>
        )
    }
}

既然 React的props.children与vue的v-slot:default相似。

那么React是不是也有特定的“插槽”呢?

答案是肯定的,毕竟Vue借鉴的React。

React使用使用对应的prop进行渲染,因为我们可以将任何东西作为 props 进行传递。

import React, { PureComponent } from "react";

const Comp = (props) => {
    return (
        <div>
            <div style={{float:"left"}}>{props.left}</div>
            <div style={{float:"right"}}>{props.right}</div>
        </div>
    )
}
export default class Composition extends PureComponent {
    render() {
        return (
            <>
                <div>Composition</div>
                <Comp
                    left={
                        <div>这是left</div>
                    }
                    right={
                        <div>这是right</div>
                    }
                />
            </>
        )
    }
}

对于组件的继承,React官方给出的建议是:如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们。

如果用组件使用继承的话我们可能会看到这样的代码出现

class Modal extends PureComponent {}
class DefaultHeaderModel extends Modal {}
class MiniHeaderModal extends Modal {}
class DefaultFooterDefaultHeaderModal extends DefaultHeaderModel {}
class CustomFooterMiniHeaderModal extends MiniHeaderModal {}

......
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值