React——组件的三大核心属性【七】

简介: React——组件的三大核心属性【七】

前言

组件的三大核心属性

内容

state

定义一个展示天气信息组件,通过点击切换天气信息

理解

  1. state是组件对象最重要的属性,值是对象(可以包含多key-value组合)
  2. 组件被称为状态机,通过更新组件的state来重新渲染组件
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test">
</div>
<!--引入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>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
class Weather extends React.Component {
    //调用1次
    constructor(props) {
        super(props);
        //初始化状态
        this.state = { isHot: true };
        //解决changeWeather的指向问题
        this.changeWeather = this.changeWeather.bind(this)
    }
    //调用次数1+n 1是初始化,n是状态更新
    render() {
        console.log(this)
        //读取状态
        const {isHot} = this.state
        return (
            <div>
               <h1 onClick={this.changeWeather}>今天天气 {isHot ? '热热' : '不热热'}</h1>
            </div>
        );
    }
    //点击几次调用几次
    changeWeather(){
        //状态不可直接更改需要借助内置方法(setState)进行更改
        const isHot = this.state.isHot
        this.setState({isHot:!isHot})
    }
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
</body>
</html>

简写

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test">
</div>
<!--引入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>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
class Weather extends React.Component {
    
    render() {
        const {isHot} = this.state
        return (
            <div>
               <h1 onClick={this.changeWeather}>今天天气 {isHot ? '热热' : '不热热'}</h1>
            </div>
        );
    }
    //赋值语句+箭头函数
    changeWeather = () => {
        const isHot = this.state.isHot
        this.setState({isHot:!isHot})
    }
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
</body>
</html>

注意点

1. 组件中的render方法中的this为组件实例对象
2. 组件中自定义的方法中的为undefined,如何解决?
   2.1 前置绑定this:通过函数对象的bind()
   2.2 赋值语句+箭头函数
3. 状态数据,不能直接修改或更新,需通过setState来变更

props

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

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

理解

