React基础学习(一)

本文介绍了React中的虚拟DOM概念及其与真实DOM的区别,强调了jsx语法在创建虚拟DOM时的规则。同时,详细讲解了组件的state和props的使用,包括初始化、更新及属性限制。此外,还探讨了事件处理机制和ref的运用,以及React组件的生命周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、虚拟DOM和真实DOM
<script type="text/babel"> // 此处一定要写babel!!!!!!!
   // 1. 创建虚拟DOM
   // const VDOM = <h1 id="title">Hello, React!</h1> // 此处一定不要写引号 因为这不是字符串!!!!!!!
   const VDOM = ( // 如果有多层嵌套,使用jsx更加方便快捷 更为符合开发方式
       <h1 id="title">
           <span>Hello, React!</span>
       </h1>
   )

   // 2. 渲染虚拟DOM 参数:虚拟DOM、容器
   ReactDOM.render(VDOM, document.getElementById('box'))


   // ----------------------------------------------------
   const TDOM = document.getElementById('test')
   console.log('虚拟DOM', VDOM) // Object
   console.log('真实DOM', TDOM) // <div id="test"></div>
   debugger;
	
</script>
关于虚拟DOM:
  1. 本质是Object对象(一般对象)
  2. 虚拟DOM比较“轻”(属性和方法少),真实DOM比较“重”(属性和方法多),因为虚拟DOM是React内部在用,无需真实DOM上那么多属性
  3. 虚拟DOM最终都会被React转换为真实DOM,最终呈现在页面。
二、jsx的语法规则
  1. 定义虚拟DOM时,不要用引号
  2. 标签中混入js表达式时,使用{}
  3. 样式的类名指定不能用class,要使用className,因为要与es6中的关键字类(class)做区分
  4. 内联样式,要使用{{key:value}}的形式去写,外层{}表示里边的内容为js,内层{}表示对象
  5. 只能有一个根标签
  6. 标签必须闭合
  7. 标签首字母:
    1)首字母小写开头,则将该标签转为html中的同名元素,若html中无与之对应的同名元素,则报红色警告
    2)首字母大写开头,react会去渲染对应的组件,若组件没有定义,则报错。
<script type="text/babel">
     const myId = 'container'
     const myData = 'Hello, React'
     // 创建虚拟DOM
     const VDOM = (
         <div>
             <h1 className="title" id={myId}>
                 <span style={{color: 'white'}}>{myData}</span>
             </h1> 
             <h1 className="title" id={myId+'2'}>
                 <span style={{color: 'white'}}>{myData}</span>
             </h1> 
             <good>222</good>   // 无与之对应的html标签 会报警告
             // <Good>333</Good>   // 报错 首字母大写表示使用的是组件 Good组件未定义
         </div>
     )
     // 渲染虚拟DOM到页面
     ReactDOM.render(VDOM, document.getElementById('box'))
 </script>
三、组件实例的三大属性
  1. state
<script type="text/babel">
    // 1.创建一个组件
    class Weather extends React.Component {
        
        // 构造器调用几次?------一次
        constructor(props) {
            console.log('constructor')

            super(props)
            // 初始化状态
            // 给state添加属性 就需要在组件实例初始化时赋值
            this.state = {isHot: false, wind: '微风'}
            // 解决changeWeather中this指向问题
            this.changeWeather = this.changeWeather.bind(this)

            // 【this指向问题解释】实际上也可以这么写:
            // 右边的this.changeWeather.bind(this):this指向Weather实例对象,改变(bind)原型对象上changeWeather方法的this指向为 Weather实例对象
            // 左边的this.demo:this指向Weather实例对象,表示初始化给实例对象一个名为demo的方法
            // 把右边的表达式赋值给左边
            // this.demo = this.changeWeather.bind(this)
        }

        // render调用几次?----1+n次,1是初始化调用1次,n是状态更新的次数
        render() {
            console.log('render')

            // 读取状态
            let {isHot, wind} = this.state
            // console.log(this) // this指向的是 Weather 组件实例,state是组件实例的属性 
            // react中的点击事件为onClick(原生为onclick)
            // 此处不使用changeWeather()的原因是:页面一加载时就执行了onClick={changeWeather},相当于直接执行了changeWeather函数体中的内容,所以使用changeWeather 相当于是把changeWeather函数赋值给onClick事件
            return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '寒冷'}{wind}</h1>
            
            // 【this指向问题解释】实际上也可以这么写:
            // 调用的并不是原型对象上的changeWeather,而是初始化时实例对象上的名为demo的方法
            // return <h1 onClick={this.demo}>今天天气很{isHot ? '炎热' : '寒冷'}</h1>
        }

        // changeWeather调用几次?------点几次调几次
        changeWeather() {
            console.log('changeWeather')

            // changeWeather放在了 类Weather的原型对象 上,供实例使用
            // 由于changeWeather作为onClick的回调,所以不是通过实例调用的,是直接调用
            // 类中的方法默认开启了严格模式,所以changeWeather中的this指向为undefined
            // console.log(this)


            const isHot = this.state.isHot
            // 【严重注意】:状态必须要通过setState进行更新,且更新是合并(只更新setState中传入的属性),不是替换(setState中其他未传入的属性不会被删除)。
            this.setState({isHot: !isHot})

            // 【严重注意】:状态(state)不可直接更改,下面这行就是直接更改!!!
            // this.state.isHot = !isHot   // 这是错误的!!!

        }
    }
    // 2.渲染到页面
    ReactDOM.render(<Weather/>, document.getElementById('box'))

