目录
一、为什么我来安利你学习 React?
二、使用 React 的前置工作
三、简易 demo 学开发
3.1、jsx语法
3.2、函数式组件 demo
3.3、简单类组件定义
3.4、复杂类组件定义
3.4.1、state
写法一:复杂式
写法二:简便式
3.4.2、props
类型限制
props简写
函数式组件props
3.4.3、refs
ref 回调函数
createRef
一、为什么我来安利你学习 React?
效率起飞!!!
以往我们都是通过原生的 js 直接去操作真实 DOM ,而真实的 DOM 相对于虚拟 DOM 更加重量,一旦对真实 DOM 的操作频繁,带来的开销是不可估量的,而 React 却是通过构建虚拟 DOM,再转化为真是 DOM 来呈现在浏览器上,无需真实 DOM 附带繁杂的属性~
二、使用 React 的前置工作
一定要注意,按照以下顺序引入到你的项目中!
1.引入 react 核心库 react.development.js
下载地址:https://unpkg.com/react@18.0.0/umd/react.development.js
2.React 渲染组件 react-dom.developmengt.js
下载地址:https://unpkg.com/react-dom@18.0.0/umd/react-dom.development.js
3.引入 babel 用于将 jsx 转为 js babel.min.js
下载地址:https://unpkg.com/babel-standalone@6/babel.min.js
三、简易 demo 学开发
3.1、jsx语法
我们在 <script type="text/babel"><script/>中编写需要注意一下几点
- 定义虚拟 DOM 时,不要写引号。
- 标签中混入 JS 表达式时需要使用 {}。
- 样式的类名指定不要用 class ,要用 className。
- 内联样式,要用 style={{key:value}} 的形式去写。
- 只能有一个根标签。
- 标签首字母:(1)、若小写字母开头,则将标签转为 html 中的 同名元素,若 html 中无该标签对应的同名元素,则报错。(2)、若大写字母开头,react 就去渲染对应的组件,若组件没有定义,则报错。
如下案例:
<!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>
<style>
    .title{
        background-color: aqua;
    }
</style>
<body>
    <!-- 准备一个容器 -->
    <div id="test"></div>
    <!-- 1.引入 react 核心库 -->
    <script type="text/javascript" src="../model/react.development.js"></script>
    <!-- 2.渲染组件到页面 -->
    <script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
    <!-- 3.引入 babel 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../model/babel.min.js"></script>
    <script type="text/babel">
        //模拟数据
        const data = ['Angular', 'React', 'Vue'];
        const myId = 'tITLe';
        const myData = 'hello react';
        //1.构造虚拟 DOM 
        const VDOM = (
            <div>
                <h1>前端 js 框架列表</h1>
                <ul>
                    {
                        data.map((str, index)=>{
                            return <li key={index}>{str}</li>
                        })
                    }
                </ul>
                <div>
                    <h1 className="title" id={myId.toLowerCase()}>
                        <span style={{color:'white', fontSize:'29px'}}>
                            {myData.toLocaleLowerCase()}
                        </span>
                    </h1>
                    <h1 className="title" id={myId.toUpperCase()}>
                        <span style={{color:'white', fontSize:'29px'}}>
                            {myData.toLocaleLowerCase()}
                        </span>
                    </h1>
                    <input type="text"/>
                </div>
            </div>
        );
        //2.渲染到浏览器
        ReactDOM.render(VDOM, document.querySelector("#test"));
    </script>
</body>
</html>执行结果如下

3.2、函数式组件 demo
<!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>
    <!-- 1.引入 react 核心库 -->
    <script type="text/javascript" src="../model/react.development.js"></script>
    <!-- 2.渲染组件到页面 -->
    <script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
    <!-- 3.引入 babel 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../model/babel.min.js"></script>
    <script type="text/babel">
        function MyComponent() {
            return "这是一个 Demo 组件(首字母必须大写,才可以被 render 追踪为组件)";
        }
        ReactDOM.render(<MyComponent/>, document.querySelector("#test"));
    </script>
