美文网首页
React01-开始

React01-开始

作者: 我也不知道啊丶 | 来源:发表于2019-01-04 20:37 被阅读0次

    在记录react的学习之路开始,我想先谈谈为什么会有react
    假如有一个页面,页面上有一个dom,要操作这个dom的内容,有如下步骤:

    1. 在js中获取dom
    2. 修改dom的内容
    3. 把内容回填到dom里,通知页面更新

    代码示例:

    <body>
        <span id="result">0</span>
        <button id="add">+</button>
        <button id="minus">-</button>
    </body>
    <script>
        let result = document.querySelector('#result')
        let add = document.querySelector('#add')
        let minus = document.querySelector('#minus')
    
        add.addEventListener('click',function(){
            let number = parseInt(result.innerHTML,10)
            number += 1
            result.innerHTML = number
        })
    
        minus.addEventListener('click',function(){
            let number = parseInt(result.innerHTML,10)
            number -= 1
            result.innerHTML = number
        })
    </script>
    

    这段代码就是从页面获取dom,接着修改dom内容然后回填到dom里去
    虽然简单,但是 可能有点繁琐
    那么有没有可能省略其中的某些步骤呢
    很明显
    修改内容、把内容回填到dom中不能省略
    那么就只能把获取dom省去
    既然不获取dom,那么干脆开始在页面中就不写dom,等操作完数据(内容)后直接插入页面中就行了
    于是,有了react.js

    正式开始之前

    在正式开始之前,想说一下jsx
    jsx可以让你像写html一样写js

    <div className='box'>
        <span className='num'>{变量}</span>
        <button onClick={函数}>+</button>
        <button onClick={函数}>-</button>
    </div>
    

    比如这段代码,看起来是不是很神奇又很眼熟?
    我们来用React来改写最初的那个功能

    <body>
        <div id='root'>
    
        </div>
    </body>
    // html部分就写完了,只需要一个id告诉React虚拟DOM该插到哪里
    <script>
        let number = 0;
        function add(){
            number += 1;
            render()
        }
        function minus(){
            number -= 1;
            render()
        }
        render()
        function render(){
            ReactDOM.render(
                <div>
                    <span>{number}</span>
                    <button onClick={add}>+</button>
                    <button onClick={minus}>-</button>
                </div>,
                document.getElementById('root')
            )
        }
    

    ok,就这样写完了一个
    逻辑是不是比上面的版本清晰很多?
    React牛逼的地方不仅如此
    还是来看看上面的代码,因为只是实现一个很简单的功能,所以ReactDOM.render里只用写那几行代码,
    如果是构建一个大型页面呢?如果还是用这种方法,那么ReactDOM.render里可能就要写几千行代码来描述DOM,这是不能忍受的,维护起来也十分麻烦,所以需要一个东西把这些结构分块包裹起来
    最简单的就是用函数包裹,来看看

    function App(){
        return (
            <div>
                <span>{number}</span>
                <button onClick={add}>+</button>
                <button onClick={minus}>-</button>
            </div>
        )
    }
    

    然后下面改成

    function render(){
        ReactDOM.render(
            React.createElement(App),
            document.getElementById('root')
        )
    }
    

    React.createElement()用来创造虚拟DOM
    但是我们用的是JSX,所以可以改成下面这种写法

    function render(){
        ReactDOM.render(
            <App />,
            document.getElementById('root')
        )
    }
    

    再往下看,如果页面上有多个这种功能

    function App(){
        return (
            <div>
                <box1 />
                <box2 />
            </div>
        )
    }
    function Box1(){
        return (
            <div>
                <span>{number}</span>
                <button onClick={add}>+</button>
                <button onClick={minus}>-</button>
            </div>
        )
    }
    function Box2(){
        return (
            <div>
                <span>{number}</span>
                <button onClick={add}>+</button>
                <button onClick={minus}>-</button>
            </div>
        )
    }
    

    最简单的React的函数组件
    这样写会有一个问题,当点击box1中的+按钮时,box2里面的值也会跟着改变,要解决这个问题,最简单的方法就是再声明一个变量和函数来分别给box1box2调用,但是如果页面上有多个相同的功能模块呢?那就得声明多个一样的变量和函数,这样的代码明显是不好的。
    先来看看如何给函数传参

    function App(){
        return (
            <div>
                <box1 name='加一' />
                <box2 />
            </div>
        )
    }
    function Box1(obj){
        return (
            <div>
                我的name是:{obj.name}
                <span>{number}</span>
                <button onClick={add}>+</button>
                <button onClick={minus}>-</button>
            </div>
        )
    }
    

    注意,在React里,最好不要在函数里修改传入的属性
    再回头来看上面的问题,想想在js里,有什么东西既能满足函数的功能,又有自己的作用域

    要注意的是,在React里使用class,必须要继承 React.Component

    class App2 extends React.Component{
        render(){ //局部render
            return(
                <div>
                    {this.props.name}
                </div>
        )
    }
    function render(){
        ReactDOM.render(
            <App2 name='我是App2'/>,
            document.getElementById('root')
        )
    }
    

    props是由继承的React.Component构造的,必须使用
    来设置一下自己的局部变量

    class App2 extends React.Component{
        constructor(props){  //必须这样写
            super(props) //必须加上这句
            this.state = {
                number : 0
            }
        }
        add(){
            this.setState({ //必须写在this.setState里,为什么可以看ES6里的set和get
                number : this.state.number + 1 //如果这里要使用this.state.number,在下面引用函数时必须使用this.add.bin(this)或() => this.add
            })
        }
        minus(){
            this.setState({
                number : this.state.number - 1
            })
        }
        render(){ //局部render
            return(
                <div>
                    {this.props.name}
                    <br/>
                    <span>{this.state.number}</span>
                    <button onClick={this.add.bind(this)}>+</button>
                    <button onClick={this.minus.bind(this)}>-</button>
                </div>
            )
        }
    }
    
    function render(){
        ReactDOM.render(
            <App2 name='我是App2'/>,
            document.getElementById('root')
        )
    }
    

    可以看到虽然class的功能更加强大,但是React里使用class的规则有一点多,目前有如下几点:

    1. class必须extends React.Component
    2. class里的局部变量必须写在constructorthis.state={变量的key:变量的value}里,并且必须要在constructor里写this.state={}
    3. constructor里的第一行必须是super()这个是ES6的规定
    4. 如果要在class的函数里操作this.state={}里的变量,必须用this.setState({修改变量})
    5. 外部传入的值默认挂在props下,props是父类React.Component构造出来的一个属性,使用时用{this.props.键名}
    6. 如果要在函数里使用this.state={}里的变量,用this.state.变量名这种方法时,在调用函数时必须用
      this.函数名.bind(this)或者() =>this.函数名,这是因为React默认在调用函数时是以函数.call(undefined,方法),所以如果不用bind()传入this或者用箭头函数,this就会是undefined
    function App(){
        return (
            <div>
                <Box1 name='我是class1' />
                <Box2 name='我是class2' />
            </div>
        )
    }
    
    class Box1 extends React.Component{
        constructor(props){
            super(props)
            this.state = {
                number : 0
            }
        }
        add(){
            this.setState({
                number : this.state.number + 1
            })
        }
        minus(){
            this.setState({
                number : this.state.number - 1
            })
        }
        render(){
            return (
                <div className='box1'>
                    <p>{this.props.name}</p>
                    <span>{this.state.number}</span>
                    <button onClick={this.add.bind(this)}>+</button>
                    <button onClick={this.minus.bind(this)}>-</button>
                </div>
            )
        }
    }
    
    class Box2 extends React.Component{
        constructor(props){
            super(props)
            this.state = {
                number : 0
            }
        }
        add(){
            this.setState({
                number : this.state.number + 2
            })
        }
        minus(){
            this.setState({
                number : this.state.number - 2
            })
        }
        render(){
            return (
                <div className='box2'>
                    <p>{this.props.name}</p>
                    <span>{this.state.number}</span>
                    <button onClick={this.add.bind(this)}>+2</button>
                    <button onClick={this.minus.bind(this)}>-2</button>
                </div>
            )
        }
    }
    
    function render(){
        ReactDOM.render(
            <App />,
            document.getElementById('root')
        )
    }
    
    render()
    

    React的class组件
    来说一下为什么在函数中不自己render()而是用setState({})
    如果是自己来render(),可能会在短时间内多次render(),导致页面卡顿
    setState({})会将大批量的更新合并成一次(很有可能是异步更新)

    相关文章

      网友评论

          本文标题:React01-开始

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