React类组件函数组件&& 组件实例的三大核心属性

本文详细介绍了React中的函数式组件与类式组件的区别,涉及组件实例属性、this指向、state和props的管理,以及ref的使用方法,包括字符串形式和回调形式。通过实例演示了如何定义和操作组件,以及最佳实践和常见注意事项。
摘要由CSDN通过智能技术生成

目录

基本理解和使用

React面向组件编程

函数式组件:

复习类的相关知识

类式组件:

 组件实例的三大核心属性

类中方法的this指向

state

 props

展开运算符

类中的构造器

函数式组件使用props

符串形式的ref

回调形式的ref

createRef创建ref容器·


基本理解和使用

React面向组件编程

函数式组件:

此处this是undefined babel编译后开启了严格模式

执行了 ReactDOM.render(<Demo />, document.getElementById('test'))之后

  • React解析组件标签,找到Demo组件
  • 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM呈现在页面中

<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-dom 用于react操作dom -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- 引入babel 用于jsx转 js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<!-- 一定要写babel -->
<script type="text/babel">
    //创建函数式组件
    function Demo() {
        console.log(this);//undefined 
        return <h2>我是一个函数定义的组件(适用于[简单组件]的定义)</h2>
    }
    //渲染组件到组件
    ReactDOM.render(<Demo />, document.getElementById('test'))
</script>

注意

  1. 组件名必须首字母大写标签
  2. 虚拟DOM元素只能有一个根元素
  3. 虚拟DOM元素必须有结束标签
  4. 函数必须有返回值

复习类的相关知识

  • 类中的构造器,不是必须写的,要对实例进行一些初始化的操作 如添加指定属性时才写
  • 如果子类继承了父类,且子类写了构造器,那么子类构造器中super是必须要定义的
  • 类中所定义的方法,都放在了类的原型对象上供实例使用
  •  a=1 类中可以直接写赋值语句 给实例对象添加一个属性名为a 值为1
  <script>
        //创建一个parson类
        class Parson {
            constructor(name, age) {
                //构造器中的this是实例对象
                this.name = name
                this.age = age
            }
            a=1//类中可以直接写赋值语句 给实例对象添加一个属性名为a 值为1

            // 一般方法
            speak() {
                // spak 放在了类的原型对象上,供实例使用的
                // 通过parson实例调用speak时,speak中的this就是parson实例
                console.log(`我叫${this.name}我的年龄是${this.age}`);
            }
        }
        //  创建一个Student类,继承于Parson类
        class Student extends Parson {
            constructor(name, age, grade) {
                //继承属性必须写super
                super(name, age)
                this.grade = grade
            }
            speak() {
                console.log(`我叫${this.name}我的年龄是${this.age},我的年级是${this.grade}`);
            }
            study() {
                // study 放在了类的原型对象上,供实例使用的
                // 通过Student实例调用study时,study中的this就是Student实例
                console.log('我很努力的学习');
            }
        }

    </script>

类式组件:

必须继承React.Component,要有返回值

必须写render    rouder放在类的原型对象上,供实例实用  this是 组件的实例对象

执行了 ReactDOM.render(<Demo />, document.getElementById('test'))之后

  • React解析组件标签,找到Demo组件
  • 发现组件是使用类定义的,随后new出该类的实例,并通过该实例调用到原型上的render方法
  • 将render返回的虚拟DOM转为真实DOM随后呈现在页面中
<script type="text/babel">
    //创建类组件
    class Demo extends React.Component {
        //   rouder放在类的原型对象上,供实例实用
        //   this是 Demo 的实例对象
        render() {
            return <h2>我是一个类定义的组件(适用于[复杂组件]的定义)</h2>
        }
    }
    ReactDOM.render(<Demo />, document.getElementById('test'))

 组件实例的三大核心属性

类中方法的this指向

通过实例调用this为实例

把方法赋值给x变量相当于把方法赋值给了x变量 这时this发生变化(类中的方法开启局部严格模式)所以为undefined

bind可以生成一个新函数改变this指向

      //创建一个parson类
        class Parson {
            constructor(name, age) {
                this.name = name
                this.age = age
            }
            speak() {
                // spak 放在了类的原型对象上,供实例使用的
                // 通过parson实例调用speak时,speak中的this就是parson实例
                console.log(this);
            }
        }
        const p1 = new Parson()
        p1.speak()//通过实例调用speak方法
        const x = p1.speak
        x() //undefined

state

  1. state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
  2. 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

强烈注意

  1. 组件中render方法中的this为组件实例对象
  2. 组件自定义的方法中thisundefined,如何解决?
    1. 强制绑定this: 通过函数对象的bind()
    2. 箭头函数
  3. 状态数据,不能直接修改或更新,要使用 React.Component 父类提供的setState方法
  4.  构造器执行一次,renderd调用1+n次 1是初始化 n是状态更新的次数  方法点几次调用几次

需求: 定义一个展示天气信息的组件 默认展示天气炎热 或 凉爽 点击文字切换天气

完整版

