• 有问题请联系QQ:2374146085
  • 有问题请联系QQ:2374146085

React-组件+三大核心

8个月前 (10-02) 534次浏览 已收录 0个评论 扫描二维码

导读

react函数式组件、类式组件、组件三大核心:state,props,refs、react中构造函数的作用、事件绑定、字符串形式refs、回调形式refs、内联回调与class回调、createRef、受控组件、非受控组件、事件处理、ReactDOM.render做了什么? 函数式组件有props,state,ref吗.组件传值,两种setState修改状态.useState、useEffect、useEffect、useRef


组件

函数式组件

<!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>Document</title>
</head>
<body>
    <div id="box"></div>
    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>
    <script type="text/babel">
        // 创建函数式组件,首字母必须大写
        function Demo(){
            console.log(this) //此处的this是undefined,因为babel编译后开启了 严格模式
            return <h1>函数组件</h1>
        }
        //渲染组件到页面
        ReactDOM.render(<Demo/>,document.getElementById('box'))
    </script>
</body>
</html>

执行ReactDOM.render(<Demo/>…)发生了什么

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

hooks

useState

import React from 'react'

export default function App() {
  console.log('该函数调用1+n次')
  /**
   * count:定一个state状态为0
   * setCount:改变count的方法 ,可选
   * 下边代码只会调用一次,因为第一次初始化指定的值会在内部做缓存
   */
  const [count,setCount]=React.useState(0)

  function add(){
    // setCount(count+1) //第一种写法
    setCount((count)=>{ //第二种写法
      return count+1
    })
  }
  return (
    <div>
      <p>{count}</p>
      <button onClick={add}>加一</button>
    </div>
  )
}

useEffect

可以在函数组件中执行副作用操作,比如模拟类组件中的生命周期钩子

副作用:需要和组件外部变量交互的都是副作用

  • 发送ajax请求
  • 设置订阅/启动定时器
  • 手动更改真实dom

纯函数:是不是外部变量进行交互,相同的输入必定得到相同的输出.

import React from 'react'
import ReactDOM from 'react-dom/client'

export default function App() {
  const [count,setCount]=React.useState(0)
  const [name,setName]=React.useState('wxl')
  //const reudxCount = useSelect(state=>state.count) 拿到redux里的count状态

  /**监测 指定state状态的改变,初始化会调用一次
   * [count,reudxCount,?]下,会 “调用” 1+n 次 , name改变不会调用,而count,reduxCount会,并
   *  可以监测任何值,包括路由参数...
   * []空数组下,不检测任何state,只会在初始化调用一次
   * 不写数组这个参数,则会监测所有state
   * 
   * 相当于生命周期里的componentDidMount、componentDidUpdate,componentWillUnmount
   */
  React.useEffect(()=>{
    console.log('调用____在这执行带副作用的操作')
    let timer = setInterval(()=>{},1000)
    return()=>{
      console.log('组件将要卸载时 自动调用我返回的这个函数___做一些收尾工作')
      clearInterval(timer)
    }
  },[count])

  //React.useEffect(()=>{}) //根据场景增加不同的useEffect
  

  function fun_add(){
    setCount(count+1) //第一种写法
  }
  function fun_unMount(){
    ReactDOM.unmountComponentAtNode(document.getElementById('root'))
  }
  
  return (
    <div>
      <p>{count}</p>
      <button onClick={fun_add}>加一</button>
      <button onClick={fun_unMount}>卸载组件</button>
    </div>
  )
}

useEffect (异步)会在第一次真实dom渲染结束后调用回调函数 , 而清除函数会在以后的每次更新调用该回调之前调用清楚函数,然后再调用该回调函数.

具体的执行顺序:

  1. render > 回调(useEffect)
  2. render > 上一次清理函数 > 回调(useEffect)
  3. render > 上一次清理函数 > 回调(useEffect)
  4. 组件销毁 > 上一次清理函数

回调和上一次的清理函数 是 通过闭包来运作的

useRef

  • useRef获取DOM元素
  • useRef保存普通变量,它返回一个ref对象,它只有一个.current属性,并且被初始化为传入的参数(非函数,不然会每次render都会执行函数)
    • ref对象在组件的整个生命周期内引用地址不变
    • 其中current重新赋值时不会引发组件的重新渲染
    • 它可以绕过Capture Value,每次都可以拿到最新属性current值,而不会再每个render间存在快照.
import React from 'react'

export default function App() {

  const inputRef=React.useRef() //专人专用

  function fun_showInput(){
    console.log(inputRef)
    alert(inputRef.current.value)
  }

  return (
    <div>
      <input type="text" ref={inputRef}/>
      <button onClick={fun_showInput}>展示输入的值</button>
    </div>
  )
}

