1.React 组件、状态管理

1.React 组件、状态管理

在REACT工程化项目中(yscode),我们会把需要写REACT组件的JS命名为.jsx

目的 : 让创建文件识别jsx语法,而在create-react-app 脚手架创建的项目中,已经包含了对.jsx文件的处理

REACT 中的组件:每一个组件都是一个单独的个体(数据私有,有自己完整的生命周期,有自己的视图)

1.函数式组件

只要返回一个JSX元素就可以(掌握props)

  • 当REACT-DOM.RENDER渲染的时候,如果TYPE是函数(函数式组件),会把函数执行(函数式组件要求必须有返回JSX虚拟DOM的RETURN返回值),会把解析出来的props(属性+子元素)传递给函数,属性是只读的;
  • 对于传递的子元素(props.children)可以基于React.Children.map来迭代遍历

特点:

  1. 简单(开发维护简单和渲染速度也快)
  2. 函数式组件是静态组件,一旦组件被调用,组件中的内容渲染完成,当前组件中的信息基本上就不变了(给组件传递进来的属性只读,也不能赋值),(除非重新调用组件传递不同的信息)=> ”静态组件“; 报错信息: Cannot assign to read only property 'title' of object
  3. 没有state状态管控内容,生命周期函数等随时更改组件中的内容(只有父组件重新调用它,才可能被更改)
  1. 不能给传递的属性直接的赋值
props.title = props.title || '我是标题'  ×let title = props.title || ‘我是标题  √
  1. 函数式组件不能像类组件一样,基于prop-types给属性设置默认的规则
// 只要在JS中使用jsx,则必须引入REACT(因为需要用到CREATE-ELEMNT)// React.Children.map 遍历传递进来的子JSX对象(子元素props.children)import React from 'react';export default function Vote(props) {    console.log(props)  // => {index: 10, title: "每天开心大笑~"}    return <div>        {props.title}        {/* {props.children} */}        {React.Children.map(props.children, (item, index) => {            if (index === 0) {                return <h2>                    {item} === {index}                </h2>            }        })}    </div>}==================================    ReactDOM.render(<div>    hello world~    <Vote index={10} title='每天都要开心大笑~'>    <span>哈哈哈</span><span>呵呵呵</span>    </Vote>    <Vote title = 'REACT支持单闭和标签组件调用(VUE不支持)'/></div>, document.getElementById('root')) 

2.基于React.Component 类创建组件

我们先来看一下ES6中关于类的一些知识点

