React系列(四)ref

一、ref的三种方式

  • 字符串形式Ref
  • 内联函数形式Ref
  • 官方推荐createRef

1.1 字符串形式Ref

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

            showData = ()=>{
                const {input1} = this.refs; 
                console.log("showdata:"+input1.value+",Class:"+input1.className+',fieldValue:'+input1.getAttribute('data-field'));

            }

            showData2 = ()=>{
                 
                const input2  = this.refs.input2;
                console.log("showdata2"+input2.value+",Class:"+input2.className+',fieldValue:'+input2.getAttribute('data-field'));

            }

           render(){

               return (
                   <div>
                        <input ref="input1" data-field="123" className="input1Class" type="text" placeholder="clickShowData" />
                        <button onClick={this.showData}>show data</button>
                        <input ref="input2" data-field="234" className="input2Class" onBlur={this.showData2} type="text"  placeholder="clickShowData2"/>
                    </div>
               )
           }   
       }

       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Demo />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>

1.2 内联函数形式Ref

1.2.1 行内内联回调函数(不建议)

行内内联回调函数会在状态更新时重新调用,下面通过例子说明

先来一个简单的例子

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

            showData = ()=>{
                const {input1} = this; 
                console.log("showdata:"+input1.value+",Class:"+input1.className+',fieldValue:'+input1.getAttribute('data-field'));
            }
           render(){

               return (
                   <div>
                        <input ref={(c)=>{this.input1=c}} data-field="123" className="input1Class" type="text" placeholder="clickShowData" />
                        {/**<input ref={(c) => { this.input2 = c; }}  data-field="456" className="input2Class" type="text" placeholder="clickShowData" />
                   <input ref={c =>  this.input3 = c }  data-field="789" className="input3Class" type="text" placeholder="clickShowData" /> **/}
                        <button onClick={this.showData}>show data</button>
                      
                    </div>
               )
           }   
       }
       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Demo />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>

现在我们在上述例子增加一个状态变更(state)

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

            state = { showType:false}
            showData = ()=>{
                const {input1} = this; 
                console.log("showdata:"+input1.value+",Class:"+input1.className+',fieldValue:'+input1.getAttribute('data-field'));
            }

            changeShowtype = ()=>{
                const {showType} = this.state;
                console.log("@"+showType)
                this.setState({showType:!showType});

            }
           render(){
                const {showType} = this.state;

               return (
                   <div>
                        <h1>1{showType?'显示':'隐藏'}1</h1>
                        <input ref={(c)=>{this.input1=c;console.log("@222");}} data-field="123" className="input1Class" type="text" placeholder="clickShowData" />
                        <button onClick={this.showData}>show data</button>
                        <button onClick={this.changeShowtype}>changeShowtype</button>
                    </div>
               )
           }   
       }
       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Demo />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>
React系列(四)ref插图

通过例子后,我们发现会调用两次。可以通过下面的例子进行修复

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

            state = { showType:false}
            showData = ()=>{
                const {input1} = this; 
                console.log("showdata:"+input1.value+",Class:"+input1.className+',fieldValue:'+input1.getAttribute('data-field'));
            }
            saveInput1 = (c)=>{
                this.input1 = c;
                console.log("showdata: " + this.input1.value + ", Class: " + this.input1.className );
                console.log(222);
            }
            changeShowtype = ()=>{
                const {showType} = this.state;
                console.log("@"+showType)
                this.setState({showType:!showType});

            }
           render(){
                const {showType} = this.state;

               return (
                   <div>
                        <h1>1{showType?'显示':'隐藏'}1</h1>
                        <input ref={this.saveInput1} data-field="123" className="input1Class" type="text" placeholder="clickShowData" />
                        <button onClick={this.showData}>show data</button>jj
                        <button onClick={this.changeShowtype}>changeShowtype</button>
                    </div>
               )
           }   
       }
       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Demo />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>

1.3 createRef形式

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

            input1Ref = React.createRef();
            input2Ref = React.createRef();
            showData = ()=>{
                const input1 = this.input1Ref.current;

                console.log("showdata:"+input1.value+",Class:"+input1.className+',fieldValue:'+input1.getAttribute('data-field'));

            }
            showData2 = ()=>{
                const input2 = this.input2Ref.current; 
               
                console.log("showdata2:"+input2.value+",Class:"+input2.className+',fieldValue:'+input2.getAttribute('data-field'));

            }

           render(){

               return (
                   <div>
                        <input ref={this.input1Ref} data-field="123" className="input1Class" type="text" placeholder="clickShowData" />
                        <button onClick={this.showData}>show data</button>
                        <input ref={this.input2Ref} data-field="234" className="input2Class" onBlur={this.showData2} type="text"  placeholder="clickShowData2"/>
                    </div>
               )
           }   
       }

       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Demo />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>

二、受控组件和非受控组件

2.1受控组件

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

            state = {
                username:'',
                password:''
            }

            saveUsername =(event)=>{
                this.setState({username:event.target.value})
            }

            savePassword =(event)=>{
                this.setState({password:event.target.value})
            }

            handleSubmit = (event)=>{
                event.preventDefault (); //组织表单提交

                const {username,password} = this.state;

                alert(`username:${username},password:${password}`);
                // 构建表单数据对象
                const formData = new FormData();
                formData.append('username', username);
                formData.append('password', password);

                // 获取 form 元素并提交表单
                const form = event.target;
                form.action = 'http://example.com/submit'; // 设置表单提交的 URL
                form.method = 'POST'; // 设置表单提交的方法
                form.submit(); // 提交表单
            }
           render(){

               return (
                   <form onSubmit={this.handleSubmit}>
                        username:<input onChange={this.saveUsername} type="text" name="username" /><br/>
                        password:<input onChange={this.savePassword} type="password" name="password" /><br/>
                        <button>submit</button>
                    </form>
               )
           }   
       }

       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Login />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>