类式组件

<!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>Document</title>
</head>
<body>
    <div id="box"></div>
    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>
    <script type="text/babel">
        //创建类式组件
        class Demo2 extends React.Component{
            //render是放在Demo2类的原型对象上,供实例访问
            //render中的this是Demo2的实例对象/Demo2组件实例对象
            render(){
                return (
                    <h1>类式组件</h1>
                )
            }
        }
        //渲染组件到页面上
        ReactDOM.render(<Demo2/>,document.getElementById('box'))
    </script>
</body>
</html>

执行ReactDOM.render(<Demo/>…)发生了什么

  • React解析组件标签,找到了Demo组件
  • 发现组件是使用类定义的,随后new出来该类的实例,并通过实例调用到原型上的render方法
  • 将render返回的虚拟dom转为真实dom,随后呈现在页面中

组件(组件实例)的三大核心

state 状态

<!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>Document</title>
</head>
<body>
    <div id="box"></div>
    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>
    <script type="text/babel">
        class Demo2 extends React.Component{
            constructor(props){
                super(props)
                //初始化state状态
                this.state={
                    isShow:true
                }
            }
            render(){
                console.log('this',this)
                return (
                    <h1>我是{this.state.isShow ? 'wxl' : 'zzl'}</h1>
                )
            } 
        }
        ReactDOM.render(<Demo2/>,document.getElementById('box'))
    </script>
</body>
</html>

事件绑定

下边代码是对没有this的解释,程序不能正常运行

<!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>Document</title>
</head>
<body>
    <div id="box"></div>
    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>
    <script type="text/babel">
        class Demo2 extends React.Component{

            constructor(props){
                super(props)
                //初始化状态
                this.state={
                    isShow:true
                }
            }
            render(){
                console.log('this',this)
                //读取状态
                const {isShow} = this.state
                return (
                    <h1 onClick={this.show}>我是{isShow ? 'wxl' : 'zzl'}</h1>
                    //onClick={this.show} 相当于了 const tmp=this.show 故当执行tmp时,就单单是直接调用了,没有了this
                )
            }
            
            // show是放在Demo2类的原型对象上,供实例访问
            //由于show是作为onClick的回调,所以不是通过实例调用的,而是直接调用,
            //又因为类中的方法默认开启了局部严格模式,所以show中的this为undefined
            show(){
                // 类中的方法会自动开启严格模式,也就是this不会只想window
                console.log(this)  //undefined
            }

        }
        ReactDOM.render(<Demo2/>,document.getElementById('box'))
    </script>
</body>
</html>

下边是对上边代码this指向问题的解决

<!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>Document</title>
</head>
<body>
    <div id="box"></div>
    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>
    <script type="text/babel">
        class Demo2 extends React.Component{

            constructor(props){
                super(props)
                //初始化状态
                this.state={
                    isShow:true
                }
                //解决show中this的指向问题
                this.show1=this.show.bind(this)
            }
            render(){
                console.log('this',this)
                //读取状态
                const {isShow} = this.state
                return (
                    <h1 onClick={this.show1}>我是{isShow ? 'wxl' : 'zzl'}</h1>
                )
            }
            
            show(){
                console.log(this)  //undefined
            }

        }
        ReactDOM.render(<Demo2/>,document.getElementById('box'))
    </script>
</body>
</html>

[pre1] 以下代码能正常运行,并且是最完整的事件绑定修改state状态

<!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>Document</title>
</head>
<body>
    <div id="box"></div>
    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>
    <script type="text/babel">
        class Demo2 extends React.Component{
            //构造器调用一次
            constructor(props){
                super(props)
                //初始化state状态
                this.state={
                    isShow:true
                }
                //解决show中this的指向问题,即为事件处理函数绑定实例
                this.show1=this.show.bind(this)
            }
            //render调用1+n次 1是初始化 n是状态更新的次数
            render(){
                console.log('this',this)
                //读取状态
                const {isShow} = this.state
                return (
                    <h1 onClick={this.show1}>我是{isShow ? 'wxl' : 'zzl'}</h1>
                )
            }
            
            show(){
                const isShow=this.state.isShow
                // 状态不可直接更改
                // this.state.isShow=!isShow
                //状态必须通过setState进行更新,且是合并,不是覆盖替换
                this.setState({isShow:!isShow})
            }

        }
        ReactDOM.render(<Demo2/>,document.getElementById('box'))
    </script>
</body>
</html>

由上小节代码[pre1]中可知,构造函数在react中用于以下两种情况:

  • 通过给this.state赋值对象来初始化内部state(初始化state状态)
  • 为事件处理函数绑定实例

