react学习2-组件式开发

本文介绍了React中的函数式组件和类组件的创建与渲染,详细讲解了状态state的管理和props的传递,包括如何初始化状态、更新状态以及处理事件。同时,讨论了ref的使用,包括基本使用、回调函数形式和React.createRef()方法。文章还涉及到了表单数据的处理,包括非受控组件和受控组件的概念,并探讨了高阶函数的应用,如柯里化的实现。

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

函数式组件

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

  <!--babel-->
  <script type="text/babel">
    //1.创建函数式组件 (必须有返回值)
    function MyComponent(){
    console.log(this) //undefined,因为babel编译后开启了严格模式
      return <h2>我是用函数定义的组件(适用于简单组件的定义)</h2>
    }
    //2.渲染组件到页面
    ReactDOM.render(<MyComponent />,document.getElementById('test'))

执行ReactDOM.render之后:
1)react解析组件标签,找到MyComponent组件;
2)发现组件是函数定义,调用该函数,将返回的虚拟DOM转为真实DOM,呈现页面

类相关知识

1.类的创建和实例

  <script type="text/javascript">
    //创建一个person类
    class Person{
      //构造器方法
      constructor(name,age){
        //构造器中的this是类的实例对象
        this.name=name
        this.age=age
      }
      //一般方法
      speak(){
        //speak方法放在类的原型对象上,供实例使用
        //通过person实例调用speak时,speak的this就是person实例
        console.log(`我叫${this.name},我的年龄是${this.age}`)
      }
    }

    //创建person实例对象
    const p1=new Person('Tom',18)
    console.log(p1)
    const p2=new Person('Jerry',19)
    console.log(p2)
    p1.speak()
    p2.speak()
    p1.speak.call({a:1,b:2})  //call更改函数指向  我叫undefined,我的年龄是undefined
  </script>

2.继承

  <div id="test"></div>
  <script type="text/javascript">
    //创建一个person类
    class Person{
      constructor(name,age){
        this.name=name
        this.age=age
      }
      speak(){
        console.log(`我叫${this.name},我的年龄是${this.age}`)
      }
    }
    
    //创建一个student类,继承person
    class Student extends Person{
      constructor(name,age,grade){
        super(name,age) //必须写在最开头
        this.grade=grade
        this.school='第一学校'
      }
      //重写父类继承过来的方法
      speak(){
        console.log(`我叫${this.name},我的年龄是${this.age},我读的是${this.grade},我在${this.school}`)
      }
      study(){
        console.log("我很努力的学习")
      }
    }
    //创建student实例对象
    const s1 = new Student('小张',19,'高一')
    s1.speak() //我叫小张,我的年龄是19,我读的是高一,我在第一学校
    s1.study() //我很努力的学习
  </script>

3.总结
1)类中构造器不是必须写的,对实例进行一些初始化操作,如添加指定属性时才写;
2)如果A继承B,且A有构造器,则A类构造器中的super必须调用;
3)类中所定义的方法,都是放在类的原型对象上,供实例使用。
4)类中可以直接写赋值语句

类式组件

  <div id="test"></div>
  <script type="text/babel">
    //1.创建类式组件
    class MyComponent extends React.Component{
      render(){
        //render放在类MyComponent的原型对象上,供实例使用
        //render中的this是类的实例对象
        console.log(this) //MyComponent {…}
        return(
          <h2>我是用类定义的组件(适用于复杂组件的定义)</h2>
        )
      }
    }
    //2.渲染组件到页面
    ReactDOM.render(<MyComponent />,document.getElementById("test"))
  </script>

执行ReactDOM.render之后:
1)react解析组件标签,找到MyComponent组件;
2)发现组件是类定义,随后new出来该类的实例,并通过该实例调用到原型上的render方法
3)将render返回的虚拟dom转为真实dom,呈现在页面上

状态state(组件实例的三大核心属性之一)

