前端react 基础学习一

1.react介绍

本质:React 是一个用于构建用户界面的 JAVASCRIPT 库。不是一个MVC框架,而是一个前端界面开发工具,用于构建组件化UI的库。所以顶多算是MVC中的V(view)。

特点:减少与DOM的交互。React可以与已知的库或框架很好地配合。 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。 React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。

主要能做什么:1.轻松地创建用户交互界面,声明式编写UI(声明式:声明式编程的计算在运行时构建完成,命令式编程的计算在编译时构建完成,声明式是一个很大的概念,详情可以百度),2.组件化构建页面3.可以用作开发原生应用的框架 React Native

核心:虚拟DOM,Diff算法

虚拟dom和高效的渲染:React将DOM抽象为虚拟DOM,虚拟DOM其实就是用一个对象来描述DOM,通过对比前后两个对象的差异,最终只把变化的部分重新渲染,提高渲染的效率

为什么用虚拟dom,当dom反生更改时需要遍历 而原生dom可遍历属性多大231个 且大部分与渲染无关 更新页面代价太大

为啥要学:react ,Angular,Vue三大框架我更倾向Vue,原因学过的基本都清楚,不过项目要用react也没办法。

2.react的基本使用

导入基本相关库,react.js 是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能,Browser.js 的作用是将 JSX 语法转为 JavaScript 语法,babel将es6转es5。

定义变量的方法:let和const,属于es6语法,两个都属于定义变量,const为ECMAScript带来了定义常量的能力,let用于块状作用域,类似局部变量

// 1. 导入 react
import React from \'react\'
import ReactDOM from \'react-dom\'

const element =<h1 title="Hello, world!">Hello, world!</h1>;
// 3. 渲染
//ReactDOM.render() 接受两个参数,第一个为 React 组件(虚拟dom对象),第二个为组件插入的容器,第三个 参数3:回调函数 ReactDOM.render(element, document.getElementById(\'app\'))

上述属于 JSX语法,最终会被编译为 createElement() 方法

const divVD = React.createElement(\'h1\', {
  title: \'hello,word!\'
}, \'Hello,world!\')

样式:

直接引入 <div 300px" }}>{text}</div>  但可能名字不一样,如marginTop  = margin-top
或者
import styles from \'../Derivative/DeritvativeList.less\';
<div className={styles.tableList}><div>

3.JSX

为了把 HTML 模板直接嵌入到 JS 代码里面,这样就做到了模板和组件关联,但是 JS 不支持这种包含 HTML 的语法,所以需要通过工具将 JSX 编译输出成 JS 代码才能使用.

与html差异(特点):

1:如果在 JSX 中给元素添加类, 需要使用 className 代替 class ,label 的 for属性,使用htmlFor代替

2:直接使用 JS代码,直接在 JSX 中通过 {} 中间写 JS代码即可

JSX 中不能使用 if else 语句,可以用三元符代替

React 的 JSX 使用大、小写的约定来区分本地组件的类和 HTML 标签,即组件是大写开头。

4.组件

组件:是由一个个的HTML元素组成的,概念上来讲, 组件就像JS中的函数。它们接受用户输入(props),并且返回一个React对象,用来描述展示在页面中的内容

作用:组件可以让你把UI分割为独立、可复用的模块

定义组件的两种方法:

1.函数定义

function HelloMessage(props) {

return <h1>Hello World!</h1>;

}

2.class定义

class Welcome extends React.Component {

render() {

return <h1>Hello World!</h1>;

}

}

注意:

1.组件只能有一个顶层标签,组件名必须大写,必须有返回值:jsx对象或null。

2.通过 class 创建(有状态组件) ---》场景用于一定的业务逻辑,需要操作数据, 通过 JS函数 创建(无状态组件)---》场景用于仅仅展示数据

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

实现继承

// 实现继承的方式
class Studentextends Person {
  constructor() {
    // 必须调用super(), super表示父类的构造函数
    super()
    this.name= \'D\'
  }
}
class Welcome extends React.Component {
  constructor(props) {
    super(props)
  }
  render() {
    return <h1>Hello, {this.props.name}</h1>
  }
}

5.props和state

通常用props传递大量数据,state用于存放组件内部一些简单的定义数据

props 作用:给组件传递数据,一般用在父子组件之间 props是只读的,无法给props添加或修改属性,内容:React把传递给组件的属性转化为一个对象并交给 props

state 作用:用来给组件提供组件内部使用的数据只有通过class创建的组件才具有状态 状态是私有的,完全由组件来控制

只需更新组件的 state,然后根据新的 state 重新渲染用户界面

注意:不要在 state 中添加 render() 方法中不需要的数据,会影响渲染性能!不要在 render() 方法中调用 setState() 方法来修改state的值

propTypes

作用:通过类型检查,提高程序的稳定性