  1. 每个组件对象都会有props(properties)属性
  2. 组件标签的所有属性都保存在props中
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<div id="test1"></div>
<div id="test2"></div>
<!--引入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>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
class Person extends React.Component {
    render() {
        //props是只读的,不可进行修改
        const {name,age,sex} = this.props
        return (
            <div>
                <ul>
                    <li>姓名:{name}</li>
                    <li>年龄:{age}</li>
                    <li>性别:{sex}</li>
                </ul>
            </div>
        );
    }
}
//对标签属性进行类型,必要性限制
Person.protoType = {
    name: PropTypes.string.isRequired, // 限制name必传且类型为string
    age: PropTypes.number,
    sex: PropTypes.string,
    speak: PropTypes.func
}
//指定默认标签属性值
Person.defaultProps = {
    sex: "男",
    age: 18
}
function speak() {
    return "哈哈哈哈"
}
//2.渲染组件到页面
const p = {name:"张三", age:66, sex:'男'}
ReactDOM.render(<Person name="tom" age={19} sex="男" speak={speak}/>,document.getElementById('test'))
ReactDOM.render(<Person name="jim" age="10" sex="男"/>,document.getElementById('test1'))
//语法糖
ReactDOM.render(<Person {...p}/>,document.getElementById('test2'))
</script>
</body>
</html>

简写

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<div id="test1"></div>
<div id="test2"></div>
<!--引入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>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
class Person extends React.Component {
    // constructor(props) {
    //     //构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
    //     super(props);
    // }
    //对标签属性进行类型,必要性限制
    static protoType = {
        name: PropTypes.string.isRequired, // 限制name必传且类型为string
        age: PropTypes.number,
        sex: PropTypes.string
    }
    //指定默认标签属性值
    static defaultProps = {
        sex: "男",
        age: 18
    }
    render() {
        //props是只读的,不可进行修改
        const {name,age,sex} = this.props
        return (
            <div>
                <ul>
                    <li>姓名:{name}</li>
                    <li>年龄:{age}</li>
                    <li>性别:{sex}</li>
                </ul>
            </div>
        );
    }
}
ReactDOM.render(<Person name="tom" />,document.getElementById('test'))
</script>
</body>
</html>

函数式组件使用props

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<div id="test1"></div>
<div id="test2"></div>
<!--引入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>
<script type="text/babel">/*一定要以text/babel来声明*/
//1. 创建组件
function Person(props) {
    const {name, age, sex} = props
    return (
        <div>
            <ul>
                <li>姓名:{name}</li>
                <li>年龄:{age}</li>
                <li>性别:{sex}</li>
            </ul>
        </div>
    )  ;
}
    //对标签属性进行类型,必要性限制
     Person.protoType = {
        name: PropTypes.string.isRequired, // 限制name必传且类型为string
        age: PropTypes.number,
        sex: PropTypes.string
    }
    //指定默认标签属性值
     Person.defaultProps = {
        sex: "男",
        age: 18
    }
ReactDOM.render(<Person name="tom" sex="女" age={18}/>,document.getElementById('test'))
</script>
</body>
</html>

注意点

1. 通过标签属性从组件外向组件内传递变化的数据
2. 注意: 组件内部不要修改props数据
3. 内部通过this.props.xx读取某个属性值
4. props中的属性值进行类型限制和必要性限制
   4.1 React v15.5 开始已弃用
        Person.propTypes = {
         name: React.PropTypes.string.isRequired,
         age: React.PropTypes.number
        }
   4.2 使用prop-types库进限制(需要引入prop-types库)
       Person.propTypes = {
        name: PropTypes.string.isRequired,
        age: PropTypes.number. 
       }
5. 扩展属性: 将对象的所有属性通过props传递
   <Person {...person}/>
6. 默认属性值
   Person.defaultProps = {
    age: 18,
    sex:'男'
   }

ref

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

理解

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

字符串类型ref

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入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>
<script type="text/babel">/*一定要以text/babel来声明*/
class Demo extends React.Component {
    //左侧
    showData = () => {
        const { input1 } = this.refs
        alert(input1.value)
    }
    //右侧
    showData2 = () => {
        const { input2 } = this.refs
        alert(input2.value)
    }
    render() {
        return (
            <div>
                <input ref="input1" type="text" placeholder="点击按钮提示数据"/> &nbsp;
                <button  onClick={this.showData}>点我提示左侧数据</button>
                <br/>
                <hr/>
                <input onBlur={this.showData2} ref="input2" type="text" placeholder="失去焦点提示数据"/>
            </div>
        );
    }
}
ReactDOM.render(<Demo/>, document.getElementById("test"))
/**
 * string类型的ref是过时的API
 * https://react.docschina.org/docs/refs-and-the-dom.html#legacy-api-string-refs
 *
 * https://github.com/facebook/react/pull/8333#issuecomment-271648615
 */
</script>
</body>
</html>

回调函数类型ref

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入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>
<script type="text/babel">/*一定要以text/babel来声明*/
class Demo extends React.Component {
    //左侧
    showData = () => {
        const {input1} = this
        alert(input1.value)
    }
    //右侧
    showData2 = () => {
        const {input2} = this
        alert(input2.value)
    }
    render() {
        return (
            <div>
                <input ref={currentNode => this.input1 = currentNode} type="text" placeholder="点击按钮提示数据"/> &nbsp;
                <button  onClick={this.showData}>点我提示左侧数据</button>
                <br/>
                <hr/>
                <input  ref={currentNode => this.input2 = currentNode} onBlur={this.showData2}  type="text" placeholder="失去焦点提示数据"/>
            </div>
        );
    }
}
ReactDOM.render(<Demo />, document.getElementById("test"))
</script>
</body>
</html>

如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入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>
<script type="text/babel">/*一定要以text/babel来声明*/
class Demo extends React.Component {
    state = {isHot:true}
    changeWeather = () => {
        const {isHot} = this.state
        this.setState({isHot:!isHot})
    }
    //左侧
    showData = () => {
        const {input1} = this
        alert(input1.value)
    }
    saveInput = (c) => {
        this.input1 = c;
        console.log('@',c);
    }
    render() {
        const {isHot} = this.state
        return (
            <div>
                <h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2>
                <button onClick={this.changeWeather}>点击切换天气</button>
                {/*<input ref={(currentNode) => { this.input1 = currentNode; console.log('@',currentNode);} }  type="text" placeholder="点击按钮提示数据"/> &nbsp;*/}
                <input ref={this.saveInput}  type="text" placeholder="点击按钮提示数据"/> &nbsp;
                <button  onClick={this.showData}>点我提示左侧数据</button>
            </div>
        );
    }
}
ReactDOM.render(<Demo />, document.getElementById("test"))
</script>
</body>
</html>

createRef

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入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>
<script type="text/babel">/*一定要以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>
                <input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="=失去焦点显示数据"/> &nbsp;
            </div>
        );
    }
}
ReactDOM.render(<Demo />, document.getElementById("test"))
</script>
</body>
</html>

注意点

1.  string类型的ref是过时的API,可能会在未来版本被移除,建议使用回调函数或createRef API来代替。
    <input ref="input1"/>
2. 回调函数类型的ref
   <input ref={(c)=>{this.input1 = c}} />
   2.1 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素
       <input ref={this.saveInput} /> //通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题
3. createRef创建ref容器
   myRef = React.createRef() 
   <input ref={this.myRef}/>

事件处理

1.通过onXxx属性指定事件处理函数(注意大小写)
  1) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件___兼容性
  2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)___高效性
2.通过event.target得到发生事件的DOM元素对象___不要过度使用ref
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!--创建"容器"-->
<div id="test"></div>
<!--引入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>
<script type="text/babel">/*一定要以text/babel来声明*/
class Demo extends React.Component {
    /**
     1. 通过onXxx属性指定事件处理函数(注意大小写)
         1) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件___兼容性
         2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)___高效性
     2. 通过event.target得到发生事件的DOM元素对象___不要过度使用ref
     *
     */
    // 创建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>
                <input onBlur={this.showData2} type="text" placeholder="=失去焦点显示数据"/> &nbsp;
            </div>
        );
    }
}
ReactDOM.render(<Demo />, document.getElementById("test"))
</script>
</body>
</html>