</script>
简写方式
<script type="text/babel">
     // 1.创建一个组件
     class Weather extends React.Component {
         // 初始化状态
         // 给Weather的实例对象上直接添加state属性
         state = {isHot: false, wind: '微风'}

         render() {
             let {isHot, wind} = this.state
             return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '寒冷'}{wind}</h1>
         }

         // 自定义方法----使用赋值语句+箭头函数 替代bind方法
         changeWeather = () => {
             const isHot = this.state.isHot
             this.setState({isHot: !isHot})
         }
     }
     // 2.渲染到页面
     ReactDOM.render(<Weather/>, document.getElementById('box'))

 </script>
  1. props
<script type="text/babel">
    // 创建组件
    class Person extends React.Component {
        render() {
            const {name, age, gender} = this.props
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{age}</li>
                    <li>年龄:{gender}</li>
                </ul>
            )
        }
    }

    // 渲染组件到页面
    ReactDOM.render(<Person name="tom" age="28" gender="男"/>, document.getElementById('box1'))

    // ReactDOM.render(<Person name="daisy" age="20" gender="女"/>, document.getElementById('box2'))

    const p = {name: 'daisy', age: '21', gender: "女"}
    // ReactDOM.render(<Person name={p.name} age={p.age} gender={p.gender}/>, document.getElementById('box2'))
    // 下面这种写法(...p)是上面这种写法的语法糖,在组件中的{...p}---{}表示的是里边要写js语句了 并不是对象的意思
    // 在react和babel的共同作用下,是允许使用展开运算法展开一个对象(...p是被允许的)
    ReactDOM.render(<Person {...p}/>, document.getElementById('box2'))
</script>
简写方式
<script type="text/babel">
    // 创建组件
    class Person extends React.Component {
        // 对标签属性进行必要性以及类型限制
        static propTypes = {
            name: PropTypes.string.isRequired, // 限制name必传,且为string类型
            age: PropTypes.number, // 限制age为number类型
            gender: PropTypes.string, // 限制gender为string类型
        }

        // 指定标签属性默认值
        static defaultProps= {
            age: 10, // age默认为10
            gender: '男' // gender默认为男
        }

        render() {
            const {name, age, gender} = this.props
            // props是只读的
            // this.props.name = 'jerry'   // 会报错,因为props是只读的

            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>年龄:{age + 1}</li>
                    <li>性别:{gender}</li>
                </ul>
            )
        }
    }

    // 渲染组件到页面
    ReactDOM.render(<Person name="tom"/>, document.getElementById('box1'))
</script>
函数式组件使用props
<script type="text/babel">
     // 创建组件
     function Person(props) {
         const {name, age, gender} = props
         return (
             <ul>
                 <li>姓名:{name}</li>
                 <li>年龄:{age + 1}</li>
                 <li>性别:{gender}</li>
             </ul>
         )
     }

     // 对标签属性进行必要性以及类型限制
     Person.propTypes = {
         name: PropTypes.string.isRequired, // 限制name必传,且为string类型
         age: PropTypes.number, // 限制age为number类型
         gender: PropTypes.string, // 限制gender为string类型
     }

     // 指定标签属性默认值
     Person.defaultProps= {
         age: 10, // age默认为10
         gender: '男' // gender默认为男
     }
     
     // 渲染组件到页面
     ReactDOM.render(<Person name="tom"/>, document.getElementById('box1'))
 </script>
  1. ref
<script type="text/babel">
    //创建组件
    class Demo extends React.Component{
        // React.createRef 调用后返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”
        myRef = React.createRef()
        myRef2 = React.createRef()

        // 展示左侧数据
        showData = () => {
            alert(this.myRef.current.value)
        }

        // 展示右侧数据
        showData2 = () => {
            alert(this.myRef2.current.value)
        }

        render() {
            return (
                <div>
                    <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />&nbsp;
                    <button onClick={this.showData}>点我提示左侧数据</button>&nbsp;
                    <input ref={this.myRef2} type="text" placeholder="失去焦点提示数据" onBlur={this.showData2}/>
                </div>
            )
        }
    }

    // 渲染组件到页面
    ReactDOM.render(<Demo/>, document.getElementById('box'))
</script>
四、事件处理
<script type="text/babel">
   //创建组件
    class Demo extends React.Component{
        // 创建ref容器
        myRef = React.createRef()
        myRef2 = React.createRef()

        // 展示左侧数据
        showData = () => {
            alert(this.myRef.current.value)
        }

        // 展示右侧数据
        showData2 = (event) => {
            alert(event.target.value)
        }

        render() {
            return (
                <div>
                    <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />&nbsp;
                    <button onClick={this.showData}>点我提示左侧数据</button>&nbsp;
                    <input type="text" placeholder="失去焦点提示数据" onBlur={this.showData2}/>
                </div>
            )
        }
    }

    // 渲染组件到页面
    ReactDOM.render(<Demo/>, document.getElementById('box'))
</script>
事件处理总结:
  1. 通过onXxx属性指定事件处理函数(注意大小写)
    a)React使用的是自定义(合成)事件,而不是使用的原生DOM事件 ----为了更好的兼容性
    b)React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ---- 为了更高效
  2. 通过event.target得到发生事件的DOM元素对象 ---- 不要过度使用ref
五、组件的生命周期(详细代码在下一篇笔记)
旧版与新版对比图示:

react生命周期对比图

附:使用html学习React基础代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>demo</title>
</head>
<body>
    <!-- 准备好一个容器 -->
    <div id="box"></div>

    <!-- 引入react核心库 -->
    <script type="text/javascript" src="https://unpkg.com/react@16/umd/react.development.js"></script> 
    <!-- 引入react扩展库 -->
    <script type="text/javascript" src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转换为js -->
    <script type="text/javascript" src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <!-- 引入prop-types,用于对组件标签的限制 -->
    <script type="text/javascript" src="../../../js/prop-types/prop-types.js"></script>


    <script type="text/babel">
      
    </script>
    
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值