React的一些基础概念。

0 阅读9分钟

        为什么要用react?在没有框架这个概念之前,我们用原生js中的DOM对象去操作DOM元素,需要用到非常繁琐的各种api去操作DOM元素。这对应的就是开发的时间效率导致的高成本以及入行难。为了解决成本以及开发难度这些问题。在view界面和model数据之间,引入一个中间人vm帮助我们操作dom我们只需要负责数据的声明和增删改查vue和react就是中间人这就是MVVM模型。

       ​编辑

        所以react框架就是一个构建界面的js库,我们通过操作react让react去操作DOM,说白了react就是构建界面ui网页用来代替DOM(在网页中)。react使用有哪些特殊的地方和js相比呢? 1.api简单易懂开发难度低。2.兼容性问题帮我们解决。3.性能更好 会自动比较DOM只更新变化的区域。4.声明式 jsx.5.组件 网页各个部分分为组件 最后拼装。6.服务端渲染 7.快速简单易学

        描述出来终究只是记忆,我们需要去写代码去真正的理解。

1.hello-react

 <!-- 引入react核心库 -->
    <script src="script/react.development.js"></script>
    <!-- 引入DOM库 -->
    <script src="script/react-dom.development.js"></script>
</head>
<body>
    <div id="root">

    </div>
</body>
<script>
    const div = document.createElement('div')//创建的DOM元素
    div.innerText = '我是一个div'
    const root = document.getElementById('root')
    root.appendChild(div)
    const div = React.createElement('div', { id: 'www' }, '我是一个react创建的div');//创建一个react元素
    React.DOMcreateRoot()将一个DOM元素作为参数
    const root = ReactDOM.createRoot(document.getElementById('root'))
    root.render(div)

</script>

        首先我们想用React框架,或者说用react库里面的api方法,我们就需要去引入文件,去文档里面或者地址去存到本地。首先react就是用来操作DOM的,我们先用DOM去给id为root的div标签添加一个子标签。我们用到创建DOM的api 获取DOM的api,以及appendChild()添加子元素。而React帮我们封装后的方法就是创建的react元素,不再是dom元素,我们创建react元素,然后获取dom元素然后定义一个react根元素作为我们想要展示的地方也就是根节点。然后用render()方法将div渲染到根元素。这里看写法是一致的,只不过react操作react元素。

2.React-api

 //创建react元素--所以我们调用react核心库里面的React类
    const button = React.createElement('button', {
        id: "btn", type: 'button', className: 'hello', onClick: () => { alert('点我干嘛') }
    }, '我是一个按钮');
    const div = React.createElement('div', {}, '我是一个div', button)
    //用来创建一个React元素 参数 1.标签名(html标签必须小写)2.标签中的属性 设置事件的时候,属性名需要驼峰命名法,class属性需要className设置 3.元素的内容(子元素)
    //注意点 React元素会通过虚拟DOM转化为真实的DOM元素
    //React元素创建之后无法修改,只能创建新元素去替换
    //如果在点击事件onClick: alert('22')写成这个样子,相当于直接调用了方法,所以传回了一个undefined值
    //获取react根元素,把dom元素转换为一个react根元素
    const root = ReactDOM.createRoot(document.getElementById('root'))
    //将元素在根元素中渲染 根元素就是React元素要插入的位置
    root.render(div);
    const btn = document.getElementById('btn')
    btn.addEventListener('click', () => {
        const button = React.createElement('button', {
            id: "btn", type: 'button', className: 'hello', onClick: () => { alert('点我干嘛') }
        }, 'click me ');
        const div = React.createElement('div', {}, '我是一个div', button)
        //修改React元素后必须对根元素进行渲染
        //调用render渲染页面React会自动比较两次渲染的元素,只在真实DOM更新变化的部分 没变化的保持不变
        //每次修改的时候保证对页面修改是最少的,性能更好
        //root.render()用来将react元素渲染到根元素中(根元素中所有的内容会被删除,被react元素所替换)
        //重复调用render()时 React会将两次的渲染结果比较确保只修改发生变化的元素
        root.render(div)
    })

        介绍一下react以及react-dom库中的api。