</body>
</html>问题:执行了 ReactDOM,render(<Demo/>, document.querySelector("#test")) 之后,发生了什么?
            1. React 解析组件标签,找到了 MyComponent 组件。
             2. 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟 DOM 转为真是的 DOM ,随后呈现在主页面中。
3.3、简单类组件定义
类组件通过继承 React.Component ,重写 render 方法来渲染页面
<!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>
    <!-- 1.引入 react 核心库 -->
    <script type="text/javascript" src="../model/react.development.js"></script>
    <!-- 2.渲染组件到页面 -->
    <script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
    <!-- 3.引入 babel 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../model/babel.min.js"></script>
    <script type="text/babel">
        //创建类式组件(必须继承 React.Component,重写 render 方法)
        class MyComponent extends React.Component {
            render() {
                //render 中的 this 是 MyComponent 的实例对象
                return <h2>我是用类定义的组件(适用于复杂组件的定义)</h2>
            }
        }
        ReactDOM.render(<MyComponent/>, document.querySelector("#test"));
        /*
            执行了 ReactDOM,render(<MyComponent/>, document.querySelector("#test")) 之后,发生了什么?
            1. React 解析组件标签,找到了 MyComponent 组件。
            2. 发现组件是使用类定义的,随后 new 出来该类的实例,并通过该实例调用到原型上的 render 方法
            3.将 render 返回的虚拟 DOM 转为真实的 DOM ,随后呈现在页面中
        */
    </script>
</body>
</html>3.4、复杂类组件定义
3.4.1、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="test"></div>
    <!-- 1.引入 react 核心库 -->
    <script type="text/javascript" src="../model/react.development.js"></script>
    <!-- 2.渲染组件到页面 -->
    <script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
    <!-- 3.引入 babel 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../model/babel.min.js"></script>
    <script type="text/babel">
       //创建组件 
       class MyComponent extends React.Component{
            constructor(props) {
                super(props); //先别管为什么,这个必须有
                this.state = {isHot: true} //这里必须是一个对象
                //解决 changeWeather 中 this 指向问题
                this.nick = this.changeWeather.bind(this);
            }
            render() {
                return <h2 onClick={this.nick}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}!</h2>
            }
            //作为事件进行回调
            changeWeather() {
                //注意:状态不可以直接更改,需要使用内置 API 去更改
                //this.state.isHot = !isHot //这是错误写法
                //获取原来的 isHot 值
                const isHot = this.state.isHot;
                //注意:状态 state 必须通过 setState 更改,并且这里不是覆盖,而是合并 
                this.setState({isHot: !isHot});
            }
       }
       //渲染
       ReactDOM.render(<MyComponent/>, document.querySelector("#test"));
    </script>
</body>
</html>写法二:简便式
<!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>
    <!-- 1.引入 react 核心库 -->
    <script type="text/javascript" src="../model/react.development.js"></script>
    <!-- 2.渲染组件到页面 -->
    <script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
    <!-- 3.引入 babel 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../model/babel.min.js"></script>
    <script type="text/babel">
       //创建组件 
       class MyComponent extends React.Component{
            //初始化状态
            state = {isHot: true}
            render() {
                return <h2 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}!</h2>
            }
            //自定义方法
            //箭头函数的 this 就是外层的类(解决 this 指向问题)
            changeWeather = () => {
                const isHot = this.state.isHot;
                this.setState({isHot: !isHot});
            }
       }
       //渲染
       ReactDOM.render(<MyComponent/>, document.querySelector("#test"));
    </script>
