Regex

React

[^2018 jul 5]:

初始化项目可以通过一个叫做create-react-app的包来创建

npm i -g create-react-app

create-react-app my-app

cd my-app

yarn start

在jsx代码中使用表达式

let a = 1;
let b = 3;
ReactDOM.render(
  <div>
    {a + b} //也可以使用模板字符串
    //{ `${a} ${b}`}
  </div>,
  document.getElementById("root")
);

在花括号中可以进行简单的运算,调用有正确返回值的函数,插入模板字符串等等

for循环,流程判断语句都不属于表达式,所以不能在这里使用,如果需要进行判断,可以使用三目运算符,或者逻辑运算符进行判断

花括号可以在jsx文件的任意位置使用,代码结构也可以被当做变量,但要注意的是,插入的变量也必须要有一个根元素,否则将会报错

let jsx1 =(
  <div>
    <h1>yoooo</h1>
  </div>
)
ReactDOM.render(
  <div>
  <p>
   {jsx1}
  </p>
  </div>
,
  document.getElementById("root")
);

并且,jsx的模板变量不能插入到模板字符串中

如果并不想插入的结构或者声明的变量中有一个根元素,可以使用react提出的解决方案,Fragment,他可以当做一个标签使用,但是他并不会被渲染出来,使用之前需要引入这个变量

import React ,{Fragment}from "react";
import ReactDOM from "react-dom";

let jsx1 =(
  <Fragment>
    <h1>yoooo</h1>
    <h1>yoooo</h1>
  </Fragment>
)
ReactDOM.render(
  <Fragment>
 
   {jsx1}
 
  </Fragment>
,
  document.getElementById("root")
);

样式

如果想要在jsx的代码中应用行间样式,需要使用双层的花括号

ReactDOM.render(
  <Fragment>
 
  <div style=>yooo</div>
 
  </Fragment>
,
  document.getElementById("root")
);

在jsx中样式不能有破折线,应该采用驼峰命名的形式

并且react会自动判断单位并补齐,所以在书写的时候并不一定要写全

关键字例如class需要改写成className

如果需要引用外部样式表,可以在js文件中使用es6的import命令来引入,create-react-app所搭建的环境会帮助我们进行编译

import './main.css'

组件

let People = ()=>(
  <div>hhhhhhh 
  </div>
);
//es5 写法
function People(){
    return(
    <div>hhhhhhh 
  </div>
    )
}
ReactDOM.render(
  <Fragment>
 <h1 className="kkk">yoooo</h1>
 <People/>
  </Fragment>
,
  document.getElementById("root")
);

标签如果没有内容可以直接闭合

以上是生成一个自定义的组件的形式,函数必须要有正确的返回值,上面使用的es6的箭头函数默认返回的一个组件,有一点需要注意,react会把第一个字母大写的标签识别为组件,否则将被直接渲染到页面里


class Com extends React.Component{
render(){
  return(
    <div>
      qqqqq
     </div>
    )
  }
}

ReactDOM.render(
  <Fragment>
 <h1 className="kkk">yoooo</h1>
 <Com/>
  </Fragment>
,
  document.getElementById("root")
);

组件也可以通过类的方式定义,类必须要继承自React.Component,且至少执行一个render方法,里面要有正确的返回结构,使用方式与声明函数相同,也可以在文件初始化的时候取出Component这个类

import React ,{Fragment,Component}from "react";
import ReactDOM from "react-dom";
class Com extends Component{
render(){
  return(
    <div>
      qqqqq
     </div>
    )
  }
}

Props

Props可以实现组件间的通信

属性的名和值都是任意的,组件所传递的属性和值会被props捕获到,并整体封装成一个对象,如果需要在组件中使用所传递的属性的值,可以使用props.###,如果什么都没有传递,那么props将会是一个空对象

####函数组件的通信

let Sunction = (props)=>{
     return(
    <p>This is Sunction {props.name}</p>
	)
}
ReactDOM.render(
  <Fragment>
 <Sunction name="Joe" age={21} self={true}/>
  </Fragment>
,
  document.getElementById("root")
);

Class组件的通信

class Man extends Component{
    
    render(){
      let {name,age} = this.props;
      return(
        <div>
          引入成功
              name:{name},
              age:{age}
         </div>
        )
      }
    }