​编辑

        首先这个React.createElement()方法使用如图,跟document.createElement()是一样的,只不过能够做更多事情,也就是把DOM多个方法合到了一起,比如这里可以传3个参数 1.标签名(html标签必须小写)2.标签中的属性 设置事件的时候,属性名需要驼峰命名法,class属性需要className设置 3.元素的内容(子元素)。div中也可以直接第三个参数写button指名前面的buttom是子元素。

        ​编辑

        这个就是获取根元素,把dom元素转换一个react根元素,

        ​编辑

        元素会在根元素中渲染,根元素就是react元素要插入的位置。render()这个方法也会做很多事情比如,修改React元素后必须对根元素进行渲染,调用render渲染页面React会自动比较两次渲染的元素,只在真实DOM更新变化的部分 没变化的保持不变,每次修改的时候保证对页面修改是最少的,性能更好,root.render()用来将react元素渲染到根元素中(根元素中所有的内容会被删除,被react元素所替换),重复调用render()时 React会将两次的渲染结果比较确保只修改发生变化的元素。

 3.jsx     

 <!-- 引入react核心库 -->
    <script src="./script//react.development.js"></script>
    <!-- 引入DOM库 -->
    <script src="./script/react-dom.development.js"></script>
    <!-- 引入babel -->
    <script src="./script//babel.min.js"></script>
</head>
<body>
    <div id="root">
    </div>
</body>
<!-- 设置js代码被babel处理 -->
<script type="text/babel">
    //创建一个react元素 <button>为啥一个按钮</button>
    //命令式编程
    // const button = React.createElement('button', {}, '为啥一个按钮')
    //声明式编程 结果导向的编程
    //jsx就是react.createElement()的语法糖简写jsx在执行前都会被babel转化为js代码
    const div = <div>
        <button>为啥一个按钮</button>
    </div>
    //直接通过jsx(js的扩展)创建React元素 jsx需要被翻译为js代码 才能被执行
    //所以要使用jsx必须引入babel翻译 jsx转化为js
    const root = ReactDOM.createRoot(document.getElementById('root'))
    root.render(div)
</script>

        首先我们前面去创建react元素用的都是命令式,告诉react我们要用createElement()这个方法去创建一个react元素,这种太繁琐了,我们希望可以更简便的去创建react或者操作react元素。我们就需要用jsx,是createElement()的语法糖,我们在用之前需要去引入babel库,然后定义js代码类型为babel,会自动转换成js代码。然后就可以写​编辑 这种声明式的代码,babel转换为createElement这种形式。

4.jsx的特点

<script type="text/babel">
    const name = 'www'
    function fn() {
        return ('hello')
    }
    const div = <div id='box' onClick={() => { alert('haha') }} className='box1' style={{ backgroundColor: 'red', border: '10px solid pink' }}>
        <button>为啥一个按钮</button>
        <input type="text " />
        {1 + 1},{name}---{fn()}
        {true} {undefined} {null}
    </div>
    const button = <button>为我我</button>
    alert(button)
    //打印的是字符串如果加上'' 没加直接打印就是一个对象
    const root = ReactDOM.createRoot(document.getElementById('root'))
    root.render(div)
</script>

     jsx的注意事项

        1.不是字符串 不要加引号

        2.jsx中html标签应该小写 React组件应该大写开发

        3.jsx中只有一个根标签 最外层需要根标签包裹

        4.jsx语法必须正确结束 自结束标签比如input必须写/

        5.在jsx中可以使用{}嵌入表达式

               有值的语句就是表达式

         6.表达式如果是null undefined不会显示

        7.jsx中 属性可以直接在标签里吗设置

                 class 需要用className代替 style必须用对象设置

                style={{ backgroundColor: 'red', border: '10px solid pink' }}

                对象外面还需要套{} 外面表示表达式,里面的{}是对像