<script type="text/babel">
    class Weather extends React.Component {
        //构造器执行一次
        constructor(props) {
            super(props)
            this.state = { isHot: true }
            //解决change中的this指向问题(把右侧类中的change修改后的新函数赋值给change)
            this.change = this.change.bind(this)//this为实例
        }

        // renderd调用1+n次 1是初始化 n是状态更新的次数
        render() {
            // 读取状态
            console.log(this);//组件的实例对象
            const { isHot } = this.state
            return <h2 onClick={this.change} > 天气很{isHot ? '炎热' : '凉爽'}</h2 >
        }

        //点几次调用几次
        change() {
            //change放在 Weather 的实例对象上
            //由于 change 是作为onClick的回调所以不是通过实例调用的,是直接调用
            //类中的方法默认开启局部严格模式所以change中的this为 undefined

            //获取原来的 isHot 值
            const isHot = this.state.isHot
            // 状态数据,不能直接修改或更新,要使用 React.Component 父类提供的setState方法.且更新是一种合并,不是替换

            this.setState({ isHot: !isHot })


            // //状态不可以直接更改
            // this.state.isHot = !isHot

        }
    }
    ReactDOM.render(<Weather />, document.getElementById('test'))

简化版

<!-- 一定要写babel -->
<script type="text/babel">
    class Weather extends React.Component {
        //初始化状态 给实例对象添加
        state = { isHot: true }
        render() {
            const { isHot } = this.state
            return <h2 onClick={this.change} > 天气很{isHot ? '炎热' : '凉爽'}</h2 >
        }
        //自定义方法--->赋值语句+箭头函数,放在实例身上
        change = () => {
            const isHot = this.state.isHot
            this.setState({ isHot: !isHot })
        }
    }
    ReactDOM.render(<Weather />, document.getElementById('test'))

</script>

 props

  1. 每个组件对象都会有props(properties的简写)属性
  2. 组件标签的所有属性都保存在props中
  3. 通过标签属性从组件外向组件内传递变化的数据
  4. 注意: 组件内部不要修改props数据

展开运算符

  • [...arr1, ...arr2] 连接数组
  • let obj2 = { ...obj } 构建字面量对象时使用展开运算符,展开运算符不能展开对象
  •  合并  let obj3 = { ...obj, name: 'lisa', address: '地球' }
  • reduce  依次迭代数组每一项,他会把上一次迭代中,回调函数处理的结果传递给下一次迭代,以此实现结果的累积 a之前的值,b当前的值 有返回值
    <script>
        let arr1 = [1, 3, 5, 7, 9]
        let arr2 = [2, 4, 6, 8, 10]
        console.log(...arr1);//展开一个数组

        let arr3 = [...arr1, ...arr2]

        console.log(arr3);//连接数组

        //在函数中使用
        function sum(...numbers) {
            // 依次迭代数组每一项,他会把上一次迭代中,回调函数处理的结果传递给下一次迭代,以此实现结果的累积 a之前的值,b当前的值 有返回值
            return numbers.reduce((a, b) => {
                console.log(a, b);
                return a + b
            })
        }
        console.log(sum(sum(1, 2, 3, 4)));

        //构建字面量对象时使用展开运算符
        let obj = { name: 'tom', age: 18 }
        // console.log(...obj);//展开运算符不能展开对象

        let obj2 = { ...obj }
        console.log(obj2);//克隆一个对象

        //合并
        let obj3 = { ...obj, name: 'lisa', address: '地球' }
        console.log(obj3);
    </script>

编码操作

  1. 内部读取某个属性值 this.props.name
  2. props中的属性值进行类型限制和必要性限制

3.扩展属性: 将对象的所有属性通过props传递 <Person{...p} />

4. 默认属性值:

5.组件类的构造函数

 

效果

需求: 自定义用来显示一个人员信息的组件

  1. 姓名必须指定,且为字符串类型;
  2. 性别为字符串类型,如果性别没有指定,默认为男
  3. 年龄为字符串类型,且为数字类型,默认值为18

 完整版

<!-- prop-types 用于对组件标签属性进行限制 -->

<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-dom 用于react操作dom -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- 引入babel 用于jsx转 js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<!-- prop-types 用于对组件标签属性进行限制 -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 一定要写babel -->
<script type="text/babel">
    class Person extends React.Component {

        render() {
            console.log(this);
            const { name, age, sex } = this.props
            // this.props.name = 'ls' 此处会报错,因为props是只读的
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{age}</li>
                    <li>年龄:{sex}</li>
                </ul>
            )
        }

    }
    const p = { name: 'tom', age: 18, sex: '女' }
    //对标签属性进行类型,必要性的限制
    Person.propTypes = {
        name: PropTypes.string.isRequired,//限制name 必传,且为字符串
        age: PropTypes.number,
        sex: PropTypes.string,
        speak: PropTypes.func,//限制 speak 为函数
    }

    //指定默认标签属性值
    Person.defaultProps = {
        sex: '女',//sex默认值为女
        age: 18
    }

    // ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex} />, document.getElementById('test'))
    ReactDOM.render(<Person{...p} speak={speak} />, document.getElementById('test'))
    function speak() {
        console.log('我说话了');
    }

