文档管理中心

react基础知识总结

React 的特点

  1. 使用 JSX 语法 创建组件,实现组件化开发,为函数式的 UI 编程方式打开了大门

  2. 性能高的让人称赞:通过 diff 算法 和 虚拟 DOM 实现视图的高效更新

为什么要用 React

  1. 使用组件化开发方式,符合现代 Web 开发的趋势

  2. 技术成熟,社区完善,配件齐全,适用于大型 Web 项目(生态系统健全)

  3. 由 Facebook 专门的团队维护,技术支持可靠

  4. ReactNative - Learn once, write anywhere: Build mobile apps with React

  5. 使用方式简单,性能非常高,支持服务端渲染

  6. React 非常火,从技术角度,可以满足好奇心,提高技术水平;从职业角度,有利于求职和晋升,有利于参与潜力大的项目

创建组件的两种方式

  1. 通过 JS 函数 创建(无状态组件)

  2. 通过 class 创建(有状态组件)

JS 函数创建

  1. 函数名称必须为大写字母开头,React 通过这个特点来判断是不是一个组件

  2. 函数必须有返回值,返回值可以是:JSX 对象或 null

  3. 返回的 JSX,必须有一个根元素

  4. 组件的返回值使用()包裹,避免换行问题

class 创建

在 es6 中 class 仅仅是一个语法糖,不是真正的类,本质上还是构造函数+原型 实现继承

jsx 语法

jsx 语法是一种 JavaScript 语法扩展,在 React 中可以方便地用来描述 UI。比如下面就是一段 jsx 语法

上面的代码实质上等价于:

jsx 的书写规范

  • jsx 的顶层只能有一个根元素,所以我们很多时候会在外层包裹一个 div(或者使用 Fragment)

  • jsx 中的标签可以是单标签,也可以是双标签;如果是单标签,必须以/>结尾

  • jsx 的外层包裹一个小括号(),这样可以方便阅读,并且 jsx 可以进行换行书写

  • 在{}内部,可以写任何符合 JS 规范的代码;如果要写注释,注释必须放到 {} 内部

jsx 中嵌入表达式

在 jsx 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式,它可以是

  • 运算表达式

  • 三元运算符

  • 执行一个函数


class App extends React.Component {

  constructor(props) {

    super(props)

    this.state = {

      firstName: 'kobe',

      lastName: 'bryant',

      age: 20,

    }

  }


  sayHello(name) {

    return 'Hello ' + name

  }


  render() {

    return (

      <div> <h2>{this.state.firstName + ' ' + this.state.lastName}</h2> <h2>{this.state.age >= 18 ? '成年人' : '未成年人'}</h2> <h2>{this.sayHello('lzg')}</h2> </div>

    )

  }

}


jsx 条件渲染

1、两个组件二选一的渲染

2、一个组件有无的渲染

function MessageList(props) {

  const unreadMessages = props.unreadMessages

  return (

    <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2>You have {unreadMessages.length} unread messages.</h2>}

    </div>

  )

}


jsx 列表循环

在jsx语法中,循环渲染是利用数组的遍历 map() 方法返回一个集合。

遍历时必须有唯一索引 key 提高遍历的效率。一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串,万不得已可以使用 index。

class Admin extends Component {

  constructor(props) {

    super(props)

    this.state = {

      menus: [

        { icon: require('../imag/home/ic_noti_block@2x.png'), title: '菜单1' },

        { icon: require('../imag/home/ic_noti_block@2x.png'), title: '菜单2' },

        { icon: require('../imag/home/ic_noti_block@2x.png'), title: '菜单3' },

        { icon: require('../imag/home/ic_noti_block@2x.png'), title: '菜单4' },

      ],

    }

  }

  renderList(value, index) {

    return (

      <li key={index}> <p>张三</p> <p>18岁</p> </li>

    )

  }


  render() {

    return (

      <div> <ul>

          {[1, 2, 3, 4, 5].map((value, index) => {

            return this.renderList(value, index)

          })}

        </ul> <ul>

          {this.state.menus.map((value, index) => {

            return (

              <li key={index}>

                <img src={value.icon} width="30" />

                <div>{value.title}</div>

              </li>

            )

          })}

        </ul>

      </div> )

  }

}


接收数据 props

我们想要在组件之间进行传值,那么 props 属性就起到了这个作用。react 的每个组件都可以接受一个 props 参数,它是一个对象,包含了所有你对这个组件的配置。

特点

  • React 把传递给组件的属性转化为一个对象并交给 props

  • props 是只读的,无法给 props 添加或修改属性

组件状态 state

如果需要定义组件的自定义属性,需要在组件的 constructor 构造函数里面去定义 state

特点

  • 只有通过 class 创建的组件才具有 state

  • state 是私有的,完全由组件来控制

  • 不要在 state 中添加 render() 方法中不需要的数据,会影响渲染性能!

  • 不要在 render() 方法中调用 setState() 方法来修改 state 的值

