React详解

介绍:

React是一个用于构建用户界面的javaScript库,起源于facebook的内部项目,在13年f进行开源

17版本官网:React – A JavaScript library for building user interfaces

18版本官网:React 官方中文文档

特点:

  1. 声明式编码
  2. 组件化编码
  3. React Native 编写原生应用
  4. 高效(优秀的Diffing算法)

一、基础

主要核心,依赖下面四个文件
    <!-- 引入核心库。全局出现React对象-->
    <script type="text/javascript" src="./React-js/16.8/react.development.js"></script>
    <!-- 用于支持react操作DOM。全局出现ReactDOM对象-->
    <script text="text/javascript" src="./React-js/16.8/react-dom.development.js"></script>
    <!-- 用于将jsx转换为js -->
    <script text="text/javascript" src="./React-js/16.8/babel.min.js"></script>
    <!-- 用于对组件标签属性进行限制。全局出现PropTypes对象 -->
    <script src="./React-js/16.8/prop-types.js"></script>

1、基本使用

1.1、虚拟dom

关于虚拟DOM:

  • 本质是object类型的对象(一般对象)
  • 虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM 上:那么多的属性。
  • 虚拟DOM最终会被React转化为真实DOM。呈现在页面上
<body>
    <div id="test"></div>

    <!-- 引入核心库 -->
    <script type="text/javascript" src="./React-js/16.8/react.development.js"></script>
    <!-- 用于支持react操作DOM -->
    <script text="text/javascript" src="./React-js/16.8/react-dom.development.js"></script>
    <!-- 用于将jsx转换为js -->
    <script text="text/javascript" src="./React-js/16.8/babel.min.js"></script>

    <!-- 一定是babel -->
    <script type="text/babel">
        // 创建虚拟dom
        const VDOM = <h1>Hello.React</h1>
        const VDOM2 = <h1>----------------</h1>
        // 渲染虚拟DOM到页面(后面的会替换之前)
        ReactDOM.render(VDOM,document.getElementById('test'))
        ReactDOM.render(VDOM2,document.getElementById('test'))
    </script>
</body>

 2.2、JSX写法

1、全称:  JavaScript XML。

2、react定义的一种类似于XMLJS扩展语法: JS + XML本质是React.createElement(componentprops, ...children)方法的语法糖

3、作用: 用来简化创建虚拟DOM

     写法:var ele = <h1>Hello JSX!</h1>

     注意1:它不是字符串, 也不是HTML/XML标签

     注意2:它最终产生的就是一个JS对象

4、jsx语法规则:

  1. 定义虚拟DOM时,不要写引号。
  2. 标签中混入JS表达式时要用{}-
  3. 样式的类名指定不要用class,要用className.
  4. 内联样式,要用style={ {key : value}}的形式去写。
  5. 只有一个根标签
  6. 标签必须闭合
  7. 标签首字母

         (1).若小写字母开头,则将改标签转为htm1中同名元素,若htm1中无该标签对应的同名元素,则报错。

         (2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。

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

    <!-- 引入核心库 -->
    <script type="text/javascript" src="./React-js/16.8/react.development.js"></script>
    <!-- 用于支持react操作DOM -->
    <script text="text/javascript" src="./React-js/16.8/react-dom.development.js"></script>
    <!-- 用于将jsx转换为js -->
    <script text="text/javascript" src="./React-js/16.8/babel.min.js"></script>

    <!-- js写法 -->
    <script type="text/javascript">
        // 创建虚拟dom
        const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'js写法'))
        // 渲染虚拟DOM到页面(后面的会替换之前)
        ReactDOM.render(VDOM, document.getElementById('test'))
    </script>

    <!-- jsx写法 -->
    <script type="text/babel">
        const data = ['抽烟','喝酒','烫头']
        const obj = {name1:'抽烟',name2:'喝酒',name3:'烫头'}
        const myId = 'song'
        const myData = 'HELLO'
        const VDOM = (
            <div>
                <h1 className="box" id={myId}>
                    <span style={
  { color: 'red', fontSize: '40px' }}>{myData.toLocaleLowerCase()}</span>
                </h1>
                <input type="text" />
                <ul>
                   {
                    // data   // 直接使用数组,会自动遍历
                    // obj     // 对象,会报错
                    data.map((item,i)=><li key={i}>{item}</li>)
                   }
                </ul>
            </div>

        )
        // 渲染虚拟DOM到页面(后面的会替换之前)
        ReactDOM.render(VDOM, document.getElementById('test'))
    </script>