使用:给类提供一个静态属性 propTypes(对象),来约束props

// 引入模块

import PropTypes from \'prop-types\'

// ...以下代码是类的静态属性:

// propTypes 静态属性的名称是固定的!!!

static propTypes = {

initCount: PropTypes.number, // 规定属性的类型

initAge: PropTypes.number.isRequired // 规定属性的类型,且规定为必传字段

}

或者

propTypes: {

title: React.PropTypes.string.isRequired,

},

props={title:\'hello\'}

reder(){return <h>{this.props.title}</h> }

6.单向数据流

单向数据流:数据主要从父节点传递到子节点(通过props)。如果顶层(父级)的某个props改变了,React会重渲染所有的子节点

stateprops的区别在于前者(state)只存在于组件内部,只能从当前组件调用this.setState修改state值(不可以直接修改this.state!

一般我们更新组件都是通过改变state,再附给props进行改变组件的属性值。

function FormattedDate(props) {

return <h2>现在是 {props.date.toLocaleTimeString()}.</h2>;

}

<FormattedDate date={this.state.date} />

组件沟通:最为常见的组件沟通也就是父子了。

一般情况是:* 父组件更新组件状态 -----props-----> 子组件更新

  另一种情况是:* 子组件更新父组件状态 -----需要父组件传递回调函数-----> 子组件调用触发

子组件更新父组件:父组件通过props传递一个回调函数到子组件中,这个回调函数可以更新父组件,子组件就是通过触发这个回调函数,从而使父组件得到更新。

回调函数是什么?很多人看完过后回调函数是啥都不知道。

回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。这个过程就叫做回调,这么一说大家应该有印象了。

说完单向数据流,也说下双向绑定:值和UI双绑定,Angular2用的就是双向绑定

7.组件的生命周期

生命周期函数:从组件被创建,到组件挂载到页面上运行,再到页面关闭组件被卸载,这三个阶段总是伴随着组件各种各样的事件,那么这些事件,统称为组件的生命周期函数!

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

创建阶段(Mounting):该阶段的函数只执行一次

constructor() 1 获取props 2 初始化state 通过 constructor() 的参数props获取
class Hello extends React.Component {   
    constructor(props) {     
    // 获取 props     
   super(props)    
    // 初始化 state     
   this.state = {       count: props.initCount     }   
} } 
// 初始化 props // 语法:通过静态属性 defaultProps 来初始化props 
Hello.defaultProps = { initCount: 0 };
componentWillMount() :组件被挂载到页面之前调用,其在render()之前被调用,因此在这方法里同步地设置状态将不会触发重渲染

注意:无法获取页面中的DOM对象 注意:可以调用 setState() 方法来改变状态值

用途:发送ajax请求获取数据 ,

componentWillMount() {  

    console.warn(document.getElementById(\'btn\')) // null   
   this.setState({     count: this.state.count + 1   })
}
render() :渲染组件到页面中,无法获取页面中的DOM对象 不要在render方法中调用 setState() 方法,否则会递归渲染
render() {   
   console.warn(document.getElementById(\'btn\')) // null  
   return (  <div> <button  onClick={this.handleAdd}>打豆豆一次</button> </div>   ) 
}
componentDidMount() :组件已经挂载到页面中 可以进行DOM操作,比如:获取到组件内部的DOM对象 可以发送请求获取数据 可以通过 setState() 修改状态的值

注意:在这里修改状态会重新渲染 ,用于比较多还是获取url后面带过来的参数再重新绚烂页面

componentDidMount() {
// 此时,就可以获取到组件内部的DOM对象 console.warn(\'componentDidMount\', document.getElementById(\'btn\')) const { dispatch } = this.props; dispatch({ type: \'deriveEventRule/DataTypes\', }); const query = this.props.location.search; const arr = query.split(\'&\'); const eventid = arr[0].substr(9); dispatch({ type: \'deriveEventAct/formSaveDeriveEventData\', payload: { eventId: eventid}, }); }

运行和交互阶段(Updating):该阶段的函数执行多次 每当组件的props或者state改变的时候,都会触发运行阶段的函数

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

参数:当前组件props值 可以通过 this.props 获取到上一次的值

使用:若你需要响应属性的改变,可以通过对比this.props和nextProps并在该方法中使用this.setState()处理状态改变

注意:修改state不会触发该方法

componentWillReceiveProps(nextProps, nextState) {   
  console.warn(\'newProps\', nextProps)  
  console.warn(\'newstate\', nextState)  
}

shouldComponentUpdate() :返回值决定是否重新渲染组件,返回true重新渲染,否则不渲染

优势:通过某个条件渲染组件,降低组件渲染频率,提升组件性能

说明:如果返回值为false,那么,后续render()方法不会被调用

场景:根据随机数决定是否渲染组件 // - 第一个参数:最新属性对象 // - 第二个参数:最新状态对象

shouldComponentUpdate(nextProps, nextState) { return true}

componentWillUpdate() :组件将要更新 参数:最新的属性和状态对象

注意:不能修改状态 否则会循环渲染 componentWillUpdate(nextProps, nextState) { }

render() :渲染

作用:重新渲染组件,与Mounting阶段的render是同一个函数 注意:这个函数能够执行多次,只要组件的属性或状态改变了,这个方法就会重新执行

componentDidUpdate():组件已经被更新

参数:旧的属性和状态对象 componentDidUpdate(prevProps, prevState) { }

卸载阶段(Unmounting) 组件销毁阶段:组件卸载期间,函数比较单一,只有一个函数,这个函数也有一个显著的特点:组件一辈子只能执行依次! 使用说明:只要组件不再被渲染到页面中,那么这个方法就会被调用( 渲染到页面中 -> 不再渲染到页面中 )

componentWillUnmount():在卸载组件的时候,执行清理工作

如:清除定时器 清除componentDidMount创建的DOM对象

state和setState 使用 setState() 方法修改状态,状态改变后,React会重新渲染组件 注意:不要直接修改state属性的值,这样不会重新渲染组件

使用:1 初始化state 2 setState修改state

constructor(props) { super(props) // 正确姿势!!!

// -------------- 初始化 state --------------

this.state = { numcount: props.num } }

this.setState({ count: this.state.numcount + 1 })

8.组件绑定

1 通过React事件机制 onClick 绑定 推荐 <input type="button" value="触发单击事件" onClick={this.handleCountAdd} onMouseEnter={this.handleMouseEnter} />

2 JS原生方式绑定(通过 ref 获取元素),有时候我们可能需要直接获取真实的dom节点,而不是虚拟dom。组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM。只有当它插入容器以后,才会变成真实的 DOM 。采用diff算法将虚拟 DOM 上发生变动的部分,反映在真实 DOM上。

绑定一个 ref 属性到 render 的返回值上:<input ref="myInput" />

这样我们就获取该真实dom:

var input = this.refs.myInput;

var inputValue = input.value;

事件绑定中的this

1 通过 bind 绑定

 // 自定义方法:
 handleClick(arg1, arg2) {   
       this.setState({     msg: \'点击事件修改state的值\' + arg1 + arg2   }) 
} 
render() {  
 return (     
     <div>       
     <button onClick={         
     // 无参数         // this.handleClick.bind(this)        
     // 有参数         this.handleClick.bind(this, \'abc\', [1, 2])       
     }>点击处理</button>       
    <h1>{this.state.msg}</h1>     
    </div>   
    ) }

 在构造函数中使用
 constructor() {  
     super()   
     this.handleBtnClick = this.handleBtnClick.bind(this) 
 } 
// render() 方法中: <button onClick={ this.handleBtnClick }>点击处</button  

2 通过 箭头函数 绑定

<input type="button" value="在构造函数中绑定this并传参" onClick={ () => { this.handleBtnClick(\'参数1\', \'参数2\') } } />

handleBtnClick(arg1, arg2) { this.setState({ msg: \'在构造函数中绑定this并传参\' + arg1 + arg2 }); }

9.受控组件

在React中,可变的状态通常保存在组件的state中,并且只能用 setState() 方法进行更新. React根据初始状态渲染表单组件,接受用户后续输入,改变表单组件内部的状态。 因此,将那些值由React控制的表单元素称为:受控组件。

受控组件的特点: 表单元素 由React通过JSX渲染出来 由React控制值的改变,也就是说想要改变元素的值,只能通过React提供的方法来修改

只能通过setState来设置受控组件的值

// 模拟实现文本框数据的双向绑定 <input type="text" value={this.state.msg} onChange={this.handleTextChange}/>

// 当文本框内容改变的时候,触发这个事件,重新给state赋值 handleTextChange = event => { console.log(event.target.value) this.setState({ msg: event.target.value }) }

10.Ajax

通过 Ajax 请求从服务器获取数据,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI

class UserUpdate extends React.Component {
  constructor(props) {
      super(props);
      this.state = {username: \'\', lastGistUrl: \'\'};
  }
  componentDidMount() {
    this.serverRequest = $.get(this.props.source, function (result) {
      var lastGist = result[0];
      this.setState({
        username: lastGist.owner.login,
        lastGistUrl: lastGist.html_url
      });
    }.bind(this));
  }
  componentWillUnmount() {
    this.serverRequest.abort();
  }
  render() {
    return (
      <div>
        {this.state.username} 用户地址:
        <a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a>
      </div>
    );
  }
}
ReactDOM.render(
  <UserUpdate source="https://localhost:8080/user" />,
  document.getElementById(\'example\')
);