而构造器是否接收props,是否传递给super,取决于你是否希望在构造器中通过this(实例)访问props,并且开发中不常用不希望.

上边的代码[pre1]的简写(state简写,开发用这种) :

<!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>Document</title>
</head>
<body>
    <div id="box"></div>
    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>
    <script type="text/babel">
        class Demo2 extends React.Component{
            //初始化状态
            //实例对象自身上添加的的属性  (赋值语句=,就会把该属性放在实例自身)
            state={
                    isShow:true
                }

            render(){
                console.log('this',this)
                const {isShow} = this.state
                return (
                    <h1 onClick={this.show}>我是{isShow ? 'wxl' : 'zzl'}</h1>
                )
            }

            // 这范围里的this是实例对象

            //实例对象自身上的方法----用赋值语句+箭头函数
            show=()=>{
                console.log(this) //实例对象 ,而箭头函数没有this,是外层的this
                const isShow=this.state.isShow
                this.setState({isShow:!isShow})
            }

        }
        ReactDOM.render(<Demo2/>,document.getElementById('box'))
    </script>
</body>
</html>

setState修改状态

  • setState(stateChange, [callback])——对象式的setState
    • 如果新状态不依赖于原状态,就使用对象式的setState
    • stateChange为状态改变对象(该对象可以体现出状态的更改)
    • callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
    • const {count} = this.state
      this.setState({count:99},()=>{
          console.log('我现在能拿到最新的值 ',this.state.count)
        })
  • setState(updater, [callback])——函数式的setState
    • 如果新状态依赖于原状态,就使用函数式的setState
    • updater为返回stateChange对象的函数
    • updater可以接收到state和props。
    • callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。react中构造函数的作用(不常用)
    • //不用获取原来的状态值
      this.setState((state,props)=>{
          return {count:state.count+1}
        })

props

<!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>Document</title>
</head>

<body>
    <div id="box"></div>
    <div id="box2"></div>

    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>
    
    <!-- 引入props-types ,用于对组件标签属性进行限制 -->
    <script src="../../lib/prop-types.js"></script>

    <script type="text/babel">
        class Demo3 extends React.Component {
            render() {
                const {name,age,sex}=this.props
                // this.props.name='ll' 此行代码会报错,因为name 是只读的
                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性别:{sex}</li>
                        <li>年龄:{age}</li>
                    </ul>
                )
            }
        }
        Demo3.propTypes={
            name:PropTypes.string.isRequired,//限制name为字符串且必传项
            age:PropTypes.number,//限制age为number
            sex:PropTypes.string,
            speak:PropTypes.func //限制speak为函数
        }
        Demo3.defaultProps={
            sex:'男' //默认值
        }
        const data={name:'wxl',age:22,sex:'男'}
        //react提供的展开运算符在{}里展开一个对象,并不是原生js里的花括号与展开云算法 拷贝对象 的样子
        ReactDOM.render(<Demo3 {...data}/>, document.getElementById('box'))
        ReactDOM.render(<Demo3 name="ll" age={21} sex="男" speak={speak} />, document.getElementById('box2'))

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

</html>

上边代码的简写(props简写,开发用这种):

<!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>Document</title>
</head>

<body>
    <div id="box"></div>
    <div id="box2"></div>

    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>
    
    <!-- 引入props-types ,用于对组件标签属性进行限制 -->
    <script src="../../lib/prop-types.js"></script>

    <script type="text/babel">
        class Demo3 extends React.Component {
            // 给类本身加属性,来限制props的类型
            static propTypes={
                name:PropTypes.string.isRequired,//限制name为字符串且必传项
                age:PropTypes.number,//限制age为number
                sex:PropTypes.string,
                speak:PropTypes.func //限制speak为函数
            }
            //默认值
            static defaultProps={
                sex:'男' 
            }
            
            render() {
                const {name,age,sex}=this.props
                // this.props.name='ll' 此行代码会报错,因为name 是只读的
                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性别:{sex}</li>
                        <li>年龄:{age}</li>
                    </ul>
                )
            }
        }
        const data={name:'wxl',age:22,sex:'男'}
        //react提供的展开运算符在{}里展开一个对象,并不是原生js里的花括号与展开云算法 拷贝对象 的样子
        ReactDOM.render(<Demo3 {...data}/>, document.getElementById('box'))
        ReactDOM.render(<Demo3 name="ll" age={21} sex="男" speak={speak} />, document.getElementById('box2'))

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

</html>

组件通信

搭配方式:

  • 父子组件:props
  • 兄弟组件:消息订阅、redux
  • 跨级组件:消息订阅,redux,context