学无止境,谦卑而行.

目录
相关文章
|
12天前
|
前端开发 UED 开发者
React 悬浮按钮组件 FloatingActionButton
悬浮按钮(FAB)是常见的UI元素,用于提供突出的操作。本文介绍如何在React中使用Material-UI创建美观的FAB组件,涵盖基本概念、实现方法及常见问题解决。通过代码示例和优化技巧,帮助开发者提升用户体验,确保按钮位置、颜色、交互反馈等方面的表现,同时避免无障碍性和性能问题。
110 80
|
20天前
|
前端开发 JavaScript 开发者
React 按钮组件 Button
本文介绍了 React 中按钮组件的基础概念,包括基本的 `&lt;button&gt;` 元素和自定义组件。详细探讨了事件处理、参数传递、状态管理、样式设置和可访问性优化等常见问题及其解决方案,并提供了代码示例。帮助开发者避免易错点,提升按钮组件的使用体验。
160 77
|
18天前
|
存储 前端开发 UED
React 面包屑组件 Breadcrumb 详解
面包屑导航是现代Web应用中常见的UI元素,帮助用户了解当前位置并快速返回上级页面。本文介绍如何使用React构建面包屑组件,涵盖基本概念、实现方法及常见问题。通过函数式组件和钩子,结合React Router动态生成路径,处理嵌套路由,并确保可访问性。示例代码展示了静态和动态面包屑的实现,帮助开发者提升用户体验。
123 73
|
2月前
|
前端开发 JavaScript 测试技术
React 分页组件 Pagination
本文介绍了如何在 React 中从零构建分页组件,涵盖基础概念、常见问题及解决方案。通过示例代码详细讲解了分页按钮的创建、分页按钮过多、初始加载慢、状态管理混乱等常见问题的解决方法,以及如何避免边界条件、性能优化和用户反馈等方面的易错点。旨在帮助开发者更好地理解和掌握 React 分页组件的开发技巧,提升应用的性能和用户体验。
83 0
|
21天前
|
前端开发 UED 开发者
React 对话框组件 Dialog
本文详细介绍了如何在 React 中实现一个功能完备的对话框组件(Dialog),包括基本用法、常见问题及其解决方案,并通过代码案例进行说明。从安装依赖到创建组件、添加样式,再到解决关闭按钮失效、背景点击无效、键盘导航等问题,最后还介绍了如何添加动画效果和处理异步关闭操作。希望本文能帮助你在实际开发中更高效地使用 React 对话框组件。
127 75
|
2月前
|
设计模式 前端开发 编译器
与普通组件相比,React 泛型组件有哪些优势?
与普通组件相比,React 泛型组件有哪些优势?
107 63
|
26天前
|
前端开发 Java API
React 进度条组件 ProgressBar 详解
本文介绍了如何在 React 中创建进度条组件,从基础实现到常见问题及解决方案,包括动态更新、状态管理、性能优化、高级动画效果和响应式设计等方面,帮助开发者构建高效且用户体验良好的进度条。
48 18
|
2月前
|
存储 前端开发 测试技术
React组件的最佳实践
React组件的最佳实践
|
2月前
|
前端开发 API 开发者
React 文件上传组件 File Upload
本文详细介绍了如何在 React 中实现文件上传组件,从基础的文件选择和上传到服务器,再到解决文件大小、类型限制、并发上传等问题,以及实现多文件上传、断点续传和文件预览等高级功能,帮助开发者高效构建可靠的应用。
69 12
|
1月前
|
存储 前端开发 JavaScript
React 表单输入组件 Input:常见问题、易错点及解决方案
本文介绍了在 React 中使用表单输入组件 `Input` 的基础概念,包括受控组件与非受控组件的区别及其优势。通过具体代码案例,详细探讨了创建受控组件、处理多个输入字段、输入验证和格式化的方法,并指出了常见易错点及避免方法,旨在提升表单的健壮性和用户体验。
45 4