/* * 继承 *    1.原型继承 *    2.CALL继承 *    3.寄生组合继承 Object.create *    4.ES6中基于CLASS实现继承  */class Parent { }class Clock extends Parent {constructor() {super(); //=>Must call super constructor in derived class before accessing 'this' or returning from derived constructor 只要用到CONSTRUCTOR,第一行就要写SUPER(类似于CALL继承,会把父类当做函数执行,让函数中的THIS是子类的实例)this.x = 100;}y = 200; //=>新增的语法:给实例设置的私有属性 和 CONSTRUCTOR中的 this.y=200效果一样AAA() {// Clock.prototype.AAA}static CCC = 300; //=>ES7新增的语法:直接在类上设置静态属性(REACT脚手架中给我们设置了关于这种语法的处理:@babel/plugin-proposal-class-properties)static BBB() {// Clock.BBB}}let c = new Clock();console.dir(c);console.dir(Clock);

类组件应用:

class Xxx extends React.Component/React.PureComponent
  • 当REACT-DOM.RENDER渲染的时候,如果发现虚拟DOM中TYPE是一个类组件,会创建这个类的一实例,并且把解析出来的PROPS传递给这个类:new Clock(props)

  • =>先执行CONSTRUCTOR(此时PROPS并未挂载到实例上,基于THIS.PROPS不能获取到值,但是可以直接使用形参中的PROPS;

  • **解决方法:**SUPER(PROPS)这样在CONSTRUCTOR中也可以用THIS.PROPS了)

  • =>当CONSTRUCTOR执行完,REACT会帮我们继续处理

  • ->把PROPS/CONTEXT...挂载到实例上(后期在其它的钩子函数中可以基于THIS.PROPS获取传递的属性值)

  • ->REACT帮我们把RENDER方法执行

类组件有自己的生命周期(lifecycle)

getDefaultProps

getInitialState

static childContextTypes={}

component

class Clock extends React.Component{  constructor(props){    // props:调取组件传递进来的属性    没有执行super()    console.log(props,this.props) // {title: "今天天气真好"} undefined(如果super(props)会读取到传递的属性    super();     //SUPER执行,相当于把React.Component当做普通函数执行,让方法中的THIS是当前实例:this=>{props:xxx,constructor:xxx,refs:{},updater:{...}}  }  // 必须要有render函数,它返回的内容使我们当前组件要渲染的视图  render(){    return <div>        <h2>{this.props.title}</h2>    </div>  }}ReactDOM.render(<div><Clock title='今天天气真好'></Clock></div>, document.getElementById('root'))

3. React状态管理

1.设置默认值

基于第三方插件prop-types设置属性的规则:默认值和其它规则

使用网址 github.com/facebook/pr…

/*1.安装 $ yarn add prop-types*//*2.设置默认值*/static defaultProps={  xxx:xxx}/*3.设置一些其它规则*/static propTypes = {title: PropTypes.string.isRequired}/**PropTypes.isRequired 必须传递*PropTypes.string/bool/number/func/object/symbol/node(元素对象)/element(JSX元素)/instanceOf(Xxx)必须是某个类的实例/oneOf(['News', 'Photos'])多个中的一个/oneOfType([PropTypes.string,PropTypes.number,PropTypes.instanceOf(Message)])多个类型中的一个*/

和VUE一样,我们设定的规则不会阻碍内容的渲染,不符合规则的在控制台报错

2.setState

setState 在合成时间或者生命周期函数中都是异步操作

把setState 放到一个异步操作中,此时它就没必要异步了,走的是同步处理;

  1. 定时器
  2. 原生JS事件
  3. ajax异步请求

合成事件:

React有一个类似于浏览器的渲染队列机制,它会在多次执行set-state的情况下,如果是异步操作,React把其合成一次进行重新渲染,如果修改的状态一样,以最后一次为主;

`handle = ev => {

  * SET-STATE在合成事件或者生命周期函数中都是异步操作    this.setState({ n: 100 });   this.setState({ m: 100 });

}`

默认是get/set 看不到数据,

可以通过ev.persist(); 或者ev.pageX直接获取

import React from 'react';import ReactDOM from 'react-dom';import propTypes from 'prop-types'class Clock extends React.Component {static defaultProps = {title: '北京时间'};static propTypes = {title: propTypes.string};constructor(props) {super(props);//=>初始化状态(和VUE中的DATA一样),要求后期需要在组件中使用的状态都要在这里初始化一下this.state = {time: new Date().toLocaleString(),m: 100};}render() {return <div><h2>{this.props.title}</h2><p>{this.state.time}</p></div>;    }//第一次加载组件渲染完毕 等价于 VUE中的MOUNTED    componentDidMount(){        // this.state.time = "哈哈哈"; //=>这样确实可以修改状态信息,但是不会通知组件重新渲染// this.forceUpdate();/可以配合使用,让视图强制渲染   => componentWillUpdate(跳过should步骤)         //=>每一次修改状态应该基于:setState方法(相对于this.state.xxx=xxx来说,不仅更改了状态,还会通知视图重新渲染)//   partialState:部分状态(对象),我们初始化的状态有很多,想修改谁,这块只写谁即可(REACT内部是把之前的状态和传递的partialState进行合并替换的) Object.assign(this.state,partialState)//   callback:setState在某些情况下是异步操作,此回调函数代表,通知视图重新渲染后执行的//=>shouldComponentUpdate()=>componentWillUpdate()        this.setState({            time:'不知道现在时间哦~'        },() => {//=>通知视图已经重新渲染完成了console.log('C');});    }}ReactDOM.render(<>        <Clock></Clock></>, document.getElementById('root'))

受控组件

我们把基于状态(或者属性)的更新来驱动视图渲染=>'受控组件'(受状态管控的组件)

属性什么时候可以改?

  1. 设置默认值
  2. 父组件调取子组件,重新传递不同的属性;
  3. 把获取的属性传递给组件的状态,后期修改状态

基于prop-types设置默认值

class Clock extends React.Component {static defaultProps = {title: '北京时间'};static propTypes = {title: PropTypes.string};constructor(props) {super(props);this.state = {time: new Date().toLocaleString()};}render() {return <div><h2>{this.props.title}</h2><p>{this.state.time}</p></div>;}componentDidMount() {setInterval(() => {this.setState({time: new Date().toLocaleString()});}, 1000);}}ReactDOM.render(<div><Clock></Clock></div>, document.getElementById('root'));

非受控组件

非受控组件:不受状态管控(直接操作DOM)

class Clock extends React.Component {static defaultProps = {title: '北京时间'};static propTypes = {title: PropTypes.string};constructor(props) {super(props);}render() {return <div><h2>{this.props.title}</h2>{/* <p ref='timeBox'>{new Date().toLocaleString()}</p> */}<p ref={element => {//=>REF真实项目中应用最多的是函数的模式// element代表当前元素对象// 直接把元素对象挂载到实例上了this.timeBox = element;}}>{new Date().toLocaleString()}</p></div>;}componentDidMount() {//=>可以获取到DOM元素// this.refs={timeBox:p}  setInterval(() => {this.timeBox.innerHTML = new Date().toLocaleString();// this.refs.timeBox.innerHTML = new Date().toLocaleString();}, 1000);}}ReactDOM.render(<div><Clock></Clock></div>, document.getElementById('root'));
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部