无状态:简单组件;有状态:复杂组件
1.组件状态驱动页面,数据放在状态中
2.原生事件绑定点击事件

  <div>
    <button id="button1">按钮1</button>
    <button id="button2">按钮2</button>
    <button onclick="demo()">按钮3</button>
  </div>
  <!--babel-->
  <script type="text/javascript">
    const btn1=document.getElementById('button1');
    btn1.addEventListener('click',()=>{
      alert('按钮1点击')
    })
    const btn2=document.getElementById('button2');
    btn2.onclick=()=>{
      alert('按钮2点击')
    }

    function demo(){
      alert("按钮3点击")
    }
  </script>

3.实现凉爽和炎热的切换
在这里插入图片描述
在这里插入图片描述
1)类中this指向问题
①错误代码

  <!--babel-->
  <script type="text/babel">

    //1.创建组件
    class Weather extends React.Component{
      constructor(props){
        super(props)
        //初始化状态
        this.state={isHot:true}
      }
      render(){
        console.log(this)
        const {isHot} =  this.state
        return <h1 onClick={this.changeWeather}>今天天气很{ isHot ? '炎热' : '凉爽'}</h1>
      }
      changeWeather(){
      //changeWeather放在weather原型上
      //changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用的
      //类中的方法默认开启局部严格模式,所以changeWeather中的this为undefined
        console.log(this)  //undefined
      }
    }
    //2.渲染组件到页面
    ReactDOM.render(<Weather/>,document.getElementById("test"))

  </script>

②this正确方法(bind)

<script type="text/babel">
//1.创建组件
    class Weather extends React.Component{
      constructor(props){
        super(props)
        //初始化状态
        this.state={isHot:true}
        this.demo = this.changeWeather.bind(this)
      }
      render(){
        console.log(this)
        const {isHot} =  this.state
        return <h1 onClick={this.demo}>今天天气很{ isHot ? '炎热' : '凉爽'}</h1>
      }
      changeWeather(){
        //获取ishot值 state不可以直接更改(const isHot=this.state.isHot;this.state.isHot =!isHot),需要借助内部API更改(setState)
        const isHot=this.state.isHot;
        this.setState({isHot:!isHot});
      }
    }

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

2)react中state必须使用setState进行更改,且更新是一种合并,不是直接替换。
在此过程中,类中:constructor只调用1次,render调用1+N(初始+更新状态次数)次,changeWeather调用N(更新状态次数)次

3)精简版

  <script type="text/babel">
  //1.创建组件
  class Weather extends React.Component{
    //初始化状态
    state={isHot:true,wind:'微风'}

    render(){
      const {isHot,wind} =  this.state
      return <h1 onClick={this.changeWeather}>今天天气很{ isHot ? '炎热' : '凉爽'}{wind}</h1>
    }
    //自定义方法:用赋值语句的形式+箭头函数
    changeWeather= ()=>{
      console.log(this)
      const isHot=this.state.isHot;
      this.setState({isHot:!isHot});
    }
  }

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

4.state总结
1)组件中render的this为组件实例对象;
2)自定义的方法的this为undefined,解决(bind或者赋值语句+箭头函数);
3)状态只能通过setState更新。

props

1.基本使用形式

  <script type="text/babel">
    //创建组件
    class Person extends React.Component{
      render(){
        return (
          <ul>
            <li>姓名:{this.props.name}</li>
            <li>性别:{this.props.age}</li>
            <li>年龄:{this.props.sex}</li>
          </ul>
        )
      }
    }
    //2.渲染组件到页面
    ReactDOM.render(<Person name="tom" age="18" sex="男"/>,document.getElementById("test"))
  </script>

在这里插入图片描述
在这里插入图片描述
2.展开运算符传值

  <div id="test1"></div>
  <div id="test"></div>