state 和 props 的区别

props 是组件对外的接口,state 是组件对内的接口。两者主要的区别: state 是可变的,是组件内部维护的一组返回 ui 组件的集合,而 props 是组件的只读属性,组件内不能直接修改 props,只能在组件的上层修改。

创建 state

如果需要定义组件的自定义属性,在组件的 constructor 构造函数里面去定义 state

修改 state

不能直接去修改 state 的值,否则数据无法驱动关联,需要使用 setState,setState 方法接收一个参数,参数为一个对象,类似于小程序原生的 setData。

使用 this.setState()的第二种形式总是更安全的,因为更新的 props 和状态是异步的。这里,我们根据这些 props 更新状态。

另外,setState 还可以接收第二个参数,第二个参数为一个回调函数

为啥不能直接修改 state,要 setState 一下呢?setState 做的事情不仅仅只是修改了 this.state 的值,另外最重要的是它会触发 React 的更新机制,会进行 diff ,然后将 patch 部分更新到真实 dom 里。

事件绑定

1、 在调用的时候使用 bind 绑定 this


2、在构造函数中使用 bind 绑定 this

3、使用箭头函数绑定 this

4、public class fields 型

react 样式

  1. 直接写行内样式:

  1. 抽离为对象形式

  1. 使用样式表定义样式:

生命周期函数

组件的生命周期包含三个阶段:创建阶段(Mounting)、运行和交互阶段(Updating)、卸载阶段(Unmounting)

  1. Mounting 依次调用以下函数

    • constructor():ES6 类的构造函数(为了初始化 state 或绑定 this)

    • getInitialState():ES5 中初始化 state。

    • getDefaultProps():ES5 中初始化 props。在 ES6 中使用 defaultProps()方法。

    • componentWillMount():在组件被挂载前调用。只执行一次。

    • render():渲染组件,必须实现该方法。

    • componentDidMount():在组件装载后调用。这时已经生成了真实的 DOM 节点。只执行一次。

  2. Updating 依次调用以下函数

    • componentWillReceiveProps() 组件接受到新的 props 前触发这个方法

    • shouldComponentUpdate() 根据这个方法的返回值决定是否重新渲染组件,返回 true 重新渲染,否则不渲染

    • componentWillUpdate() 组件将要更新

    • render() 重新渲染组件,与 Mounting 阶段的 render 是同一个函数

    • componentDidUpdate() 组件已经被更新

  3. Unmounting

    • componentWillUnmount() 卸载组件;清除定时器,清除 dom

PropTypes

随着时间的推移,应用程序会变得越来越大,因此类型检查非常重要。PropTypes 为组件提供类型检查,并为其他开发人员提供很好的文档。如果 react 项目不使用 Typescript,建议为组件添加 PropTypes。


// 旧的写法

class PropTypeOne extends React.Component {

  render() {

    return (

      <div> <div>{this.props.name}</div> <div>{this.props.email}</div> </div>

    )

  }

}


PropTypeOne.propTypes = {

  name: PropTypes.string,

  email: function (props, propName, componentName) {

    if (!/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/.test(props[propName])) {

      return new Error('组件' + componentName + '里的属性' + propName + '不符合邮箱的格式')

    }

  },

}


// 新的写法

class PropTypeTwo extends React.Component {

  static propTypes = {

    name: PropTypes.string,

  }

  render() {

    return (

      <div> <div>{this.props.name}</div> </div>

    )

  }

}


当传入的 prop 值类型不正确时,JavaScript 控制台将会显示警告。出于性能方面的考虑,propTypes 仅在开发模式下进行检查。

您可以通过配置特定的 defaultProps 属性来定义 props 的默认值:

受控与非受控组件

受控组件

我们要经常使用表单来搜集用户输入,例如 <input> <select> <textearea> 等元素都要绑定一个 change 事件,当表单的状态发生变化,就会触发 onChange 事件,更新组件的 state。这种组件在 React 中被称为受控组件,在受控组件中,组件渲染出的状态与他的 value 或 checked 属性相对应,react 通过这种方式消除了组件的局部状态,使整个状态可控。react 官方同样推荐使用受控表单组件。

import React, { Component } from 'react'

export default class MyInput extends Component {

  handleContentChange = (e) => {

    this.setState({

      content: e.target.value,

    })

  }

  render() {

    return (

      <div> <input type="text" value={this.state.value} onChange={this.handleContentChange} />

      </div> )

  }

} 

受控组件更新 state 的流程:

  • 可以通过初始 state 中设置表单的默认值

  • 每当表单的值发生变化时,调用 onChange 事件处理器

  • 事件处理器通过事件对象 e 拿到改变后的状态,并更新组件的 state

  • 一旦通过 setState 方法更新 state,就会触发视图的重新渲染,完成表单组件的更新

