网页的局部刷新:ajax发请求,用户感知不到;js收到响应数据后,根据不同的结果来操作dom完成对页面的修改
在React中,我们操作的是React元素,并不是原生真实的dom元素
我们去修改dom, api复杂、考虑浏览器兼容性、性能不高,使用起来不方便;我们的框架可以帮助我们操作dom,我们不用直接操作dom,vue和react都有虚拟dom和diff算法,帮我们尽量减少真实dom的修改
基本使用:创建一个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>
<script
crossorigin
src="https://unpkg.com/react@18.0.0/umd/react.production.min.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18.0.0/umd/react-dom.production.min.js"
></script>
</head>
<body>
<div id="root"></div>
<script>
// 原生js创建一个div元素展示到页面
// const div = document.createElement("div");
// div.innerText = "原生dom生成的div";
// document.getElementById("root").appendChild(div);
// 1 创建一个react元素,它不是dom元素
const div = React.createElement("div", {}, "这是react创建的div");
// 2 获取根元素对应的react元素(盒子),接收一个dom元素
const root = ReactDOM.createRoot(document.getElementById("root"));
// 3 将div渲染到根元素中
root.render(div);
</script>
</body>
</html>
const reactDom=createElement('div',{},'')
作用:创建一个react元素
参数:
1》元素的名称,必须小写
2》标签中的属性
class属性需要使用className来设置,因为class是一个关键字
在设置事件时,属性名需要改为驼峰命名法,为了区分原生
3》子元素(元素内容)
注意点:React元素最终会通过虚拟dom转换为真实的dom元素
React元素一定那创建就无法修改 ,只能替换
修改React元素后,必须重新进行渲染
<script>
function changeBtnContent(content) {
const button = React.createElement(
"button",
{
type: "button",
id: "btn",
},
content
);
const div = React.createElement(
"div",
{ id: "div", className: "box" },
"div盒子的内容",
button
);
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(div);
}
changeBtnContent("点我");
setTimeout(() => {
const btn = document.querySelector("#btn");
btn.addEventListener("click", () => {
changeBtnContent("没问题,~");
});
}, 1000);
</script>
获取根元素,根元素就是react元素要插入的位置
const root=ReactDOM.createRoot(document.querySelector("#root"))
用来将react元素渲染到根元素中
根元素中所有的内容都会被删除,被react元素所替换,不会修改容器,只会修改容器的子节点
重复调用render时,会比较两次的虚拟dom,确保只修改发生变化的元素,真实dom修改最少化
JSX是js的语法扩展,是得我们可以以类似html的形式去使用js;
它是reac声明式编程的体现,是结果导向的编程 ;
JSX是React.createElement()的语法糖 ,JSX最终都会转换为调用React.createElement()创建元素的代码
使用JSX必须引入babel来进行编译;
<body>
<div id="root"></div>
<script
crossorigin
src="https://unpkg.com/react@18.0.0/umd/react.production.min.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18.0.0/umd/react-dom.production.min.js"
></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script type="text/babel">
const div = (
<div>
div的文字<button>按钮</button>
</div>
);
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(div);
</script>
</body>
JSX注意事项:
1》JSX不是字符串,不需要加引号
2》JSX中所有的html标签应该小写,React组件应该大写开头
3》JSX中有且只有一个根标签
4》JSX的标签必须正确结束,html5中单标签可以省略/ ;但是JSX中不行
5》在JSX中可以使用大括号{}来其纳入表达式(表达式就是有值的语句)
6》如果表达式是null,boolean,undefined,将不会显示
7》在JSX中,属性可以直接赋值在标签中;但是class需要使用className, style={{backgroundColor:“red”}}
<script type="text/babel">
const uname = "--拥抱变成了煎熬";
const div = (
<div
className="flower"
style={{ backgroundColor: "skyblue", border: "2px solid red" }}
>
花田里犯了错
{uname}
{null}
{undefined}
</div>
);
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(div);
</script>
8》列表渲染
在JSX中,{}只能用来放js表达式,而不能放(if、for等语句); 但是js语句中可以操作JSX
在JSX中,如果直接放入一个数组,他会自动的遍历
<script type="text/babel">
let arr = ["first", "second", "third"];
const ul = <ul>{arr}</ul>;
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(ul);
</script>
数组生成列表
<script type="text/babel">
let arr = ["first", "second", "third"];
const jsxArr = [];
// for (let i = 0; i < arr.length; i++) {
// jsxArr.push(<li>{arr[i]}</li>);
// }
// const ul = <ul>{jsxArr}</ul>;
// es6中map直接操作数组的每一项
arr = arr.map((item) => <li>{item}</li>);
const ul = <ul>{arr}</ul>;
// 由于有返回值,所以也可以这样写;只是可读性差点,复杂的就还是分开
// const ul = (
// <ul>
// {arr.map((item) => (
// <li>{item}</li>
// ))}
// </ul>
// );
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(ul);
</script>
React通过虚拟DOM,将React元素和原生dom进行映射,虽然操作的是React元素,但是这些操作最终都会在真实dom中体现出来
虚拟dom的好处:
1》降低API复杂度;
2》解决兼容性问题;
3》减少不必要的dom操作,提示性能
每次调用root.render(),页面聚会重新渲染;React会同故宫diff算法,将新的元素和旧的元素进行比较;只会对发生变化的元素进行修改
<button class="btn">修改列表内容</button>
<div id="root"></div>
<script type="text/babel">
function showDom(arr) {
const ul = (
<ul>
{arr.map((item) => (
<li>{item}</li>
))}
</ul>
);
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(ul);
}
showDom(["a", "b", "c"]);
const btn = document.querySelector(".btn");
btn.onclick = () => {
showDom(["a", "b", "c", "d"]);
};
</script>
在我点击按钮的时候,在列表中增加了一个li,其他的元素并没有变化
它首先比较的式父元素,比较完父元素再比较子元素,子元素的类型和内容有没有变化,从第一个子元素开始比较,按顺序比较,这是它默认的比较方式
但是有一个问题,比如我们点击传入的数组式[“d”,“a”, “b”, “c”],那么新的第1、2、3、4个li的内容分别和原来的第1、2、3比较,都不一样,导致所有的li都需要更新,显然是不好的
所以React提供了一个key值,数组中的每一个元素都设置一个唯一的key,那么比较的时候按照key来比较,而不是默认的子元素顺序比较;
<ul>
{arr.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
这样原来三个li,key值分别为a、b、c; 点击按钮新生成的key分别为a、b、c、d;a、b、c比较时内容和类型都没有变,所以不需要更新,只需要新增d
注意:
我们一般采用id作为key值,因为他们唯一,而且是不会变化的;这样就可以保证我们比较的时候,即使顺序变了,也能保证没变的不更新
尽量不要使用index作为key,因为它会随着顺序的改变而变化,所以使用索引index作为key和跟没有key一样;只是控制台不会警告;只是如果元素的顺序不会发生变化时,使用index作为key也没问题