美文网首页
React入门(二)

React入门(二)

作者: Leonard被注册了 | 来源:发表于2019-11-15 18:55 被阅读0次

    组件

    1.函数式组件

    • 什么是函数式组件
      创建一个函数,只要函数中返回一个新的JSX元素,则为函数式组件
    import React from 'react'
    function News(props){    // 声明函数式组件
      console.log(props);    //接收只读属性
      return <div>
        <ul>
          <li>webpack</li>
          <li>vue</li>
          <li>react</li>
        </ul>
      </div>
    }
    export default News;
    
    • 调用组件
      可以是单闭合,也可以是双闭合。双闭合方式可以把一些子节点当作属性(children)传递给组件,在组件中可以把传递的这些节点放在指定的位置
    // index.js
    ReactDOM.render(<>
            <Dialog con='嘿嘿嘿'  />
        <Dialog con='呵呵呵' lx={1} >
              <span>1</span>
              <span>2</span>
        </Dialog>
    </>, document.getElementById('root'));
    
    // Dialog.js
    export default function Dialog(props) {
        let {con, lx = 0, children, style = {}} = props,
            title = lx === 0 ? '系统提示' : '系统警告';
        return <section style={style}>
            <h2>{title}</h2>
            <div>{con}</div>
            {/*把属性中传递的子元素放到组件中的指定位置*/}
            { children }
    
            {/*也可以基于REACT中提供的专门遍历CHILDREN的方法来完成遍历操作*/}
            {
                React.Children.map(children, item => item)
            }
        </section>;
    };
    
    • 静态组件
      每次调用函数组件,都会重新进行渲染和计算,把渲染后的结果呈现在页面中,渲染完成后呈现的内容将不再改变,除非重新调用该组件

    2.类组件

    • 什么是类组件
      创建一个类,让其继承React.Component或者React.PureComponent,此类被称为类组件
    • 基于状态管理动态组件:
      1.设置初始状态值
      2.修改状态:setState修改组件中的状态
    import React from 'react'
    
    export default class Clock extends React.Component{
      // 调取组件,创建类的一个实例,首先执行constructor,把属性、上下文等信息传递进来
      constructor(props){
        super(props);
        // 如果只写SUPER():虽然创建实例的时候把属性传递进来了,但是并没有传递父组件,也就是没有把属性挂载到实例上,使用THIS.PROPS获取的结果是UNDEFINED
        // 如果SUPER(PROPS):在继承父类私有的时候,就把传递的属性挂载到了子类的实例上,CONSTRUCTOR中就可以使用THIS.PROPS了
        console.log(this.props);    // 接收的只读属性
        // 创建初始状态
        this.state = {
          time: new Date().toLocaleString()
        }
      }  
      // render渲染组件的内容  
      render(){
        return <div>
            {this.state.time}
        </div>
      }
      // componentDidMount:生命周期  第一次渲染完
      componentDidMount(){
        setInterval(() => {
                // 修改状态,并且通知组件重新渲染
                this.setState({
                    time: new Date().toLocaleString()
                });
        }, 1000);
    }
    
    • 属性的操作
      利用第三方插件prop-types可以设置属性的规则
    // test.jsx
    import PropTypes from 'prop-types';
    ...
    // 设置默认属性
    static defaultProps = {
        m: 100
    };
    // 属性验证
    static propTypes = {
        m: PropTypes.number,
        x: PropTypes.string.isRequired
    };
    ...
    
    // index.js
    ...
    <Clock m={1} x='pass'/>
    ...
    
    • 非受控组件
      不受状态管控的组件(通过ref方式),有时我们会需要直接对某个DOM节点或组件进行操作,而不是通过状态,此时会运用到非受控组件,对应的概念:受控组件:受状态管控的组件 => 数据驱动视图渲染
    // 以下是三种使用ref的方法
    export default class Input extends React.Component {
        constructor(){
          super();
          this.refObj = React.createRef();  // { current: null }    method 3
        }
        render() {
            return <div>
                 <input type="text" ref='inpBox' />      // method 1,不推荐使用
                 <input type="text" ref={element => {    // method 2
                    // element当前的元素对象
                    this.inp = element;
                 }} /> 
                 <input type="text" ref={ this.refObj } />  // method3
            </div>;
        }
        componentDidMount() {
            this.refs.inpBox.focus();  // method 1,不推荐使用
            this.inp.focus();          // method 2
            this.refObj.current.focus();  // method3
        }
    }
    

    3.细节知识点

    • REACT中的事件是合成事件,即所有的事件都是进行事件代理的,而且事件对象也是合成的,故会出现以下情况。解决这一问题的方法有两种,一是采用bind改变this指向,二是采用ES6的箭头函数
    render(){
      return <div>
        <button onClick={this.handle}>button</button>
      </div>
    }
    handle(ev){
      console.log(this);    // undefined
      console.log(ev);      // 事件对象
    }
    
    <button onClick={this.handle.bind(this)}>button</button>    //method 1
    <button onClick={()=>console.log(this)}>button</button>     //method 2
    
    • 当使用setState进行状态设置时,即使状态不发生变化,仍然会触发render的重新渲染,此时应当考虑对其进行优化,可以在shouldComponentUpdate中进行手动对比设置,也可以直接让类组件继承React.PureComponent来自动进行浅对比(引用变化是检测不出来的)
    handle = ev => {
        this.setState({
            // 不管状态是否改变,都会控制render重新渲染
        });
    }
    
    // 手动对比优化,与自动对比同时出现时手动为主
    shouldComponentUpdate(nextProps, nextState) {
        // 拿当前的状态和最新修改的状态进行对比(浅对比),如果一样则不渲染,不一样才进行渲染
        if (this.state.n === nextState.n) {
            return false;
        }
        return true;
    } 
    
    // 自动对比
    export default class Test extends React.PureComponent {
      ...
    }
    ...
    
    • setState本身在生命周期函数或者合成事件中执行是异步的
      =>保证REACT生命周期函数执行的顺序不会紊乱
      =>保证其实现渲染队列的机制,可以合并setState后统一处理
    export default class Test1 extends React.Component {
       state = {
           n: 0
       };
       render() {
           console.log("render")
           return <div>
               {this.state.n}
               <button onClick={this.handler}>+</button>
           </div>
       }
       handler = ev => {
           this.setState({
               n: this.state.n + 1
           })
           console.log('ok')
       }
    }
    
    点击按钮后
    • setState在原生事件绑定中和其他异步操作中是同步的
      =>此时失去渲染队列的效果
    export default class Test1 extends React.Component {
        state = {
            n: 0,
            m: 0
        };
        render() {
            console.log('render')
            return <div>
                {this.state.n} === {this.state.m}
                <button onClick={this.handler}>+</button>
            </div>
        }
        handler = ev => {
            setTimeout(()=>{
                this.setState({
                    n: 10
                })
                this.setState({
                    m:20
                })
                console.log('ok')
            },1000)
            
        }
    }
    
    失去渲染队列处理效果
    • 按理说ES6中的类是不能设置静态属性的,但是WEBPACK打包编译的时候会根据babel-preset-react将其转换为复合规范的语法
    // 以下写法理应报错,但是webpack编译后可正常运行
    ...
    static defaultProps = {
        m: 100
    };
    static propTypes = {
        m: PropTypes.number,
        x: PropTypes.string.isRequired
    };
    ...
    
    • 通过onChange事件实现MVVM双向绑定
    ...
    <input type="text" className='form-control'
          value={text}
          onChange={ev => {
               this.setState({
                    text: ev.target.value
               });
    }}/>
    ...
    

    4.生命周期

    1.第一次调用组件渲染的周期流程
    1.1.给属性设置默认值(设置默认规则)
    1.2.constructor => 设置初始的状态等
    1.3.componentWillMount 第一次挂载之前 => 向服务器发送数据请求
    1.4.render 渲染
    1.5.componentDidMount 第一次挂载之后 => 把虚拟DOM转换为真实DOM了,我们可以获取DOM元素进行操作


    2.当组件状态发生改变 setState
    2.1.shouldComponentUpdate(nextProps, nextState) 是否允许当前组件重新渲染(返回TRUE则继续重新渲染,返回FALSE则停止重新渲染)
    2.2.componentWillUpdate(nextProps, nextState) 重新渲染之前
    2.3.render重新渲染
    2.4.componentWillUpdate 重新渲染之后


    3.当组件属性发生改变:父组件重新传递最新的属性信息
    3.1.componentWillReceiveProps(nextProps, nextState) 在接受最新的属性之前
    3.2....(重复2)


    4.componentWillUnmount 卸载组件之前

    export default class Test extends React.Component {
        constructor(props) {
            super(props);
            console.log('constructor');
            this.state = {
                data: [],
                n: 0
            };
        }
    
        componentWillMount() {
            console.log('componentWillMount');
            setTimeout(() => {
                this.setState({
                    data: [100, 200]
                });
            }, 5000);
        }
    
        render() {
            console.log('render');
            let { data, n } = this.state;
            return <div>
                {data} === {n}
                <button onClick={() => {
                    this.forceUpdate();  <!-- 调用该方法时直接跳过shouldComponentUpdate阶段 -->
                }}>强制更新</button>
            </div>;
        }
    
        componentDidMount() {
            console.log('componentDidMount');
        }
    
        shouldComponentUpdate(nextProps, nextState) {
            console.log('shouldComponentUpdate', nextProps, nextState);
            // nextProps  nextState 最新要修改的属性和状态
            // this.state / this.props 修改之前的
            // this.forceUpdate() 不会执行这个周期函数,会强制更新当前组件
            return true;
        }
    
        componentWillUpdate() {
            console.log('componentWillUpdate');
        }
    
        componentDidUpdate() {
            console.log('componentDidUpdate');
        }
    } 
    

    相关文章

      网友评论

          本文标题:React入门(二)

          本文链接:https://www.haomeiwen.com/subject/qjqbbctx.html