</body>
</html>3.4.2、props
除了类构造器可以进行构造赋值传参, React 还提供了一种方式,就是 props 属性,通过使用 ReactDOM.sender 就可以直接传入参数
<!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="test1"></div>
    <div id="test2"></div>
    <div id="test3"></div>
    <!-- 1.引入 react 核心库 -->
    <script type="text/javascript" src="../model/react.development.js"></script>
    <!-- 2.渲染组件到页面 -->
    <script type="text/javascript" src="../model/react-dom.developmengt.js"></script>
    <!-- 3.引入 babel 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../model/babel.min.js"></script>
    <script type="text/babel">
        
        //定义组件
        class Person extends React.Component {
            render() {
                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" age="19" sex="男"/>, document.querySelector("#test1"));
        ReactDOM.render(<Person name="jerry" age="17" sex="女"/>, document.querySelector("#test2"));
        //更简单的渲染:
        //模拟前端 ajax传入
        const p = {name: "zhangsan", age: 10, sex: "男"}
        ReactDOM.render(<Person {...p}/> , document.querySelector("#test3"));
        //另外若需要修改并合并
        ReactDOM.render(<Person {...p} name="lisi"/>, document.querySelector("#test3"));
    </script>
</body>
</html>类型限制
如果有需要,我们还可以对传入的标签属性进行类型限制或者是默认属性,首先,我们需要引入下面这个库
https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js
代码如下:
        
        //定义组件
        class Person extends React.Component {
            render() {
                const {name, age, sex} = this.props;
                return (
                    <div>
                        <ul>
                            <li>姓名:{name}</li>    
                            <li>年龄:{age}</li>    
                            <li>性别:{sex}</li>    
                        </ul>
                    </div>
                );
            }
        }       
        //对标签属性进行类型必要性的限制
        Person.propTypes = {
            // 限制 name 属性必须为 string,isRequired 表示必须是必填项
            name:PropTypes.string.isRequired,
            // 限制 sex 属性必须为 string 类型
            sex:PropTypes.string,
            // 限制 age 属性必须为 number 属性
            age:PropTypes.number,
            // 限制 speak 属性必须为 函数
            speak:PropTypes.func
        }
        //设置默认属性(如果没有参数传入)
        Person.defaultProps = {
            sex:"不男不女",
            age:18
        }
        function speak() {
            console.log("我要发言了~");
        }
        //渲染
        ReactDOM.render(<Person speak={speak} name="tom" age="19" sex="男"/>, document.querySelector("#test1"));
props简写
直接给类添加propTypes和defaultProps属性,注意:是类属性,不是实例属性,所以加上static关键字
        //定义组件
        class Person extends React.Component {
            constructor(props) {
                /*
                * 拓展
                * 构造器是否接收props,并传递给super,取决于:是否希望在构造器中使用this访问props
                * */
                super(props);
                console.log(this.props) // 通过实例使用props ,这里如果不传递props给super,this.props为undefind,可直接使用props,如下
                console.log(props) //直接使用props
            }
            static propTypes = { //这里是类属性,不是实例
                // 限制 name 属性必须为 string,isRequired 表示必须是必填项
                name:PropTypes.string.isRequired,
                // 限制 sex 属性必须为 string 类型
                sex:PropTypes.string,
                // 限制 age 属性必须为 number 属性
                age:PropTypes.number,
                // 限制 speak 属性必须为 函数
                speak:PropTypes.func
            }
            static defaultProps = {
                sex:"不男不女",
                age:18
            }
            render() {
                const {name, age, sex} = this.props;
                return (
                    <div>
                        <ul>
                            <li>姓名:{name}</li>    
                            <li>年龄:{age}</li>    
                            <li>性别:{sex}</li>    
                        </ul>
                    </div>
                );
            }
        }       
        function speak() {
            console.log("我要发言了~");
        }
        //渲染
        ReactDOM.render(<Person speak={speak} name="tom" age="19" sex="男"/>, document.querySelector("#test1"));函数式组件props
函数式组件不支持state和refs,但是也能使用props以及限制props限制.
        function Person(props) {
            const{name, age, sex} = props
            return (
                <div>
                    <ul>
                        <li>姓名:{name}</li>    
                        <li>年龄:{age}</li>    
                        <li>性别:{sex}</li>    
                    </ul>
                </div>
            );
        }
        //对标签属性进行类型必要性的限制
        Person.propTypes = {
            // 限制 name 属性必须为 string,isRequired 表示必须是必填项
            name:PropTypes.string.isRequired,
            // 限制 sex 属性必须为 string 类型
            sex:PropTypes.string,
            // 限制 age 属性必须为 number 属性
            age:PropTypes.number,
            // 限制 speak 属性必须为 函数
            speak:PropTypes.func
        }
        //设置默认属性(如果没有参数传入)
        Person.defaultProps = {
            sex:"不男不女",
            age:18
        }
        function speak() {
            console.log("我要发言了~");
        }
        //渲染
        ReactDOM.render(<Person speak={speak} name="tom" age="19" sex="男"/>, document.querySelector("#test1"));3.4.3、refs
在原生js中,通常使用document.getElementById、document.querySelector等这种类似的操作来获取我们需要的DOM元素
React为我们提供了一种非常特殊的属性 ref,你可以用来绑定到 render() 输出的任何组件上
下面是几个适合使用 refs 的情况:
- 管理焦点,文本选择或媒体播放。
- 触发强制动画。
- 集成第三方 DOM 库。
- 不能在函数组件上使用 ref 属性,因为他们没有实例
字符串形式的ref
给组件添加ref属性 ref="refName",然后就能通过在示例方法中通过this.refs.refName获得DOM
class Demo extends React.Component {
    // 点击按钮时,显示左边输入框的数据
    showInputData1 = () =>{
        // 通过获取id的方式
        // const input = document.getElementById('input1')
        // alert(input.value)
        // 通过ref
        const { input1 } = this.refs
        alert(input1.value)
    }
    // 右边输入框失去焦点时,显示右边输入框的数据
    showInputData2 = () => {
        const { input2 } = this.refs
        alert(input2.value)
    }
    render() {
        return (
            <div>
                <input ref="input1" id="input1" type="text" placeholder="点击按钮提示数据"/> 
                <button onClick={this.showInputData1}>点击提示左边的数据</button> 
                <input onBlur={this.showInputData2} ref="input2" type="text" placeholder="失去焦点提示数据"/>
            </div>
        )
    }
}
Ps:字符串形式的ref虽然方便,但是效率并不高,所以官方不建议使用,并可能会在未来的版本被移除
ref 回调函数
React 还支持另一种设置 refs 的方式,称为“回调 refs”。它能助你更精细地控制何时 refs 被设置和解除。
内联函数语法:ref={ currentNode => this.input1 = currentNode } —— 把ref当前所处的节点挂载在实例自身上,并取名为input1
回调函数语法:ref={ this.input2 } —— 把当前节点传递给回调函数input2
class Demo extends React.Component {
    // 点击按钮时,显示左边输入框的数据
    showInputData1 = () =>{
        // 通过ref
        const { input1 } = this
        alert(input1.value)
    }
    // 右边输入框失去焦点时,显示右边输入框的数据
    showInputData2 = () => {
        alert(this.input2.value)
    }
    saveInput = (currentNode) => {
        this.input2 = currentNode
    }
    /*
    *  ref={ currentNode => this.input1 = currentNode }
    *   把ref当前所处的节点挂载在实例自身上,并取名为input1
    * */
    render() {
        return (
            <div>
                <input ref={ currentNode => this.input1 = currentNode }/*内联函数*/ id="input1" type="text" placeholder="点击按钮提示数据"/> 
                <button onClick={this.showInputData1}>点击提示左边的数据</button> 
                <input onBlur={this.showInputData2} ref={ this.saveInput /*使用类绑定的函数作为回调函数*/} type="text" placeholder="失去焦点提示数据"/>
            </div>
        )
    }
}
createRef
使用 React.createRef() 创建ref,并通过 ref 属性附加到 React 元素
React.createRef调用后会返回一个容器,该容器可以存储被ref所标识的节点
render执行的时候,发现有一个ref,而且是用createRef创建的容器,就会将当前ref所在的节点存储到这个容器里面
  
class Demo extends React.Component {
    myRef = React.createRef(); // 一个节点单独使用一个
    showInputData = () =>{
        const { current } = this.myRef;
        alert(current.value)
    }
    render() {
        return (
            <div>
                <input ref={ this.myRef } id="input1" type="text" placeholder="点击按钮提示数据"/> 
                <button onClick={this.showInputData}>点击提示左边的数据</button>
            </div>
        )
    }
}




