</body>

2、函数式组件

 <script type="text/babel">
        // 定义函数组件
        function Demo() {
            console.log(this);  // 经过babel转化开启严格模式,this没有明确的调用,所以为undefined
            return <h2>函数定义的组件</h2>
        }
        // 渲染组件到页面
        ReactDOM.render(<Demo />, document.getElementById('test'))


        /*
        执行了ReactDOM.render( <MyComponent/>.......之后,发生了什么?
        1.React解析组件标签,找到了MyComponent组件。
        2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOW转为真实DOM,随后呈现在页面中。

        */
    </script>

3、类组件

<script type="text/babel">
        // 定义类组件
        class Demo extends React.Component{
            render(){
                // render:类的原型对象上(可在浏览器控制台输入Demo回车测试),供实例使用
                // this指向Demo的实例对象。俗称:组件对象或组件实例对象
                console.log('render中this',this);
                return (
                    <h2>类定义的组件</h2>
                )
            }
        }
        // 渲染组件到页面
        ReactDOM.render(<Demo />, document.getElementById('test'))


         /*
        执行了ReactDOM.render( <MyComponent/>.......之后,发生了什么?
        1.React解析组件标签,找到了MyComponent组件。
        2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用原型上的render方法
        3.将返回的虚拟DOW转为真实DOM,随后呈现在页面中。
        */
    </script>

3.1、constructor

<script type="text/babel">
        // 定义类组件
        class Weather extends React.Component {
            // 构造器是否接受props,是否传递super,取决于:是否需要在构造器中通过this访问props
            // 若是写了构造器,不给super传props则,在构造器中拿不到props。为undefined
            constructor(props) {    // 构造器只调用一次 
                // super(props)
                super()
                console.log(this.props);
            }
            render() {
                return (
                    <h2 ></h2>
                )
            }
        }

        const p = { name: 'tom', age: 18, sex: '女' }
        // 渲染组件到页面
        ReactDOM.render(<Weather {...p} />, document.getElementById('test'))
    </script>

 

4、组件的三大核心

4.1、state:存放状态

 <script type="text/babel">
        // 定义类组件
        class Weather extends React.Component {
            constructor(props) {    // 构造器只调用一次 
                super(props)
                // 初始化状态
                this.state = {
                    isHot: false,
                    wind: '大风'
                }
                // 改变原型上的demo的this指向,并把原型上的demo赋值到实例上的demo上。处理下面this为undefind
                this.demo = this.demo.bind(this)
            }
            render() {     // 调用1+n次。1:初始化   n:状态更新的次数
                return (
                    <h2 onClick={this.demo}>今天天气{this.state.isHot ? '炎热' : '很冷'}</h2>
                )
            }
            demo() {
                // demo放在哪里? Weather的原型对象上,供实例使用
                //由于demo是作为onclick的回调,所以不是通过实例调用的,是直接调用
                //类中的方法默认开启了局部的严格模式,所以demo中的this为undefined
                console.log('this', this); // undefind

                // 不能直接修改值。数据虽然变化,但页面不刷新
                // this.state.isHot = !this.state.isHot
                // 注意:需要通过setState方法来修改状态
                this.setState({ isHot: !this.state.isHot })
            }
        }
        // 渲染组件到页面
        ReactDOM.render(<Weather />, document.getElementById('test'))

        function demo() {
            // console.log('被点击');
            alert('被点击')
        }
    </script>
