react中组件实例的三大核心属性(state、props、refs)

1、state

1.1、 理解:

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

1.2、案例

** 需求:**定义一个展示天气信息的组件

  1. 默认展示天气炎热 或 凉爽
  2. 点击文字切换天气

  代码示例:

<body>
<div id="test"></div>

<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
    //1、创建组件
    class Weather extends React.Component {
        //构造器调用几次?----1次
        constructor(props) {
            super(props);
            //初始化状态
            this.state = {isHot: false, wind: '微风'};
            //解决this指向问题
            this.demo = this.changeWeather.bind(this);
        }

        //render调用几次?----1+n次,1是初始化那次,n是状态更新的次数
        render() {
            console.log(this);
            const {isHot, wind} = this.state
            return <h1 onClick={this.demo}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
        }

        //changeWeather调用几次?---点几次调几次
        changeWeather() {
            //changeWeather放在了哪里?放在了类的原型对象上,供实例应用
            //由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用的
            //类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
            console.log(this);//在constructor中修改了this的指向后,this指向实例对象
            //获取原来的isHot的值
            let isHot = this.state.isHot
            //状态不可直接更改,要借助一个内置的API更改,setState
            this.setState({isHot: !isHot});
        }
    }

    //2、渲染组件到页面
    ReactDOM.render(<Weather/>, document.getElementById('test'));
</script>
</body>

  运行结果:

在这里插入图片描述
在这里插入图片描述
上述代码的简写:

<script type="text/babel">
//    1、创建类组件
    class Weather extends React.Component {
        //初始化状态
        state = {isHot: false, wind: '微风'};
        //自定义方法--赋值语句的形式+箭头函数
        changeWeather = () => {
            let isHot = this.state.isHot
            this.setState({isHot: !isHot});
        }

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

    //2、渲染组件到页面
    ReactDOM.render(<Weather/>, document.getElementById('test'));
</script>

1.3、注意:

  1. 组件中render方法中的this为组件实例对象
  2. 组件自定义的方法中this为undefined,如何解决?
    a) 在构造函数中强制绑定this: 通过函数对象的bind() constructor(props) { super(props); this.demo = this.changeWeather.bind(this); }
    b) 使用箭头函数(赋值语句+箭头函数的形式) changeWeather = () => { }
    c)在render中绑定this return <h1 onClick={this.changeWeather.bind(this)}>xxxxx</h1>
    d)在render中使用箭头函数 return <h1 onClick={()=>this.changeWeather()}>xxxxx</h1>
  3. 状态数据,不能直接修改或更新必须通过setState修改,且更新是一种合并,不是替换。setState是异步的

2、props

2.1、理解:

  1. 每个组件对象都会有props(properties的简写)属性
  2. 组件标签的所有属性都保存在props中

2.2、作用:

  1. 通过标签属性从组件外向组件内传递变化的数据
  2. 注意: 组件内部不要修改props数据

2,3、案例:

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

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

方法1:通过类式组件实现

<body>
<div id="test"></div>
<div id="test1"></div>
<div id="test2"></div>


<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<script src="../js/babel.min.js"></script>
<!--引入prop-types,用于对组件标签属性进行限制-->
<script src="../js/prop-types.js"></script>
<script type="text/babel">
    //   创建组件
    class Person extends React.Component {
        //通过静态属性static,将限制加在类本身,而不是实例对象上
        //对标签属性进行类型,必要性的限制
        static propTypes = {
            name: PropTypes.string.isRequired,//限制name必传且为字符串
            sex: PropTypes.string,
            age: PropTypes.number,
            speak: PropTypes.func//限制speak为函数
        }
        //指定标签属性默认值
        static defaultProps = {
            sex: '不男不女',
            age: 18
        }

        render() {
            //props是只读的
            // this.props.name='张三李四';//这样会报错
            const {name, age, sex} = this.props
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>年龄:{age + 1}</li>
                    <li>性别:{sex}</li>
                </ul>
            )
        }
    }

    ReactDOM.render(<Person name="小王"  sex="男" speak={speak}></Person>, document.getElementById('test'))
    ReactDOM.render(<Person name="小李" age={28} sex="女"/>, document.getElementById('test1'))
    //批量传递属性
    const p = {name: "小赵", age: 16}
    ReactDOM.render(<Person {...p}/>, document.getElementById('test2'))

    function speak() {
        console.log('我说哈了');
    }
</script>
</body>

方法2:通过函数式组件实现

<body>
<div id="test1"></div>