ReactDOM.render(
  <Fragment>
	<Man name="joe" age={20}/>
  </Fragment>
,
  document.getElementById("root")
);

类组件的实例数据会被存储在实例的this.props下

React中为单向数据流,即从顶层流到底层

class Man extends Component{
    render(){
      let {name} = this.props;
      return(
        <div>
            name:{name}       
         </div>
        )
      }
    }//子组件
let Sunction = (props)=>{
     return(
    <p>
       <Man name={props.test}/>
    </p>
	)
}//父组件
ReactDOM.render(
  <Fragment>
        <Sunction test="chuandi"/>
  </Fragment>
,
  document.getElementById("root")
);

组件所定义的标签之间的内容是默认为props.children,所以组件中没有使用到这个属性,那么是不会有任何显示的

let Sunction = (props)=>{
     return(
    <p>
       {props.children}
    </p>
	)
}
ReactDOM.render(
  <Fragment>
        <Sunction>
        this is children
        </Sunction>
  </Fragment>
,
  document.getElementById("root")
);

DefaultProps

let Sunction = (props)=>{
     return(
    <p>
      name:{props.name}
      age:{props.age}
      random:{props.renderprop()}
    </p>
	)
}
Sunction.defaultProps = {
    name:'',
    age:0,
    renderprop:()=>{}
}
ReactDOM.render(
  <Fragment>
        <Sunction renderprop={()=>Math.random()}/>
                <Sunction name="Joe" age="20"/>
  </Fragment>
,
  document.getElementById("root")
);

defaultProps可以指定属性的默认值,如果属性没有被传递值或者传递的值等于undefined,那么默认值将会生效,否则正常渲染

在上面的例子中,如果没有默认的值,那么第二个Sunction组件在尝试调用props.renderprop()的时候,将会抛出错误,因为这个函数并没有被定义,所以在一些情况下,设置默认值是有必要的

Props-Type

PropTypes 输出了一系列的验证器,可以用来确保接收到的参数是有效的。例如,我们可以使用PropTypes.string 语句。当给 prop 传递了一个不正确的值时,JavaScript控制台将会显示一条警告。出于性能的原因,propTypes 仅在开发模式中检测。

他不会使页面崩溃掉,只会在控制台输出错误

import PT from 'prop-types'
Sunction.PT = {
  // 你可以声明一个 prop 是一个特定的 JS 原始类型。 
  // 默认情况下,这些都是可选的。
  optionalArray: PT.array,
  optionalBool: PT.bool,
  optionalFunc: PT.func,
  optionalNumber: PT.number,
  optionalObject: PT.object,
  optionalString: PT.string,
  optionalSymbol: PT.symbol,
   // 任何东西都可以被渲染:numbers, strings, elements,或者是包含这些类型的数组(或者是片段)。
  optionalNode: PropTypes.node,
   // 一个 React 元素。
  optionalElement: PropTypes.element,
   //声明此项为必填项
  age: PropTypes.number.isRequired
}

在react中组件属性的值如果是一个数组,那么会被默认展开并渲染到页面

State

State是私有的,完全受控于当前组件

只有类组件才拥有局部状态,所以如果一个函数组件需要局部状态,那么需要把他转换为类组件

class Magic extends Component {
  constructor() {
    super();
    this.state = {
      number: Math.random(),
      name: "Joe"
    };
  }
  render() {
    let { number, name } = this.state;
    return (
      <div>
        <h2>{name}</h2>
        <p>{Math.random()}</p>
        <button
          onClick={() => {
            this.setState({
              number: Math.random()
            });
          }}
        >
          change number
        </button>
      </div>
    );
  }
}
ReactDOM.render(
  <Fragment>
    <Magic />
  </Fragment>,
  document.getElementById("root")
);

this.setState

在react中像下面这样直接调用this.state是不会重新渲染组件的,但是数据会发生改变

class Magic extends Component{
    constructor(){
     super() 
     this.state = {
        number:Math.random()
     }
    }
    render(){
        let{number} = this.state;
        return(
        <div>
        <button onClick={()=>{
            this.state.number = Math.random()
            console.log(this.state.number)
        }}>click</button>
        </div>
        )
    }
}

如果需要改变数据并渲染到视图,需要调用this.setState这个组件

他会再次调用render方法,并且重新读取数据

合并更新