(1)、state简写
<script type="text/babel">
        // 定义类组件
        class Weather extends React.Component {
            // 初始化状态
            state = { isHot: false, wind: '大风' }

            render() {    
                return (
                    <h2 onClick={this.demo}>今天天气{this.state.isHot ? '炎热' : '很冷'}</h2>
                )
            }
            // 自定义方法---需要赋值语句的形式+箭头函数
            demo = ()=> {
                console.log('this', this); // undefind

                this.setState({ isHot: !this.state.isHot })
            }
        }
        // 渲染组件到页面
        ReactDOM.render(<Weather />, document.getElementById('test'))

    </script>
    <!-- 
        1、组件中 render方法中的this 为组件实例对象-
        2、组件自定义的方法中this为 undefined,如何解决?
                 a.强制绑定this:通过函数对象bind
                 b.箭头函数
        3、状态数据,不能直接修改或更新
     -->

 4.2、props:接收参数

 <script type="text/babel">
        // 定义类组件
        class Weather extends React.Component {

            render() {
                console.log(this);
                return (
                    <ul>
                        <li>姓名:{this.props.name}</li>
                        <li>性别:{this.props.sex}</li>
                        <li>年龄:{this.props.age}---{this.props.flag}</li>
                    </ul>
                )
            }
        }

        const p = { name: 'tom', age: 18, sex: '女' }

        // 渲染组件到页面
        ReactDOM.render(<Weather {...p} flag={666}/>, document.getElementById('test'))

    </script>
(1)、props限制

    <!-- 用于对组件标签属性进行限制。全局出现PropTypes对象 -->

    <script src="./React-js/16.8/prop-types.js"></script>

 <script type="text/babel">
        // 定义类组件
        class Weather extends React.Component {

            render() {
                console.log(this);
                // 注意:props是只读的
                this.props.speak()
                return (
                    <ul>
                        <li>姓名:{this.props.name}</li>
                        <li>性别:{this.props.sex}</li>
                        <li>年龄:{this.props.age+1}-----</li>
                    </ul>
                )
            }
        }
        // propTypes:给类加规则
        Weather.propTypes = {
            // 在15以及以下版本
            // name:React.PropTypes.string
            // 16版本及以上,需要通过引入PropTypes对象
            name:PropTypes.string,
            sex:PropTypes.string,
            age:PropTypes.number.isRequired,  // isRequired。必传
            speak: PropTypes.func  // 限制为函数
        }
        // 设置不传时的默认值
        Weather.defaultProps = {
            sex:'我是默认值'
        }

        // 渲染组件到页面
        ReactDOM.render(<Weather name="song" age={666} speak={fun}/>, document.getElementById('test'))

        function fun (){
            console.log('我是函数');
        }
    </script>
(2)、简写
<script type="text/babel">
        class Weather extends React.Component {
            // 写在类里面,相当于给类加属性
            static propTypes = {
                name: PropTypes.string,
                sex: PropTypes.string,
                age: PropTypes.number.isRequired,  // isRequired。必传
                speak: PropTypes.func  // 限制为函数
            }
            static defaultProps = {
                sex: '我是默认值'
            }
            
            render() {
                console.log(this);
                // 注意:props是只读的
                this.props.speak()
                return (
                    <ul>
                        <li>姓名:{this.props.name}</li>
                        <li>性别:{this.props.sex}</li>
                        <li>年龄:{this.props.age + 1}-----</li>
                    </ul>
                )
            }
        }


        // 渲染组件到页面
        ReactDOM.render(<Weather name="song" age={666} speak={fun} />, document.getElementById('test'))

        function fun() {
            console.log('我是函数');
        }
    </script>
(3)、在函数组件的使用
// 定义函数组件
        function Weather(props) {
            console.log(this, props);  // 经过babel转化开启严格模式,this没有明确的调用,所以为undefined
            return (
                <ul>
                    <li>姓名:{props.name}</li>
                    <li>性别:{props.sex}</li>
                    <li>年龄:{props.age + 1}-----</li>
                </ul>
            )
        }
        Weather.propTypes = {
            name: PropTypes.string,
            sex: PropTypes.string,
            age: PropTypes.number.isRequired,
        }
        Weather.defaultProps = {
            sex: '我是默认值'
        }


        // 渲染组件到页面
        ReactDOM.render(<Weather name="song" age={666} />, document.getElementById('test'))

 4.3、refs与事件处理

