导读
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渲染结束后调用回调函数 , 而清除函数会在以后的每次更新调用该回调之前调用清楚函数,然后再调用该回调函数.
具体的执行顺序:
- render > 回调(useEffect)
- render > 上一次清理函数 > 回调(useEffect)
- render > 上一次清理函数 > 回调(useEffect)
- 组件销毁 > 上一次清理函数
回调和上一次的清理函数 是 通过闭包来运作的
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
- npm install pubsub-js
-
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(生产者-消费者)
- 类式组件
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>