一、react认识
用于构建用户界面的 JavaScript 库
npx create-react-app my-app cd my-app npm start
-
分析react项目
node_modules:依赖包
src:核心代码
App.css:根组件的样式
App.js:更组件
App.text:根组件的测试文件
index.css:全局样式
index.js:入口文件,特点是这个文件中写的代码,都会被执行,在这个项目启动的时候
reportWebVitals:兼容浏览器
setTests.js:做测试
-
分析index.js 入口文件
//入口文件 import React from 'react'; //引入react=》获取到react 提供api import ReactDOM from 'react-dom/client'; //将 虚拟dom => 真实dom import './index.css'; //全局样式 import App from './App'; //引入根组件 console.log(ReactDOM); //将 虚拟dom => 真实dom =挂载到对应的位置 const root = ReactDOM.createRoot(document.getElementById('root')); //挂载到对应的位置 root.render( //虚拟dom => 真实dom <App /> );
三、jsx
-
什么是jsx
就是JavaScript和html的结合
-
特点:
-
可以js:就是vue指令,
-
更加的安全
-
-
相对于html的区别
-
类名:className
-
事件处理:on事件类型
-
四、指令
1:动态数据
语法:{ }
在{ }内可以写:1. 动态值,2. 四则运算,3. 三元运算符,4. js语法
function App(){ //函数体 => vue3 script setup //定义数据 =》可变 ,不可变 let name = '张三' let age = 30 let num = 61 function add(){ return 1+1 } return( <div> <h2>你好{name}同学</h2> <h2>{age+1}</h2> <h2>{num>60?'及格':'不及格'}</h2> <h2>{add()}</h2> </div> ) } export default App
2:条件渲染
// 条件判断 /* 条件判断 => 如果不显示 => 元素是不创建的(相当于v-if) 单个: => 语法 => {} + 三元运算符 多个: => 语法 => {} + 定义方法 JavaScript 条件渲染 */ // 条件渲染 在react当中 处理条件渲染,单个 /// 语法: {}结合 三元运算符 // function App(){ // let num=62; // return( // <div> // {/* 处理单个条件判断 */} // { // num>=60?<Children>及格</Children>:<div>不及格</div> // } // </div> // ); // function Children(){ // return ( // <div>及格</div> // ) // } // } // 多个 // 语法 => {}+处理方法 // 大于60 到 70 => 及格 大于85 优秀 function App(){ console.log('created'); // 本质 => 函数体 => 默认组件的声明周期 => created => 初始化属性 let num=68; function changeNum(){ if(num>=60 && num<=70){ return ( <div>及格</div> ) } else if(num>70&&num<85){ return ( <div>良好</div> ) } else if(num>=85){ return( <div>优秀</div> ) } else{ return ( <div>不及格</div> ) } } return( <div> {/* 处理多个条件判断 */} {changeNum()} </div> ) } // 导出export export default App
3、列表渲染
-
作用:当布局有相同时候,如果有多个,我们可以使用列表渲染
-
语法:{ } +map
-
map:数组循环,返回一个新的数据
-
function App(){ let list=['🍉','🍇','🍍','🍌','🍈']; // let arr=list.map((item,index)=>{ // return item // }) return( <div> {/* 旧的写法 */} {/* <h2>🍉</h2> <h2>🍇</h2> <h2>🍍</h2> */} { list.map((item,index)=>{ return ( <h2 key={index}>{item}</h2> ) }) } </div> ); } export default App
4、动态属性
-
动态样式
-
语法:就是元素上的属性 className={}
import './App.css' //动态样式 //语法=》就是我们的元素 上的属性={} // data-num={num} 是自定义属性 function App(){ let num = 11 return( <div> <h2 className={num>10?'itemActions':''} data-num={num}>张三</h2> </div> ) } export default App
5、事件处理
-
语法: on事件类型={嵌套函数},
-
给元素添加事件:语法:on事件类型 = {()=>事件处理函数() },onClick={ ()=>事件处理函数() }
-
-
事件传递参数:本质就是一个 函数的声明和函数的调用
-
事件对象:事件的嵌套函数第一层,事件的第一个参数,就是事件对象(e)
-
事件冒泡:阻止事件冒泡,方法:事件对象.stopPropagetion()
// 事件处理 // 语法: on事件类型={嵌套函数} // 给元素添加事件 // 语法:on事件类型 = {()=>事件处理函数} // 1 为什么要写一个嵌套函数 // 因为 react => 将模板内容(jsx语法) => 变成 虚拟dom(React.createElement()) // 如果发现有事件处理,将所有事件 合成 一个事件,自动执行第一层 // function App() { // let changeAdd = () => { // console.log("触发事件"); // }; // return ( // <div> // <h2>你好 同学</h2> // <button onClick={()=>changeAdd()}>点击触发</button> // </div> // ); // } // export default App // 事件传递参数 => 本质就是一个 函数的声明和函数的调用 // function App(){ // let changeAdd=(...a)=>{ // console.log("事件触发",a); // } // return( // <div> // <h2>你好同学</h2> // <button onClick={()=>changeAdd('100','200', // '300')}>点击传参</button> // </div> // ) // } // 3 事件传参 => 事件的嵌套函数第一层,事件的第一个参数,就是事件对象 // function App() { // let changeAdd = (e) => { // console.log("事件对象", e); // }; // return ( // <div> // <h2>你好 玲儿</h2> // <button onClick={(e)=>{changeAdd(e)}}>点击传递事件对象</button> // </div> // ); // } // 事件冒泡 // 方法:事件对象.stopPropagetion() function App(){ let changeAdd=(e)=>{ e.stopPropagation(); // 阻止事件冒泡 console.log('子组件事件对象',e); } let fatherC=()=>{ console.log('father') } return( <div onClick={()=>{fatherC()}}> <h2>你好 玲儿</h2> <button onClick={(e)=>changeAdd(e)}>点击看看有没有冒泡</button> </div> ) } export default App;
6、双向数据绑定:受控组件
-
双向数据绑定:可以在逻辑层获取到视图层数据,又可以将这个数据传递视图层
-
工作中使用的场景? 获取到用户的数据=》from 表单系列的
-
// 处理动态数据 => useState import { useState } from "react"; // useState()=> 返回值 => [数据,修改数据的方法] // 实现双向数据绑定 // 1 input 元素的动态属性 // 2 给input元素绑定事件 input // 3 获取input 事件触发输入内容 => 通过事件对象 function App() { // 逻辑层 let [name, setState] = useState(""); // 接收视图层输入的值 const changeInput = (e) => { console.log(e.target.value); //获取到用户输入的内容 // 4 需要把获取到用户的内容再赋值给动态数据 => name setState(e.target.value); }; return ( <div> 用户名称:<input value={name} onInput={(e) => changeInput(e)}></input> </div> ); } export default App;
1、组件的创建:两种方式,函数的方式创建组件,class创建组件
函数组件
-
函数式组件就是函数
-
函数名称必须首字母大写:自己创建的组件
-
有return:就是自己写的页面布局(template)
-
这个函数体,第一层定义的属性,就是这个函数的属性、方法、动态数据
function App() { return ( <div className="App"> <h2>你好通信</h2> </div> ); } export default App;
class组件
2、组件之间的数据传递
父组件给子组件传递数据
-
在父组件中通过属性方式传递数据 ,
-
子组件中props 接收这个数据
-
本质:元素(组件)添加属性,这个属性被react 底层自动处理成这个函数的参数=> { }类型
// 组件的数据传递 /* 1) 父组件给子组件传递数据 方法 => 通过属性的方式 */ import "../App.js"; function App() { let money = 100; const change = () => {}; return ( <div> 这里是父组件 {/* 父组件给子组件传递数据通过属性方式 */} {/* 本质 => 元素(组件)=> 添加属性 这个属性会react 底层自动处理成 这个函数的参数 => {}类型 */} <Children money={money} data="5000" change={change}></Children> </div> ); } function Children(props) { console.log(props); // object{change:()=>{},data:"5000",money:100} return <div>这是子组件 Children get father {props.data}</div>; } export default App;
子组件给父组件传递数据
-
在父组件中定义方法,
-
在父组件中通过属性方式传递这个方法,
-
在子组件中用props接收这个方法并调用,给这个方法并传入实参即为给父组件传递的数据
-
// 组件的数据传递 /* 1) 子组件给父组件传递数据 解决 方法 => 通过自定义方法 本质 => 函数的声明和函数调用 */ function App() { // 1. 在父组件中声明方法 const getChildren = (value) => { console.log("获取到子组件的数据",value) }; return ( <div> 这里是父组件 {/* 2 再把这个方法传递给子组件 */} <Children getChildren={getChildren}></Children> </div> ); } function Children(props) { console.log(props); // object{getChildren:()=>{}} const getFather=()=>{ // 3 在子组件中调用父组件声明的方法 props.getChildren(10000); } return (<div> <button onClick={()=>getFather()}>给父组件传递的数据</button> </div>); } export default App;
本地存放数据传递参数
sessionStorage、localStorage、cookies
3、组件的组合
-
组件的组合,相当于vue中的模块化处理
-
function App() { return ( <div> {/* 页面级组件继承组合 */} <Swiper></Swiper> <CommentS></CommentS> <HotPlay></HotPlay> <LisBooks></LisBooks> <NewSong></NewSong> </div> ); }
六、react的更新机制:组件的重新创建
react的更新机制:重新创建组件(只要有数据更新,组件就会重新创建)
问题:就是在项目中,只要有数据更新,组件就会重新创建,会造成性能损耗
react组件更新机制:组件的重新创建,只要数据发生改变,组件就会重新创建,会造成性能问题
组件的渲染:先渲染父组件,在渲染子组件
问题1:在子组件中更新数据,如果没有将子组件进行模块化划分,那么父组件也会重新创建,会导致性能问题
解决方法:
-
模块化开发:组件的模块化划分,将子组件进行抽离(一个功能一个模块),此时:(子组件数据更新,该子组件会重新创建,其父组件与兄弟组件不会重新创建)
问题2:如果我们在父组件中更新数据 => 会重新渲染组件 => 这个父组件的嵌套组件(子组件),也会被重新渲染 => 会导致性能问题
解决方法:
1. 缓存组件:React.mome(需要被缓存的组件); 缓存组件,不管父组件是否重新创建,这个子组件创建一次,如果子组件的数据没有改变,就不需要重新创建
// react 更新机制 => 组件重新创建 import React, { useState } from "react"; // // 组件模块化划分 // function App() { // console.log("father 组件重新创建了"); // return ( // <div> // {/* 模块化划分 */} // <Children2></Children2> // <Children1></Children1> // </div> // ); // } // function Children2() { // console.log("children2222222222 组件重新创建"); // let [salary, setSalary] = useState(1800); // const changeSalary = () => { // setSalary(salary + 200); // }; // return ( // <div> // 月入{salary} // <button onClick={() => changeSalary()}>更新数据+200</button> // </div> // ); // } // function Children1() { // console.log("children111111 组件重新创建"); // return <div>children</div>; // } function App() { console.log("father 组件重新创建了"); let [salary, setSalary] = useState(1800); const changeSalary = () => { setSalary(salary + 200); }; return ( <div> 月入{salary} <button onClick={() => changeSalary()}>更新数据+200</button> {/* 不管父组件是否重新创建,这个子组件创建一次,如果子组件的数据没有改变,就不需要重新创建 */} <Keepchildren1></Keepchildren1> </div> ); } /* React.memo()=> 缓存组件 语法: React.memo(需要缓存的组件) => 缓存组件 特点: 缓存组件 如果这个组件属性值没有变化就不会创建,反之,就会重新创建 */ function Children1() { console.log("children111111 组件重新创建"); return (<div>children</div>) } let Keepchildren1=React.memo(Children1) export default App; // 1 组件的渲染 => 先渲染父组件,再渲染子组件 // 2 如果我们在父组件中更新数据 => 会重新渲染组件 => 这个父组件的嵌套组件(子组件),也会被重新渲染 => 会导致性能问题 // 解决方法(子组件数据更新,该子组件会重新创建,其父组件与兄弟组件不会重新创建) // 1 模块化开发 => 一个功能一个模块