(1)、字符串形式的ref
        class Demo extends React.Component{
            // 展示左侧输入框的数据
            showData = ()=>{
                alert(this.refs.inp1.value)
            }
            // 展示左侧输入框的数据
            showData2 = ()=>{
                alert(this.refs.inp2.value)
            }
            render(){
                return(
                    <div>
                        <input ref="inp1" type="text" placeholder="点击按钮提示数据"/>
                        <button onClick={this.showData}>点击提示左侧的数据</button>&nbsp;
                        <input ref="inp2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
        }
(2)、回调函数形式的ref
        class Demo extends React.Component {
            state = { isHot: true }
            // 展示左侧输入框的数据
            showData = () => {
                alert(this.inp1.value)
            }

            changWeacter = () => this.setState({ isHot: !this.state.isHot })

            /**
             * ref若是以下面内联函数的方式定义,它在更新过程中会别执行两次,
             * 第一次传入参数为null,第二次才是DOM元素
             * 因为每次渲染时都会创建新的函数实例,所以React清空旧的ref,被设置新的、
             * *
             * 不过可以把回调函数定义成class的绑定函数的方式可以避免,
             * 
            */
            saveInp = (c)=>{
                this.inp2 = c; console.log('绑定函数@', c)
            }
            render() {
                const { isHot } = this.state
                // 
                return (
                    <div>
                        <h1>今天天气{this.state.isHot ? '炎热' : '很冷'}</h1>
                        {/* c:input标签。相当于往Demo身上添加了inp1属性,把input标签赋值给它。内联函数方式*/}
                        <input ref={c => { this.inp1 = c; console.log('@', c) }} type="text" placeholder="点击按钮提示数据" />
                        {/* 使用class绑定函数的方式 */}
                        <input ref={this.saveInp} type="text" placeholder="点击按钮提示数据" />
                        <button onClick={this.showData}>点击提示左侧的数据</button>&nbsp;
                        <button onClick={this.changWeacter}>点击切换天气</button>
                    </div>
                )
            }
        }
(3)、API形式的ref
class Demo extends React.Component {
            /** React.createRef
             * 存放被ref标识的节点,但只能单独存一个
             */ 
            myRef = React.createRef()
            myRef2 = React.createRef()

             // 展示左侧输入框的数据
             showData = () => {
                console.log(this.myRef,this.myRef2);
            }
            render() {
                // 
                return (
                    <div>
                        <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
                        <input ref={this.myRef2} type="text" placeholder="点击按钮提示数据" />
                        <button onClick={this.showData}>点击提示左侧的数据</button>&nbsp;
                    </div>
                )
            }
        }
(4)、事件处理
class Demo extends React.Component {
            /** 
             * 1、通过onXxx属性指定事件处理函数(注意大小写)
            * (1)React使用的是自定义(合成)事件, 而不是使用的原生DOM事件  ---为了处理兼容
            * (2)React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)    --- 为了高效
             * 2、通过event.target得到发生事件的DOM元素对象
             */
            myRef = React.createRef()
            myRef2 = React.createRef()

            // 展示左侧输入框的数据
            showData = () => {
                console.log(this.myRef, this.myRef2);
            }
            showData2 = (e) => {
                console.log(e.target.value);
            }
            render() {
                // 
                return (
                    <div>
                        <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
                        <button onClick={this.showData}>点击提示左侧的数据</button>&nbsp;
                        <input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" />
                    </div>
                )
            }
        }
(5)、函数柯里化与高阶函数
/** 
        * *高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
        * 1.若A雨数,接收的参数是一个函数,那么A就可以称之为高阶函数。
        * 2.若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
        *   常见的高阶函数有: Promise、setTimeout、arr.map()等等
        * 
        * *函数的柯里化: 通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。
        */

// 普通写法
function sum(a,b,c){
     return a+b+c
}
const res = sum(1,2,3)

// 柯里化写法
function sum(a){
   return (b)=>{
      return (c)=>{
         return a+b+c
      }
   }
}
const res = sum(1)(2)(3)
/* 普通写法: */
        // class Demo extends React.Component {
        //     state = {
        //         username:'',
        //         password:''
        //     }

        //     // 保存
        //     saveUsername = (e)=>{
        //         this.setState({username:e.target.value})
        //     }
        //     savePassword = (e)=>{
        //         this.setState({password:e.target.value})
        //     }

        //     // 展示左侧输入框的数据
        //     handleSubmit = (e)=>{
        //         e.preventDefault()  // 阻止默认行为
        //         const {username,password } = this.state
        //         console.log('用户名密码:',username,password);
        //     }
        //     render() {
        //         // 
        //         return (
        //             <form onSubmit={this.handleSubmit}>
        //                 用户名:<input onChange={this.saveUsername} type="text" />
        //                 密码:<input onChange={this.savePassword} type="password" />
        //                 <button>登录</button>
        //             </form>

        //         )
        //     }
        // }

        /* 柯里化写法: */
        // class Demo extends React.Component {
        //     state = {
        //         username: '',
        //         password: ''
        //     }

        //     // 保存。柯里化写法
        //     saveData = (dataType) => {
        //         console.log('dataType', dataType);
        //         return (e) => {
        //             this.setState({ [dataType]: e.target.value })
        //         }
        //     }

        //     handleSubmit = (e) => {
        //         e.preventDefault()  // 阻止默认行为
        //         const { username, password } = this.state
        //         console.log('用户名密码:', username, password);
        //     }
        //     render() {
        //         // 
        //         return (
        //             <form onSubmit={this.handleSubmit}>
        //                 用户名:<input onChange={this.saveData('username')} type="text" />
        //                 密码:<input onChange={this.saveData('password')} type="password" />
        //                 <button>登录</button>
        //             </form>

        //         )
        //     }
        // }

        /* 不使用柯里化写法: */
        class Demo extends React.Component {
            state = {
                username: '',
                password: ''
            }

            // 保存。
            saveData = (dataType, data) => {
                console.log('dataType', dataType, data);
                this.setState({ [dataType]: data })
            }

            handleSubmit = (e) => {
                e.preventDefault()  // 阻止默认行为
                const { username, password } = this.state
                console.log('用户名密码:', username, password);
            }
            render() {
                // 
                return (
                    <form onSubmit={this.handleSubmit}>
                        用户名:<input onChange={(e) => this.saveData('username', e.target.value)} type="text" />
                        密码:<input onChange={(e) => this.saveData('password', e.target.value)} type="password" />
                        <button>登录</button>
                    </form>

                )
            }
        }

相关推荐

  1. React详解

    2024-02-02 01:52:02       42 阅读
  2. react详解

    2024-02-02 01:52:02       32 阅读
  3. React useCallback 详解

    2024-02-02 01:52:02       52 阅读
  4. React状态管理详解

    2024-02-02 01:52:02       56 阅读
  5. React 生命周期详解

    2024-02-02 01:52:02       53 阅读
  6. 13 React useEffect 详解

    2024-02-02 01:52:02       35 阅读
  7. React Hooks(实例及详解

    2024-02-02 01:52:02       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-02 01:52:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-02 01:52:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-02-02 01:52:02       87 阅读
  4. Python语言-面向对象

    2024-02-02 01:52:02       96 阅读

热门阅读

  1. @Async导致获取Bean异常‘com.sun.proxy.$Proxy124‘

    2024-02-02 01:52:02       45 阅读
  2. C语言实战三:图书管理系统

    2024-02-02 01:52:02       57 阅读
  3. Redis RCountDownLatch& RSemaphore的应用

    2024-02-02 01:52:02       59 阅读
  4. C++模板判断类中是否存在某个名称的成员函数

    2024-02-02 01:52:02       60 阅读
  5. ZooKeeper客户端实战

    2024-02-02 01:52:02       44 阅读
  6. 433. 最小基因变化

    2024-02-02 01:52:02       56 阅读
  7. MongoDB实战 – 用MongoDB Shell访问MongoDB数据库

    2024-02-02 01:52:02       53 阅读