react 中数据是单项流动的,从示例中,我们看出来表单的数据来源于组件的 state,并通过 props 传入,这也称为单向数据绑定。然后我们又通过 onChange 事件处理器将新的数据写回到 state,完成了双向数据绑定

非受控组件

如果一个表单组件没有 value props(单选和复选按钮对应的是 checked props)时,就可以称为非受控组件.在非受控组件中,我们可以使用一个 ref 来从 DOM 获得表单值。而不是为每个状态更新编写一个事件处理程序。

ref

React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。

字符串用法

通过 this.refs['inputRef']来访问

ref 作为回调函数

父组件的 ref 回调函数可以使用子组件的 DOM。

React.createRef()

在 React 16.3 版本后,使用此方法来创建 ref。将其赋值给一个变量,通过 ref 挂载在 dom 节点或组件上,该 ref 的 current 属性 将能拿到 dom 节点或组件的实例


react-router

react-router-dom 是应用程序中路由的库。 React 库中没有路由功能,需要单独安装 react-router-dom。

react-router-dom 提供两个路由器 BrowserRouter 和 HashRoauter。前者基于 url 的 pathname 段,后者基于 hash 段。

基本使用:


import { BrowserRouter, Route, Link, Redirect } from 'react-router-dom'


class MyRouter extends React.Component {

  render() {

    return (

      <BrowserRouter> <Link to="/">router1</Link> &nbsp;&nbsp; <Link to="/router2">router2</Link> &nbsp;&nbsp; <Link to="/router3">router3</Link> &nbsp;&nbsp; <hr /> <Redirect exact from="/" to="/router1" />

        <Route path="/router1" component={router1}></Route>

        <Route path="/router2" component={router2}></Route>

        <Route path="/router3" component={router3}></Route>

      </BrowserRouter> )

  }


路由跳转

1、用 Link 标签跳转

import { BrowserRouter, Route, Link, Redirect } from 'react-router-dom'


class MyRouter extends React.Component {

  render() {

    return (

      <BrowserRouter> <Link to="/">router1</Link> &nbsp;&nbsp; <Link to="/router2">router2</Link> &nbsp;&nbsp; <Link to="/router3">router3</Link> &nbsp;&nbsp; <hr /> <Redirect exact from="/" to="/router1" />

        <Route path="/router1" component={router1}></Route>

        <Route path="/router2" component={router2}></Route>

        <Route path="/router3" component={router3}></Route>

      </BrowserRouter> )

  }


2、编程式导航

  • 路由组件可以直接从 this.props.history 上拿到 history

  • 非路由组件无法直接拿到 history,需要配合 withRouter

  

路由传参

1.params

2.query

3.state

4.search

路由守卫

Route 组件可以接收一个 Component 组件,当 path 匹配上的时候,这个 Route 组件就会被渲染出来。我们还可以在路径匹配之后做一点事情,这一点类似于 Vue 中的路由守卫。

用到的还是 Route 这个组件,只不过这次组件不通过 Component 去传递数据,通过 render 属性。


withRouter

高阶组件中的 withRouter, 作用是将一个组件包裹进 Route 里面, 然后 react-router 的三个对象 history, location, match 就会被放进这个组件的 props 属性中。

默认情况下必须是经过路由匹配渲染的组件才存在 this.props,才拥有路由参数,才能使用编程式导航的写法,执行 this.props.history.push('/detail') 跳转到对应路由的页面,然而不是所有组件都直接与路由相连(通过路由跳转到此组件)的,当这些组件需要路由参数时,使用 withRouter 就可以给此组件传入路由参数,此时就可以使用 this.props。

import React,{Component} from 'react'

import {Switch,Route,NavLink,Redirect,withRouter} from 'react-router-dom' //引入withRouter

import One from './One'

import NotFound from './NotFound'

class App extends Component{

  //此时才能获取this.props,包含(history, match, location)三个对象

  console.log(this.props);  //输出{match: {…}, location: {…}, history: {…}, 等}

  render(){

    return (<div className='app'> <NavLink to='/one/users'>用户列表</NavLink> <NavLink to='/one/companies'>公司列表</NavLink> <Switch>

         <Route path='/one/:type?' component={One} />

         <Redirect from='/' to='/one' exact />

         <Route component={NotFound} />

      </Switch>

    </div>)

  }

}

export default withRouter(App);  //这里要执行一下WithRouter



作者:lzg9527

原链接:https://segmentfault.com/a/1190000024476820


点赞
收藏
回复
分享
举报
浏览273 发布于2020-10-02 01:30未知归属地
全部评论
最多点赞
最新发布
最早发布
暂无评论
暂无评论
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

了解社区公约,与您携手共创和谐专业的开发者社区。