react为了提高性能,当在一个组件中多次调用setState组件时,react会默认将其合并更新,也就是无论写了多少个setState组件,render方法都会合并为一次重新调用

<button onClick={()=>{

        this.setState = {
		number:Math.random()
        }
        this.setState = {
		name:'Leo'
        }
    }}>click</button>

异步更新

新数据并不会被及时的捕获

this.props 和 this.state 可能是异步更新的,你不应该依靠它们的值来计算下一个状态

<button onClick={()=>{
        let num = Math.random()
        this.setState = {
		number:num
        }
        console.log(this.state.number,num) // 当前值,上一次的值
    }}>click</button>

要修复它,请使用第二种形式的 setState() 来接受一个函数而不是一个对象。 该函数将接收先前的状态作为第一个参数,将此次更新被应用时的props做为第二个参数

this.setState((prevState, props) => ({
  console.log(prevState) // 数据被更新后的结果
  console.log(props) //组件所传递的props
}));

SyntheticEvent

boolean bubbles					//如果是事件是起泡事件,返回true
boolean cancelable				//返回一个布尔值,表明该事件是否可以被取消,是返回true
DOMEventTarget currentTarget	//指向事件处理程序附加到的元素
boolean defaultPrevented		//表明事件的默认行为是否被取消,也就是是否执行了event.preventDefault()
number eventPhase				//返回一个代表当前执行阶段的整数值
boolean isTrusted				//返回一个布尔值,为true表明当前事件是由用户行为触发,否则表明事件由一个脚本生成的
DOMEvent nativeEvent			//触摸事件相关
void preventDefault()			//阻止默认行为
boolean isDefaultPrevented()	//
void stopPropagation()			//阻止事件的冒泡
boolean isPropagationStopped()	//
DOMEventTarget target			//指向事件的触发元素
number timeStamp				//用于指定创建事件的时间(相对于纪元的毫秒数)
string type						//返回事件类型

this指向

因为在react中结构并不是真正的dom,所以一些涉及this的问题需要进行处理

class Magic extends Component {
    constructor(props) {
        super(props)
        this.state = {
            name: 'Leo'
        }
    }
    render() {
        return (
            <div>
                <button onClick={()=>{
                    this.setState({
                    number: '666'
                    })}}>Change Number</button>
            </div>
        )
    }
}

es6的箭头函数默认this指向函数所在的上下文,但如果使用原生的函数或者绑定类中的函数this就会指向undefined,这个时候需要用bind进行this的手动绑定

class Magic extends Component {
    constructor(props) {
        super(props)
        this.state = {
            name: 'Leo'
        }
    }
    render() {
        return (
            <div>
                <button onClick={(function(){
                    this.setState({
                    number: '666'
                    })
                   }
                  ).bind(this)}>Change Number</button>
            </div>
        )
    }
}
class Magic extends Component {
    constructor(props) {
        super(props)
        this.state = {
            name: 'Leo'
        }
    }
    bundleclick(){
        this.setState({
           number: '666'
        })
    }
    render() {
        return (
            <div>
                <button onClick={this.bundleclick.bind(this)}>Change Number</button>
            </div>
        )
    }
}

但是需要注意的是,上面的例子在每次触发点击事件后都会重新的进行this的绑定,相当于每次点击都生成新的button,并且react检测到render函数体内的变化就会重新渲染界面,会对性能有一定的影响,所以更推荐在构造函数内就将要执行的函数进行this的绑定,这样只会在实例化的时候进行一次绑定

class Magic extends Component {
    constructor(props) {
        super(props)
        this.state = {
            name: 'Leo'
        }
        this.bundleclick = this.bundleclick.bind(this)
    }
    bundleclick(){
        this.setState({
           number: '666'
        })
    }
    render() {
        return (
            <div>
                <button onClick={this.bundleclick}>Change Number</button>
            </div>
        )
    }
}

如果事件很多的话,也可以使用es6的语法,但这种语法不在标准内,需要在开发环境内进行编译

class Magic extends Component {
    constructor(props) {
        super(props)
        this.state = {
            name: 'Leo'
        }
    }
    bundleclick=()=>{
        this.setState({
           number: '666'
        })
    }
    render() {
        return (
            <div>
                <button onClick={this.bundleclick}>Change Number</button>
            </div>
        )
    }
}

生命周期-Mount