5.渲染列表

        

<script type="text/babel">
    const name = 'sun'
    const lang = 'en'
    // {}中只能放js表达式不能放语句 if for
    // 语句中可以操作jsx
    // const div = <div>

    //     <button>hello ---{name}</button>
    // </div>
    // let div;
    // if (lang === 'en') {
    //     div = <div>hello---{name}</div>
    // } else {
    //     div = <div>no--hello---{name}</div>
    // }
    const arr = ['liu', 'zhang', 'guan']
    //将arr渲染一个列表
    //jsx{}自动将数组元素在页面展示
    // const div = <div>{arr}</div>
    //我们希望用 <ul>
    // <li></li>
    // <li></li>
    //</ul>去展示数组的每一个元素
    // const list = <ul>
    //     <li>{arr[0]}</li>
    //     <li>{arr[1]}</li>
    //     <li>{arr[2]}</li>
    // </ul>
    const list = <ul>{arr.map((name) => {
        return (<li>{name}</li>)
    })}</ul>
    //根据
    const root = ReactDOM.createRoot(document.getElementById('root'))
    root.render(list)
</script>

         我们希望渲染一个列表到页面上面,一般我们用这种方式。

        ​编辑

     

        但是这种是一个个把数组元素拿出来,如果有100个拿100次吗?所以要用到循环这个方法。我们去这样写,

        ​编辑

        这些无论多少个都会遍历然后渲染到页面上。

6.虚拟DOM 

<script type="text/babel">
    //创建一个数据
    const data = ['sun', 'zhu', 'sha']
    //创建列表
    const list = <ul>
        {data.map((name) => {
            return (<li key={name}>{name}</li>)
        })}

    </ul>
    const root = ReactDOM.createRoot(document.getElementById('root'))
    root.render(list)
    document.getElementById('btn').onclick = function () {
        const data = ['tang', 'sun', 'zhu', 'gou']
        //创建列表
        const list = <ul>
            {data.map((name) => {
                return (<li key={name}>{name}</li>)
            })}

        </ul>
        root.render(list)
    }

        

        在react中我们操作的元素是React元素并不是真正的原生DOM元素,React通过虚拟DOM将react元素和原生DOM元素进行映射,虽然操作的react元素,但是都会在真实DOM体现出来,虚拟DOM的好处--1.降低api的复杂程度2.解决兼容性问题3.提升性能(减少DOM的不必要操作),每当我们调用root.render()时 页面就会重新渲染,React通过diifing算法,将旧的元素和新的元素比较通过比较找到发生变化的元素,只对发生的元素进行修改,没有发生改变的不与处理。

        怎么进行比较呢(diffing)

        1.比较两次数据时先比较父元素 不同的话所有元素全部替换

        2.父一样 在逐个比较子元素 直到找到所有变化的元素为止 完全一致不会修改

        以上面图的案例来演示

        1.当我们在jsx显示数组 数组每一个元素需要设置一个key(唯一的)2.重新渲染页面会按照顺序比较对应的元素 当渲染一个列表不指定key 也会按照顺序进行比较3.如果列表的顺序不发生变化 没有问题 如果发生了变化 会导致性能问题4.比如我们在上面代码更新渲染的时候列表的最前面添加一个tang,其他元素没有改变,但是由于新元素插入到开始位置,其余元素的位置全部发生变化5.而React默认根据位置比较元素 所以所以的元素都会被修改6.为了解决这个问题,设置了key属性。无法在页面中查看相当于ID ,设置了key比较元素会比较相同key元素而不是顺序

这里我们用name作为id 开发时数据一般会给id 尽量不要使用index索引 索引会根据位置改变(只是警告没有了,但是当元素顺序不会改变时用索引没问题)