简写

  •  status={}直接在类里写相当于给实例对象添加属性方法
  • static 相当于给类加属性和方法
<script type="text/babel">
    class Person extends React.Component {
        render() {
            console.log(this);
            const { name, age, sex } = this.props
            // this.props.name = 'ls' 此处会报错,因为props是只读的
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{age}</li>
                    <li>年龄:{sex}</li>
                </ul>
            )
        }
        //对标签属性进行类型,必要性的限制
        static propTypes = {
            name: PropTypes.string.isRequired,//限制name 必传,且为字符串
            age: PropTypes.number,
            sex: PropTypes.string,
            speak: PropTypes.func,//限制 speak 为函数
        }

        //指定默认标签属性值
        static defaultProps = {
            sex: '女',//sex默认值为女
            age: 18
        }
    }
    const p = { name: 'tom', age: 18, sex: '女' }
    ReactDOM.render(<Person{...p} speak={speak} />, document.getElementById('test'))
    function speak() {
        console.log('我说话了');
    }

类中的构造器

 //构造器中是否接收props 是否传递给super 取决于是否希望在构造器中通过this访问props

  class Person extends React.Component {
        constructor(props) {
            //构造器中是否接收props 是否传递给super 取决于是否希望在构造器中通过this访问props
            super(props)
            console.log(this.props);
        }

        //对标签属性进行类型,必要性的限制
        static propTypes = {
            name: PropTypes.string.isRequired,//限制name 必传,且为字符串
            age: PropTypes.number,
            sex: PropTypes.string,

        }

        //指定默认标签属性值
        static defaultProps = {
            sex: '女',//sex默认值为女
            age: 18
        }
        render() {
            console.log(this);
            const { name, age, sex } = this.props
            // this.props.name = 'ls' 此处会报错,因为props是只读的
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{age}</li>
                    <li>年龄:{sex}</li>
                </ul>
            )
        }

    }

    ReactDOM.render(<Person name="lisa" />, document.getElementById('test'))

函数式组件使用props

可以通过形参接收props 

限制标签属性要写在外面,函数组件没有static

<script type="text/babel">

    function Person(props) {
        const { name, age, sex } = props
        return (
            <ul>
                <li>姓名:{name}</li>
                <li>性别:{age}</li>
                <li>年龄:{sex}</li>
            </ul>
        )
    }
    Person.propTypes = {
        name: PropTypes.string.isRequired,//限制name 必传,且为字符串
        age: PropTypes.number,
        sex: PropTypes.string,
        speak: PropTypes.func,//限制 speak 为函数
    }

    //指定默认标签属性值
    Person.defaultProps = {
        sex: '女',//sex默认值为女
        age: 18
    }
    ReactDOM.render(<Person name="lisa" />, document.getElementById('test'))

</script>

符串形式的ref

  • 组件内的标签可以定义ref属性来标识自己
  • refs获取真实dom元素
  • 字符串的ref存在效率问题不推荐使用
 //创建类组件
    class Demo extends React.Component {

        render() {
            return (
                <div>
                    <input ref="input1" type="text" placeholder="点我提示数据" />
                    <button onClick={this.showData}>点我提示左侧的数据</button>
                    <input ref="input2" type="text" onBlur={this.showData2} placeholder="失去焦点提示数据" />
                </div>
            )
        }
        //展示左侧输入框数据
        showData = () => {
            console.log(this.refs);
            const { input1 } = this.refs
            alert(input1.value)
        }
        //展示右侧输入框数据
        showData2 = () => {
            console.log(this.refs);
            const { input2 } = this.refs
            alert(input2.value)

        }

    }
    ReactDOM.render(<Demo />, document.getElementById('test'))

回调形式的ref

  • 回调 自己定义的,自己没调用 函数最终执行了
  • 把ref当前所在节点挂在实例自身上  const { input2 } = this
  • 如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素,这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的
  • 过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,
 <div>
<input ref={c => this.input1 = c} type="text" placeholder="点我提示数据" />
<button onClick={this.showData}>点我提示左侧的数据</button>
<input onBlur={this.showData2} ref={c => this.input2 = c} type="text" placeholder="点我提示数据" />
 <input onBlur={this.showData2} ref={this.saveInput} type="text" placeholder="点我提示数据" />

 </div>
saveInput = (c) => {
 this.input = c
 console.log('@', c);
 }

createRef创建ref容器·

  •    //React.createRef 调用后可以返回一个容器,该容器可以存储被ref所标识的节点
  •    //该容器是专人专业的
  class Demo extends React.Component {
        render() {
            return (
                <div>
                    <input ref={this.myRef} type="text" placeholder="点我提示数据" />
                    <button onClick={this.showData}>点我提示左侧的数据</button>

                </div>
            )
        }
        //React.createRef 调用后可以返回一个容器,该容器可以存储被ref所标识的节点
        //该容器是专人专业的
        myRef = React.createRef()
        //展示左侧输入框数据
        showData = () => {
            console.log(this.myRef.current.value);

        }
    }
    ReactDOM.render(<Demo />, document.getElementById('test'))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值