子传父:

其中props传函数可以用于子组件给父组件传值里

  • 父组件定义函数,接收data
  • 父组件通过props把该函数传给子组件
  • 子组件通过调用this.props.fun(data)就可以传值给父组件了

父传子:

  • 直接使用props传即可

兄弟组件传值:

使用发布订阅pubsub.js

  1. npm install pubsub-js
  2. import React, { Component } from 'react'
    
    import PubSub from 'pubsub-js'
    
    export default class App extends Component {
    
      state={
        name:'ll'
      }
    
      //A组件
      componentDidMount(){
        //A组件订阅消息,timer用于取消订阅的ID
      this.timer = PubSub.subscribe('test',(msg,data)=>{
          console.log('A组件收到数据',data)
          // this.setState({name:data.name})
          this.setState(data)
        })
      }
      componentWillUnmount(){
          //取消订阅
        PubSub.unsubscribe(this.timer)
      }
    
      // -------------------------------
    
      //B组件发布消息
      PubSub.publish('test',{name:'wxl'})
    }
    

祖传父Context(生产者-消费者)

  1. 类式组件
import React, { Component } from 'react'

//创建Context对象
const MyUserDataContext = React.createContext()
export default class A extends Component {

  state={name:'wxl',age:19}

  render() {
    return (
      <>
        <div>A</div>
        <MyUserDataContext.Provider value={this.state}>
          <B/>
        </MyUserDataContext.Provider>
      </>
    )
  }
}
class B extends Component {
  render() {
    return (
      <>
        <div>B</div>
        <C/>
      </>
    )
  }
}
class C extends Component {

  //只有声明接收祖组件传过来的MyUserDataContext,才能拿到传的值name
  static contextType=MyUserDataContext 
  
  render() {
    return (
      <div>C:{this.context.name}</div>
    )
  }
}

2. 函数式组件,下边这种方式不仅适合于类组件还适合于函数组件.

import React, { Component } from 'react'

//创建Context对象
const MyUserDataContext = React.createContext()
export default class A extends Component {

  state={name:'wxl',age:19}

  render() {
    return (
      <>
        <div>A</div>
        <MyUserDataContext.Provider value={this.state}>
          <B/>
        </MyUserDataContext.Provider>
      </>
    )
  }
}
class B extends Component {
  render() {
    return (
      <>
        <div>B</div>
        <C/>
      </>
    )
  }
}

function C() {
  return (
    <div>
      C:<MyUserDataContext.Consumer>
        {
          value=>{
            return `${value.name}`
          }
        }
      </MyUserDataContext.Consumer>
      </div>
  )
}

未使用hooks的函数式组件对于三大核心,只能对props生效

<!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>Document</title>
</head>

<body>
    <div id="box"></div>
    <div id="box2"></div>

    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>

    <!-- 引入props-types ,用于对组件标签属性进行限制 -->
    <script src="../../lib/prop-types.js"></script>

    <script type="text/babel">
        function Demo4(props) {
            const { name, age, sex } = props
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age}</li>
                </ul>
            )
        }
        Demo4.propTypes = {
            name: PropTypes.string.isRequired,//限制name为字符串且必传项
            age: PropTypes.number,//限制age为number
            sex: PropTypes.string,
            speak: PropTypes.func //限制speak为函数
        }
        Demo4.defaultProps = {
            sex: '男'
        }
        
        const data = { name: 'wxl', age: 22, sex: '男' }
        
        ReactDOM.render(<Demo4 {...data} />, document.getElementById('box'))
        ReactDOM.render(<Demo4 name="ll" age={21} sex="男" speak={speak} />, document.getElementById('box2'))

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

</html>

refs

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

字符串形式的refs (不建议用)

<!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>Document</title>
</head>

<body>
    <div id="box"></div>
    <div id="box2"></div>

    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>

    <script type="text/babel">
        class Demo4 extends React.Component {
            show=()=>{
                console.log(this.refs.inputRef.value)
            }
            render() {
                return (
                    <div>
                        <input ref="inputRef"></input>
                        <button ref="btnRef" onClick={this.show}>点击</button>
                    </div>
                )
            }
        }

        ReactDOM.render(<Demo4/>, document.getElementById('box'))
    </script>
</body>

</html>

回调形式的refs

<!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>Document</title>
</head>