<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<script src="../js/babel.min.js"></script>
<!--引入prop-types,用于对组件标签属性进行限制-->
<script src="../js/prop-types.js"></script>
<script type="text/babel">
    //   1、创建组件
    function Person(props) {
        const {name, age, sex} = props;
        return (
            <ul>
                <li>姓名:{name}</li>
                <li>年龄:{age + 1}</li>
                <li>性别:{sex}</li>
            </ul>
        )
    }

    //通过静态属性static,将限制加在类本身,而不是实例对象上
    //对标签属性进行类型,必要性的限制
    Person.propTypes = {
        name: PropTypes.string.isRequired,//限制name必传且为字符串
        sex: PropTypes.string,
        age: PropTypes.number,
        speak: PropTypes.func//限制speak为函数
    }
    //指定标签属性默认值
    Person.defaultProps = {
        sex: '不男不女',
        age: 18
    }
    ReactDOM.render(<Person name="小李"/>, document.getElementById('test1'))

</script>
</body>

运行结果:
在这里插入图片描述

注意:

  1. props只允许读,不允许改

3、ref

3.1、理解

  组件内的标签可以定义ref属性来标识自己

3.2、案例

需求: 自定义组件, 功能说明如下:

  1. 点击按钮, 提示第一个输入框中的值
  2. 当第2个输入框失去焦点时, 提示这个输入框中的值

  实现请查看 ref使用方式

3.3、使用方式

3.3.1、字符串形式的ref

注意:不推荐使用,它已过时并可能会在未来的版本被移除

 //创建组件
    class Demo extends React.Component {

        showDate = () => {
            const {input1} = this.refs
            alert(input1.value)
        }
        showDate2 = () => {
            const {input2} = this.refs
            alert(input2.value)
        }

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

    ReactDOM.render(<Demo/>, document.getElementById('test'))
3.3.2、回调形式的ref
//创建组件
    class Demo extends React.Component {

        showDate = () => {
            const {input1} = this
            alert(input1.value)
        }
        showDate2 = () => {
            const {input2} = this
            alert(input2.value)
        }

        render() {
            return (
                <div>
                    {/*this指向创建的这个实例对象*/}
                    <input ref={(currentNode)=>{this.input1=currentNode}} type="text" placeholder="点击按钮提示数据"/>&nbsp;
                    <button onClick={this.showDate}>点击我提示左侧的数据</button>
                    &nbsp;
                    <input ref={(currentNode)=>{this.input2=currentNode}} onBlur={this.showDate2} type="text" placeholder="失去焦点提示数据"/>
                </div>
            )
        }
    }

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

关于回调refs调用几次的问题:

  如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。

案例

<body>
<div id="test"></div>

<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
    //创建组件
    class Demo extends React.Component {
        state = ({isHot: true})

        showDate = () => {
            const {input1} = this
            alert(input1.value)
        }
        changeWeather = () => {
            this.setState({
                isHot: !this.state.isHot
            })
        }

        render() {
            return (
                <div>
                    <h2>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h2>
                    <input ref={(currentNode) => {
                        this.input1 = currentNode;
                        console.log('@@', currentNode)
                    }} type="text" placeholder="点击按钮提示数据"/>&nbsp;
                    <button onClick={this.showDate}>点击我提示输入的数据</button>
                    <button onClick={this.changeWeather}>点我切换天气</button>
                </div>
            )
        }
    }

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

</script>
</body>

在这里插入图片描述

  通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。

saveInput = (currentNode) => {
            this.input1 = currentNode;
            console.log('@@', currentNode)
        }

        render() {
            return (
                <div>
                    <input ref={this.saveInput} type="text" placeholder="点击按钮提示数据"/>&nbsp;
                </div>
            )
        }

3.3.3、createRef创建ref容器

  React.createRef()调用后可以返回一个容易,该容器可以存储被ref所标识的节点。此方式是最新的,官方所推荐的

<body>
//创建组件
    class Demo extends React.Component {
        myRef=React.createRef();
        myRef2=React.createRef();

        showDate = () => {
            alert(this.myRef.current.value)
        }
        showDate2 = () => {
            alert(this.myRef2.current.value)
        }

        render() {
            return (
                <div>
                    <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>&nbsp;
                    <button onClick={this.showDate}>点击我提示左侧的数据</button>
                    &nbsp;
                    <input ref={this.myRef2} onBlur={this.showDate2} type="text" placeholder="失去焦点提示数据"/>
                </div>
            )
        }
    }
    ReactDOM.render(<Demo/>, document.getElementById('test'))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值