React

react历史

  • Vue2014年开源
  • 2013年面向开发者不是开源的
  • angular2009年
  • vue双向数据绑定->双向数据流
  • react单向数据流
    • 内存的改变影响页面的改变不管页面的改变,影响内存的改变,自己处理页面的改变,影响内存,通过事件
  • 没有指令

import和require

  • import属于加载前置的机制,因此将其全放再代码顶部,代码解析逐个import获取一个引入的列表,先引入依赖,再向下执行代码,加载前置
  • require
    • if(true) { let querystring=require(’ querystring’); }
    • 加载滞后,代码执行到哪一行才进行加载

脚手架

  • 下载脚手架工具 npm i -g create-react-app
  • 使用
    • create-react-app 项目名options 构建项目解构
    • cd项目目录&& npm i安装依赖包
  • 运行
    • npm run start启动
    • npm run build生成dist

jsx语法

js+ xml

基本操作总结

  • 1:引入React对象
  • 2:引入ReactDOM对象
  • 3:操作jsx
    • jsx不能用+=来运算(不是字符串)
    • jsx可以通过数组来输出数据
      1
      ,
      2
    • const arr = [
      1
      2
      ]
  • 4:渲染到指定的元素上
    • reactDOM. render (,document . getE lementById(‘app’);
  • 5:启动npm run dev

官方推荐的class方式

  • 儿子class ->子类构造器中必须super(父类构造器

编写App渲染内容

  • 只能有一个根节点函数

调用的示例

  • this指向

react中有变化的属性

  • className
  • htmlFor

传递参数及DOM

  • react中之 直接给属性就是数据,在子组件中this.props.属性名获取
  • 直接往子组件中扔DOM就是传入的DOM,在自组件中使用this.props.children输出
  • 更加健壮的排除空节点undefined或者单节点Object或多子节点Array
    • React. Children. map(this . props . children, child=>{ })

获取DOM元素

生命周期

constructor( )

1 constructor (props)

react的构造器是在装载之前被调用的,当构造器实现了React.Component类,你应该在任意的生命之前调用super(props)

  • Otherwise, this.props will be undefined in the constructor, which can lead to bugs.

常见的构造函数内目的:

  • Initializing local state by assigning an object to this .state .
  • Binding event handler methods to an instance.
constructor (props) {
super(props);
// Don't ca11 this .setState() here!
this.state = { counter: 0 };
this.handTeClick = this.hand1eClick.bind(this);//改变handleClick的this的上下文

componentWillMount

官方不推荐在此处发请求,原因可能会造成渲染的阻塞,而将请求放在componentDidMount(数据已经装载,据网上流传会引起二次render)

render ()

在一个class或者function组件中必须需要的

Note

render() will not be invoked if shoul dComponentUpdate( returns false.

componentDidMount( )

1 componentDidMount ()

实际应用发网络请求

组件安装后立即调用componentDidMount () (插入到树中) 。需要DOM节点的初始化应该到这里。如果您需要从远程端点加载数据,那么这是实例化网络请求的好地方

这个方法是建立任何订阅的好地方。如果您这样做,请不要忘记在componentWillUnmount ()中取消订阅。

componentDidupdate()

1 componentDidUpdate (prevProps, prevstate, snapshot)

componentDi dupdate() is invoked immediately after updating occurs. This method is not called for theinitial render.

当组件被更新时,将此作为在DOM.上操作的机会。这也是一一个进行网络请求的好地方,只要您将当前的props与以前的props进行比较(例如,如果props没有改变, 网络请求可能就不需要了)。

componentDidUpdate (prevProps) {
// Typical usage (don't forget to compare props):
  if (this.props.userID !== prevProps.userID) {
		this.fetchData(this.props.userID) ;
	}
}

注意:

componentDidupdate() will not be invoked if shouldComponentupdate() returns false.

shouldComponentUpdate()

componentWillUpdate()

componentWillUnmount()

传值及slot

  • 属性约束及默认值
import PropTypes from 'prop-types' ;
static propTypes = {
	name :PropTypes.number //string.isRequired
}
static defaultProps = {
	name: 'abc'
}
  • 传值
import React, {Component} from 'react';
import Son from "./son.js";

class App extends Component{
    constructor(){
        super();
        this.state = {
            age:12,
        }
    }

  render() {
    let {age} = this.state;
    let header = (<div>header</div>);
    let footer = (<div>footer</div>)
    return (
        <div>
          我是app组件,一下使用son组件
          <hr/>
            {/*组件的使用必须首字母大写*/}
          {/*<Son age={this.state.age} name="jack"/>*/}
            <Son age={age} name="jack" head={header} foot={footer}>
                <ul>
                    <li>1</li>
                    <li>2</li>
                    <li>3</li>
                </ul>
            </Son>
        </div>
    )
  }
}
export default App;
import React, {Component} from 'react';
import PropTypes from 'prop-types';

class Son extends Component{
    //属性的约定和默认值
    static propType = {
        text: PropTypes.number // string.isRequired
    }
    static defaultProps = {
        text :'abc',
    }

    constructor(props){
        super(props);
    }
    render() {
        console.log(this.props)
        //声明一rage, name属性,this. props中的同名属性进行赋值
        let {age, name, head, text} = this.props;
        //改变age与this. props. age无关
        // 声明一 个引用类型属性,this. props中同名属性的地址进行赋值
        //Let{obj}= this. props;
        //改变obj.xxx 与this. props.obj.xxx有关
        return (
            <div>
                我是子组件,数据如下:
                <hr/>
                {/*{this.props}*/}
                {name}, {age}
                <div style={{backgroundColor:'red'}}>
                    {head}
                </div>
                {this.props.children}
                <div style={{backgroundColor:'blue'}}>
                    {this.props.foot}
                </div>
                {text}
            </div>
        )
    }
}

export default Son;

内置便捷函数

  • this.props.children有可能有三种数据结构: 对象/数组/undefined
    • React.Children.map (children, function[(thisArg)]) // 返回数组
  • 更加健壮的排除空节点undlefined或者null的情况
    • React.Children.forEach (children, function [(thisArg)]) //遍历

template补充

  • 保证一个跟节点
    在这里插入图片描述

  • 解决方案

    • 在react16以后, 可以支持编写[]

    • render(){ return [

      1

      ,

      2

      ] }

    • render(){ 
        return <React.Fragment>
          <h1>1</h1>
          <h1>2</h1>
        </React.Fragment>
      }
      
    • 该方式不会创建对于的元素

react15和16的区别

React.createClass和 extends Component的区别主要在于:

  1. 语法区别
  2. propType 和 getDefaultProps
  3. 状态的区别
  4. this区别
  5. Mixins 混合的区别

语法区别

React.createClass

import React from ' react ' ;
const Contacts = React.createClass({
    render() {
        return (
           <div></div>
        );
    } 
});
export default Contacts ;

React.Component

import React from react' ;
class Contacts extends React.Component {
    constructor (props) {
        super (props);
    }
    render() {
      return (
        <div></div>
       );
    }
}

后一种方法使用ES6的语法,用constructor构造器来构造默认的属性和状态。

propType和getDefaultProps

React.createClass:通过proTypes对象和getDefaultprops ()方法来设置和获取props.

import React from ' react ' ;
const Contacts = React.createClass ({
  propTypes: {
    name: React.PropTypes.string},
    getDefaultProps() {
  		return {
        name:'abc'
      };
    },
  render() {
    return (
   		 <div></div>
    );
  }
});
export default Contacts ;

React.Component:通过设置两个属性propTypes和defaultProps

import React form 'react' ;
class TodoItem extends React.Component{
    static propTypes = { // as static property
      name: React.PropTypes.string
    };
    static defaultProps = { // as static property
      name : 1!
    };
    constructor (props){
    	super (props)
    }
    render(){
    	return <div></div>
    }
}

状态的区别

React.createClass:通过getInitialstate()方法返回一个包含初始值的对象

import React from 'react ' ;
let TodoItem = React. createClass({// return an object
    getInitialState(){
      return {
      	isEditing: false I
      }
    },
    render(){
    	return <div></div>
		}
})

React.Component:通过constructor设置初始状态

import React from 'react' ;
class TodoItem extends React . Component{
    constructor (props){
        super(props) ;
        this.state = { // define this.state in constructor
          isEditing: false
        }
    }
    render(){ 
  		  return <div></div>
    }
}

this区别

React.createClass:会正确绑定this

import React from' react' ;
const Contacts = React.createClass({
  handleClick() {
    console.1og(this); // React Component instance
  },
  render() {
    return (
      <div onClick={this . hand1eclick}></div>//会切换到正确的this上下文
    );
  }
});
export default Contacts ;

React.Component:由于使用了ES6,这里会有些微不同,属性并不会自动绑定到React类的实例上。

import React from 'react ' ;
class TodoItem extends React.Component{
  constructor(props){
  	super(props);
  }
  handleClick(){
  	console.1og(this); // null
  }
  hand1eFocus(){ // manually bind this 
  	console.1og(this); // React Component Instance
  }
  hand7eBlur: ()=>{ // use arrow function
  	console.1og(this); // React Component Ins tance
  }
  render(){
    return <input onClick={this.handleclick}
                  onFocus={this.handleFocus.bind(this)}
                  onB7ur={this.hamp1eB1ur}/>
  }
}

我们还可以在constructor中来改变this.handleClick执行的上下文,这应该是相对上面一种来说更好的办法,万一我们需要改变语法结构,这种方式完全不需要去改动JSX的部分:

import React from 'react' ;
c1ass Contacts extends React.Component {
  constructor(props) {
    super (props);
    this .hand1eClick = this.handleClick.bind(this);
  }
  handleClick() {
  	console.1og(this); // React Component instance
  }
  render() {
    return (
    	<div onClick={this . handleClick}></div>
    );
  }
}
export default Contacts;

Mixins

如果我们使用ES6的方式来创建组件,那么React mixins的特性将不能被使用了。

React.createClass:

import React from 'react';
1et MyMixin = {
  doSomething(){}
}
1et TodoItem = React.createClass({
  mixins: [MyMixin], // add mixin
  render(){
  	return <div></div>
  }
})

使用React.createClass的话,我们可以在创建组件时添加一个叫做mixins 的属性,并将可供混合的类的集合以数组的形式赋给mixins。

React.Compoent

export default function (Son) {
  return class wrap extends Component {
    compomentDidMount () {
      conso1e.1og('aaaaa') ;
      console.1og()
    }
    render() {
    <Son/>
    }
  }
}

插件相关

基本使用

  • react-router-dom(在浏览器使用)
  • react-router-native(开发手机原生应用使用的)。推荐使用react-navigation

使用流程

  • 下载npm i react-router-dom ;
  • 引入对象,按需引|入,HashRouter, BrowserRouter ,Route
  • HashRouter代表路由框架的坑
  • BrowserRouter代表路由的坑,最终 是没有#的方式,原理基于click + history.pushState
  • Route 代表锚点及组件和填入的位置

Switch选择-个

  • 横线匹配一个
  • 被其包裹的Route从上到下,只会匹配一个(选其一 )

exact精确匹配

React-router 默认是模糊匹配,所以需要添加exact来适配精确匹配

  • 纵向(深入匹配)一个
  • 精确匹配锚点(只会匹配一个)
  • 应用场景:首页’/’ 需要使用,因为/范围太大,会匹配很多东西
    • 其他路由不适用,为了能使用嵌套路由(不要控制纵向(深入)只匹配一个)

默认重定向(相当于404)

  • 放在路由最后一位,用来处理页面找不到,配合Switch
  • Redirect,常用to属性

NavLink类似router-link

  • NavLink 按需引入import {NavLink} from ‘react-router-dom’ ;
  • 当做组件来使用,其中属性to(路径与Route中的path匹配
<NavLink to="/index/course" activeSty1e={{ co1or: '#4dc060' }}>样式</NavLink>
<NavLink to=" /index/mine" activeClassName="selected">类名</NavLink>

代码注意

  • 主体组件App只能有一个根节点
  • 主体坑(HashRouter)也只能有一 个根节点
    • NavLink 只能在主体坑中
    • Switch中不能有Navllink

路由参数

<Route path= '/user/:data' component= {UserPage}></Route>1

使用

var data = {id:3,name:sam,age:36};
data = JSON.stringify(data);
var path = '/user/${data}';
1.<Link to={path}>用户</Link>
2. hashHistory.push(path);

获取数据:

var data = JSON.parse(this.props.params.data) ;
var {id,name,age} = data;12

通过这种方式跳转到UserPage页面时只能通过传递字符串来传递参数,那么是否有其他方法来优雅地直接传递对象而不仅仅是字符串呢?

二.query

query方式使用很简单,类似于表单中的get方法,传递参数为明文:首先定义路由:

<Route path='/user' component={UserPage}></Route>1

使用

var data = {id:3,name:sam,age:36};
var path = {
  pathname:'/user',
  search:'?id=4',		#url拼接
  query:data,				# 跳转后附带是参数
}
<Link to={path}>用户</L ink>xxxHistory.push(path);

获取数据:

var data = this.props.location.query;
var {id ,name ,age} = data;

query方式可以传递任意类型的值,但是页面的URL也是由query的值拼接的,URL很长,那么有没有办法类似于表单post方式传递数据使得传递的数据不以明文传输呢?

三. state

state方式类似于post方式,使用方式和query类似,首先定义路由:

<Route path= ' /user' component={Us erPage}></Route>1

使用:

var data = {id:3,name: 'sam' ,age:36} ;
var path = {
    pathname:'/user' ,
    state :data,
}
<Link to={path}>用户</Link>
hashHistory.push(path) ;

获取数据:

var data = this.props.1ocation.state ;
var {id,name,age} = data;

编程导航

  • this.props.history.push
    • 改变锚点值,引发页面变更
    • 前进或后退this. props . history . goBack() IIgoForward();
    • 前进或后退,根据参数
  • 通过历史记录来操作导航

嵌套路由

  • 在部分相同布局的情况下,局部发生变化
  • 避免相同布局的重复渲染
  • 在需要出现嵌套路由的组件位置中,直接写上坑、path、 组件
  • 嵌套的子路由的path必须写成完成的路径
posted @ 2019-06-07 07:40  南山道士  阅读(65)  评论(0编辑  收藏  举报