<body>
    <div id="box"></div>
    <div id="box2"></div>

    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>

    <script type="text/babel">
        class Demo4 extends React.Component {
            show=()=>{
                console.log(this.inputRef.value)
                console.log(this.input2Ref.value)
            }

            ref2Fun=(cn)=>{
                this.input2Ref=cn
                console.log(this.input2Ref.value)
            }
            render() {
                return (
                    // react会调用ref里的这个回调函数,然后把所处标签真实dom传给函数,函数再把该dom赋值给实例对象上
                    <div>
                        {/*内联回调*/}
                        <input ref={ (cn)=>{this.inputRef=cn} }></input>

                        <button onClick={this.show}>点击</button>

                        {/*通过class绑定的回调函数*/}
                        <input ref={this.ref2Fun} />
                    </div>
                )
            } 
        }

        ReactDOM.render(<Demo4/>, document.getElementById('box'))
    </script>
</body>

</html>

内联回调与class绑定回调的区别

  • 内联回调回在更新过程中执行两次,第一次传给回调参数null,第二次才回传入dom元素.
    • 这是因为每次渲染时会会创建一个新的函数实例,所以react会清空旧的ref,并且设置新的
  • class绑定的回调可以解决上述问题

createRef(推荐使用)

createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点

<!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>Document</title>
</head>

<body>
    <div id="box"></div>
    <div id="box2"></div>

    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>

    <script type="text/babel">
        class Demo4 extends React.Component {
            //创建出来一个容器,存储被它所标识的节点,然后挂在了实例对象自身上
            input1Ref=React.createRef() 
            input2Ref=React.createRef()

            show=()=>{
                console.log(this.input1Ref.current.value)
                console.log(this.input2Ref.current.value)
            }

            render() {
                return (
                    // react会调用ref里的这个回调函数,然后把所处标签真实dom传给函数,函数再把该dom赋值给实例对象上
                    <div>
                        <input ref={this.input1Ref}></input>
                        <button onClick={this.show}>点击</button>
                        <input ref={this.input2Ref} />
                    </div>
                )
            } 
        }

        ReactDOM.render(<Demo4/>, document.getElementById('box'))
    </script>
</body>

</html>

受控组件与非受控组件

非受控组件

现用现取,(不建议用,因为过度使用了ref)

render(){
 return(
  <form onSubmit={this.handleSubmit}>
   用户名:<input ref={c => this.username = c} type="text" name="username"/>
   密码:<input ref={c => this.password = c} type="password" name="password"/>
   <button>登录</button>
  </form>
 )
}

受控组件

随着输入,维护state状态,类似vue的v-model

<!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>Document</title>
</head>

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

    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>

    <script type="text/babel">
        class Login extends React.Component {
            //初始化状态
            state = {
                username: '', //用户名
                password: '', //密码
                sex:'男'
            }

            //方法1:保存用户名密码到 状态中------------------
            saveData = (keyType) => {
                return (event)=>{
                    //运用函数柯里化技术
                    this.setState({[keyType]: event.target.value })
                }
            }

            //方法2:保存性别到 状态中-----------------------
            saveData2=(keyType,event)=>{
                this.setState({[keyType]:event.target.value})
            }

            //表单提交的回调
            handleSubmit = (event) => {
                event.preventDefault() //阻止表单提交
                const { username, password } = this.state
                alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
            }

            render() {
                return (
                    <form onSubmit={this.handleSubmit}>
                        {/*方法1------------------*/}
                        用户名:<input onChange={this.saveData('username')} type="text" name="username" />
                        密码:<input onChange={this.saveData('password')} type="password" name="password" />

                        {/*方法2--------------------*/}
                        性别:<input onChange={e=>this.saveData2('sex',e)} />
                        <button>登录</button>
                    </form>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Login />, document.getElementById('test'))
    </script>
</body>

</html>

函数柯里化:

  • 通过函数调用继续返回函数的方式,实现 多次接收参数,最后统一处理的函数编码形式.

事件处理

  • onXxx形式,接收 一个回调函数
  • react中的事件是通过事件委托方式处理的(委托给最外层的元素)

有了事件处理可以在有些时候避免过度使用ref, 比如发生事件的事件源dom正好是我要 操作的dom.

<!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>Document</title>
</head>

<body>
    <div id="box"></div>
    <div id="box2"></div>

    <script src="../../lib/react.development.js"></script>
    <script src="../../lib/react-dom.development.js"></script>
    <script src="../../lib/babel.min.js"></script>

    <script type="text/babel">
        class Demo4 extends React.Component {
            show=(e)=>{
                console.log(e.target.value)
            }
            render() {
                return (
                    <div>
                        <input onBlur={this.show}/>
                    </div>
                )
            } 
        }

        ReactDOM.render(<Demo4/>, document.getElementById('box'))
    </script>
</body>

</html>

渣渣龙, 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:React-组件+三大核心
喜欢 (2)

您必须 登录 才能发表评论!