2.2通过受控组件来实现ajax

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

            state = {
                username:'',
                password:''
            }

            saveUsername =(event)=>{
                this.setState({username:event.target.value})
            }

            savePassword =(event)=>{
                this.setState({password:event.target.value})
            }

            handleSubmit = (event)=>{
                event.preventDefault (); //组织表单提交

                const {username,password} = this.state;

                alert(`username:${username},password:${password}`);
                // 构建表单数据对象
                const formData = new FormData();
                formData.append('username', username);
                formData.append('password', password);
                  // 发送表单数据到服务器
                fetch('http://example.com/submit', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    // 处理服务器响应
                    console.log(data);
                })
                .catch(error => {
                    // 处理错误
                    console.error(error);
                });
            }
           render(){

               return (
                   <form onSubmit={this.handleSubmit}>
                        username:<input onChange={this.saveUsername} type="text" name="username" /><br/>
                        password:<input onChange={this.savePassword} type="password" name="password" /><br/>
                        <button>submit</button>
                    </form>
               )
           }   
       }

       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Login />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>

扩展学习-对象

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
    <script type="text/javascript">
        let a = "filed1"
        let obj = {};
        obj[a]='value';
        console.log(obj)
    </script>
</body>
</html>
React系列(四)ref插图1

通过上述的例子,我们可以优化上面例子中的onchange例子

优化1:内联回调函数

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

            state = {
                username:'',
                password:''
            }

            saveFormData = (datatype,event)=>{
                console.log("upload1")
                this.setState({[datatype]:event.target.value})
            }

            handleSubmit = (event)=>{
                event.preventDefault (); //组织表单提交

                const {username,password} = this.state;

                alert(`username:${username},password:${password}`);
                // 构建表单数据对象
                const formData = new FormData();
                formData.append('username', username);
                formData.append('password', password);
                  // 发送表单数据到服务器
                fetch('http://example.com/submit', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    // 处理服务器响应
                    console.log(data);
                })
                .catch(error => {
                    // 处理错误
                    console.error(error);
                });
            }
           render(){

               return (
                   <form onSubmit={this.handleSubmit}>
                        username:<input onChange={event =>this.saveFormData('username',event)} type="text" name="username" /><br/>
                        password:<input onChange={event =>this.saveFormData('password',event)} type="password" name="password" /><br/>
                        <button>submit</button>
                    </form>
               )
           }   
       }

       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Login />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>

优化2:内联函数

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

            state = {
                username:'',
                password:''
            }

            saveFormData = (datatype)=>{
                console.log("upload2")
                return (event)=>{
                    this.setState({[datatype]:event.target.value})
                }
               
            }

            handleSubmit = (event)=>{
                event.preventDefault (); //组织表单提交

                const {username,password} = this.state;

                alert(`username:${username},password:${password}`);
                // 构建表单数据对象
                const formData = new FormData();
                formData.append('username', username);
                formData.append('password', password);
                  // 发送表单数据到服务器
                fetch('http://example.com/submit', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    // 处理服务器响应
                    console.log(data);
                })
                .catch(error => {
                    // 处理错误
                    console.error(error);
                });
            }
           render(){

               return (
                   <form onSubmit={this.handleSubmit}>
                        username:<input onChange={this.saveFormData('username')} type="text" name="username" /><br/>
                        password:<input onChange={this.saveFormData('password')} type="password" name="password" /><br/>
                        <button>submit</button>
                    </form>
               )
           }   
       }

       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Login />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>

2.3非受控组件

<!Doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
   <!-- 准备好一个容器 -->
   <div id="test"></div>

   <!--引入React 核心库-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
   <!--引入React-dom 用于支持React操作DOM-->
   <script type="text/javascript" src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
   <!--引入babel 用于Jsx转换称js-->
   <script type="text/javascript" src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
   <!--引入prop-->
   <script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

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

      
            handleSubmit = (event)=>{
                event.preventDefault (); //组织表单提交
                const username = this.refs.username;
                const {password} = this;
                console.log(this);
                alert(`username:${username.value},password:${password.value}`);
                // 构建表单数据对象
                const formData = new FormData();
                formData.append('username', username.value);
                formData.append('password', password.value);
                  // 发送表单数据到服务器
                fetch('http://example.com/submit', {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    // 处理服务器响应
                    console.log(data);
                })
                .catch(error => {
                    // 处理错误
                    console.error(error);
                });
            }
           render(){

               return (
                   <form onSubmit={this.handleSubmit}>
                        username:<input ref="username" type="text" name="username" /><br/>
                        {/** username:<input ref={(c)=>{this.username=c;}} type="text" name="username" /><br/> **/}
                        password:<input  ref={c =>  this.password = c}  type="password" name="password" /><br/>
                        
                        <button>submit</button>
                    </form>
               )
           }   
       }

       //2、渲染虚拟DOM到页面
       ReactDOM.render(<Login />,document.getElementById('test'))
       /*
       1、React 解析组件<MyCommponment/>
       2、发现组件是类式定义,随后进行实例化,调用里面上的render,返回虚拟的DOM
       3、虚拟的DOM转为真实的DOM,随后呈现在页面中
       */
   </script>
</body>
</html>