<script type="text/babel">
    //创建组件
    class Person extends React.Component{
      render(){
        // console.log(this)
        const {name,age,sex} = this.props
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{sex}</li>
            <li>年龄:{age+1}</li>
          </ul>
        )
      }
    }
    //对标签属性进行类型和默认值的设置
    Person.propTypes ={
      name:PropTypes.string.isRequired, //限制必传和string类型
      sex:PropTypes.string,
      speak:PropTypes.func
    }
    Person.defaultProps={
      sex:'男', //默认值
      age:18
    }
    const p={name:'老刘',age:19,sex:'女'}
    //2.渲染组件到页面
    ReactDOM.render(<Person name='jerry' speak={speak}/>,document.getElementById("test1"))
    ReactDOM.render(<Person {...p} />,document.getElementById("test"))

    function speak(){
      console.log("说话")
    }
  </script>

3.简写形式

    class Person extends React.Component{
      render(){
        const {name,age,sex} = this.props
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{sex}</li>
            <li>年龄:{age+1}</li>
          </ul>
        )
      }
    
      static propTypes ={
        name:PropTypes.string.isRequired, //限制必传和string类型
        sex:PropTypes.string,
        speak:PropTypes.func
      }
      static defaultProps={
        sex:'男', //默认值
        age:18
      }
    }

4.构造器–几乎用不到
构造器是否接收props,是否传递给super取决于是否希望在构造器中通过this访问props
5.函数式组件

  <script type="text/babel">
    //创建组件
      Person.propTypes ={
        name:PropTypes.string.isRequired, //限制必传和string类型
        sex:PropTypes.string,
        speak:PropTypes.func
      }
      Person.defaultProps={
        sex:'男', //默认值
        age:18
      }

    function Person(props){
      const {name,age,sex} = props
      return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{sex}</li>
            <li>年龄:{age}</li>
          </ul>
        )
    }
  
    //2.渲染组件到页面
    ReactDOM.render(<Person name='Jerry'/>,document.getElementById("test"))

  </script>

ref

1.基本使用(字符串类型的ref)–不推荐,存在效率问题
在这里插入图片描述

<script type="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 type="text" placeholder="点击按钮提示数据" ref="input1"/>&nbsp;
            <button  onClick={this.showData}>点我提示左侧数据</button>&nbsp;
            <input type="text" placeholder="失去焦点提示数据" onBlur={this.showData2} ref="input2"/>
          </div>
        )
      }
    }
  
  //渲染组件到页面
  ReactDOM.render(<Demo a="1"/>,document.getElementById('test'))
  </script>

2.回调函数形式(内联)

  <script type="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 type="text" placeholder="点击按钮提示数据" ref={c=>this.input1=c}/>&nbsp;
            <button  onClick={this.showData}>点我提示左侧数据</button>&nbsp;
            <input type="text" placeholder="失去焦点提示数据" onBlur={this.showData2}  ref={c=>this.input2=c}/>
          </div>
        )
      }
    }
 
  //渲染组件到页面
  ReactDOM.render(<Demo a="1"/>,document.getElementById('test'))
  </script>

2.回调函数形式(类绑定)

      saveInput=(c)=>{
        this.input1=c;
        console.log("@",c)
      }
      render(){
        const {isHot}=this.state
        return(
          <div>
            <h2>今天天气很{isHot ? '炎热':'凉爽'}</h2>
            <input type="text" placeholder="点击按钮提示数据" ref={this.saveInput}/><br />
            <button  onClick={this.showData}>点我提示数据</button>
            <button  onClick={this.changeWeather}>点我更换天气</button>
          </div>
        )
      }
    }

3.createRef

<script type="text/babel">
    //创建组件
    class Demo extends React.Component{
      //调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
      myRef = React.createRef()
      myRef2 = React.createRef()
      //展示左侧输入框数据
      showData= ()=>{
        alert(this.myRef.current.value)
        console.log(this.myRef) //见下图
      }
      //展示右侧输入框数据
      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('test'))
  </script>

在这里插入图片描述
4.ref总结
1)避免使用字符串形式ref;
2)内联和类绑定都可以使用;
3)React.createRef() 是react最推荐的。

事件处理

1.通过onXXX属性指定事件处理函数(注意大小写)
(1)react使用的是自定义(合成)事件,而不是使用原生DOM事件;—为了更好的兼容性
(2)react的是事件是通过事件委托方式处理的(委托的是最外层元素)—为了高效
2.通过event.target得到发生事件的DOM元素(发生事件元素是操作的元素)。—不要过度使用ref

收集表单数据

1.非受控组件:页面中所有输入型DOM都是现用现取

<script type="text/babel">
    //创建组件
    class Login extends React.Component{
      handleSubmit=(event)=>{
        event.preventDefault() //阻止表单提交
        const {username,password} = this;
        alert(`用户名是${username.value},密码是${password.value}`)
      }
      render(){
        return(
          <form action="#" onSubmit={this.handleSubmit}>
            用户名:<input input="text" name="username" ref={c=> this.username=c}/>
            密码:<input input="password" name="password" ref={c=>this.password=c}/>
            <button>登录</button>   
          </form>
        )
      }
    }

    //渲染页面
    ReactDOM.render(<Login />,document.getElementById('test'))
  </script>

2.受控组件:页面中所有输入型DOM随着输入维护到state中(vue双向数据绑定)—推荐

<script type="text/babel">
    //创建组件
    class Login extends React.Component{

      state={
        username:"", //用户名
        password:"" //密码
      }

      handleSubmit=(event)=>{
        event.preventDefault() //阻止表单提交
        const {username,password} = this.state;
        alert(`用户名是${username},密码是${password}`)
      }
      //保存用户名
      saveUsername=()=>{
        this.setState({username:event.target.value})
      }
      //保存密码
      savePassword=()=>{
        this.setState({password:event.target.value})
      }

      render(){
        return(
          <form action="#" onSubmit={this.handleSubmit}>
            用户名:<input input="text" name="username" onChange={this.saveUsername}/>
            密码:<input input="password" name="password" onChange={this.savePassword}/>
            <button>登录</button>   
          </form>
        )
      }
    }

    //渲染页面
    ReactDOM.render(<Login />,document.getElementById('test'))
  </script>

高阶函数

高阶函数:一个函数符合下面两个规范中任意一个
(1)A函数接收的参数是一个函数,A为高阶
(2)A函数调用的返回值是一个函数,A为高阶
常见的高阶函数:Promise、setTimeout、arr.map等
1.函数柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

<script type="text/babel">
    //创建组件
    class Login extends React.Component{

      state={
        username:"", //用户名
        password:"" //密码
      }

      handleSubmit=(event)=>{
        event.preventDefault() //阻止表单提交
        const {username,password} = this.state;
        alert(`用户名是${username},密码是${password}`)
      }
      //保存表单数据
      saveFormData=(dataType)=>{
        return (event)=>{
          this.setState({[dataType]:event.target.value})
        }
      }
      render(){
        return(
          <form action="#" onSubmit={this.handleSubmit}>
            用户名:<input input="text" name="username" onChange={this.saveFormData('username')}/>
            密码:<input input="password" name="password" onChange={this.saveFormData('password')}/>
            <button>登录</button>   
          </form>
        )
      }
    }

    //渲染页面
    ReactDOM.render(<Login />,document.getElementById('test'))
  </script>

2.不用柯里化

saveFormData=(dataType,event)=>{
          this.setState({[dataType]:event.target.value})
      }
      render(){
        return(
          <form action="#" onSubmit={this.handleSubmit}>
            用户名:<input input="text" name="username" onChange={event=>this.saveFormData('username',event)}/>
            密码:<input input="password" name="password" onChange={event=>this.saveFormData('password',event)}/>
            <button>登录</button>   
          </form>
        )
      }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值