-
用于构建用户界面的
JavaScript库 -
脚手架创建项目
-
指令:
npx create-react-app 项目名称 -
项目目录分析
node_modules:依赖包public:公共文件src:核心代码App.css:根组件样式App.js:根组件App.text.js:根组件的测试index.css:全局样式index.js:入口文件(此文件中的代码在项目启动时都会被执行)reportWebVitals.js:兼容浏览器setupTests.js:做测试
-
分析入口文件index.js
// index.js import React from 'react'; // 引入react,得到react的api import ReactDOM from 'react-dom/client'; // 将虚拟DOM(vnode)=>真实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 /> ); -
初识函数式组件
- 就是一个函数
- 函数名必须首字母大写
- 有**
return**,写页面布局,相当于vue中的template - 函数体第一层定义的属性,就是该组件的属性、方法、动态数据,相当于
vue中的setup,相当于生命周期created
JSX
JSX是一个JavaScript的语法扩展,就是 js 和 html 的结合- 特点:
- 可以写js,也就是指令
- 更加的安全(JSX可以防止注入攻击)
JSX相对于html的区别:jsx类名 =>className- 事件 =>
on事件类型
指令
动态数据(插值)
-
语法:{ 表达式 }
- 表达式:变量、四则运算、三元运算、js...
function App() { let name = '喜羊羊' let num = 11 return ( <div> <h3>你好,{name}!</h3> <h4>今年{num + 1}岁啦</h4> </div> ); }
条件渲染
-
单个条件渲染
-
语法:
{ }+三元运算符function App() { let num = 61 return ( // 模板 <div> {num >= 60 ? <Children /> : <h6>不合格</h6>} </div> ); } // 子组件 function Children() { return ( <h1>合格</h1> ) }
-
-
多个条件渲染
-
语法:
{ }+处理函数function App() { let num = 61 // 处理函数 function chchangeNum() { if (num >= 80) { return (<h3>优秀</h3>) } else if (num >= 60 && num < 80) { return (<h4>合格</h4>) } else { return (<h5>不合格</h5>) } } // 模板 return ( <div> {chchangeNum()} </div> ); }
-
列表渲染
-
语法:{ } +
map- **
map**会返回一个新数组
- **
-
作用:当布局有多个相同的时,可以使用列表渲染
function App() { let list = ['🍉', '🍊', '🍑'] return ( <div> { list.map((item, index) => { return (<h3 key={index}>{item}</h3>) }) } </div> ); } -
**注意:**列表循环需要添加
key#***** 为什么需要添加key? 答: 底层更新(列队的数据)通过key 来判断是否是相同的元素, 如果是则复用,如果不是则重新创建, 底层的diff 算法
动态样式(属性)
-
语法:元素属性使用 { }
import "./App.css"; // 引入样式 function App() { let num = 12 return ( <div> <h2 className={num > 10 ? 'bindActive' : ''} data-num={num}> 张三</h2 > </div > ); }
事件处理
-
语法:
on事件类型={()=>事件处理函数}#***** 为什么要写一个嵌套函数? 答: 因为react 将模板内容(jsx语法) 变成 虚拟DOM(React.createElement()) 如果发现有事件处理,则将所有事件合成 一个事件,并'自动执行第一层'function App() { function btn() { console.log('事件触发'); } return ( <div> <button onClick={() => btn()}>点击</button> </div > ); } -
事件传参
function App() { let btn = (...argument) => { console.log('事件传参:', argument); } return ( <div> <button onClick={() => btn('美羊羊', 18)}>点击</button> </div > ); } -
事件对象
-
事件对象的嵌套函数第一层的第一个形参,就是**
事件对象**function App() { let btn = (e) => { console.log('事件对象:', e); console.log('事件目标:', e.target); } return ( <div> <button onClick={(e) => btn(e)}>点击</button> </div > ); }
-
-
阻止事件冒泡
-
语法:
事件对象.stopPropagation()function App() { let btnFather = () => { console.log('父元素触发'); } let btnSon = (e) => { e.stopPropagation() // 阻止事件冒泡 console.log('子元素触发'); } return ( <div> <div onClick={() => { btnFather() }}> 父元素 <button onClick={(e) => btnSon(e)}>子元素</button> </div> </div > ); }
-
-
阻止默认行为
事件对象.preventDefault()
受控组件(双向数据绑定)
-
可以在逻辑层获取到视图层数据,可又以将这个数据传递到视图层
-
用户可以修改 js层的数据,把这样的组件,叫做
受控组件 -
步骤:
1.引入react的useState 2.表单元素绑定动态属性 3.给表单元素绑定事件 4.通过事件对象获取到表单value并赋值 -
useStateimport { useState } from 'react' //引入 let [name, setName] = useState('默认值')
// 引入react中的useState
import { useState } from 'react'
function App() {
// 逻辑层
let [name, setName] = useState('')
let changeIpt = (e) => {
console.log(e.target.value); // 获取表单的值
setName(e.target.value) //赋值给动态数据
}
return (
<div>
<input value={name} onInput={(e) => changeIpt(e)}></input>
</div>
);
}
组件
创建组件
-
创建方式:
- 使用函数创建组件:函数式组件(推荐)
- 使用
class创建组件:类组件(旧方式不推荐,后面再补充)
-
函数式组件
-
特点:
1.函数名首字母必须大写 2.函数的return,就是组件的内容 3.函数体就是组件的js,逻辑层 4.当该函数被调用,相当于触发了组件的created生命周期,初始化完毕组件的属性 -
使用:
<函数名></函数名><函数名 />
function App() { // 组件js,逻辑层 let name = '喜羊羊' console.log(name); return ( <div>{name}</div> ); } -
父传子
-
父组件通过子组件的
根标签的属性传递参数<Son money={money} fn={fn} data='200'></Son> -
子组件通过
组件函数的形参props来接收,接收的是一个对象function Son(props) { return (<div>子组件</div>) }
function App() {
let money = 10
const fn = () => {
console.log('传给子组件的方法');
}
return (
<div>
父组件
<Son money={money} fn={fn} data='200'></Son>
</div>
);
}
// 子组件
function Son(props) {
// 子组件使用形参props接收父组件传来的数据
console.log(props);
return (
<div>子组件</div>
)
}
子传父
-
本质:函数的声明和调用
-
在子组件中调用父组件中的方法
-
步骤
1.父组件中声明方法,形参value用来接收子组件传来的参数 2.方法传递给子组件 3.在子组件中调用父组件的方法
function App() {
const fn = (value) => {
console.log('获取到子组件的数据:', value);
}
return (
<div>
父组件
<Son fn={fn}></Son>
</div>
);
}
// 子组件
function Son(props) {
const sonFn = () => {
props.fn(100)
}
return (
<div>
<button onClick={() => { sonFn() }}>子组件</button>
</div>
)
}
本地存储
- 使用浏览器的本地存储
provider和inject
useContext- 在
hooks中进行详细解释
redux
- 全局状态管理
- 在后面做详细解释
组件的组合
-
在
react中,只要有自己的功能模块,就需要进行抽离(模块化划分)function App() { return ( <div> <Swiper></Swiper> <CommentS></CommentS> <HotPlay></HotPlay> <LisBooks></LisBooks> <NewSong></NewSong> </div> ); }
封装组件
-
思路
1.完成基本样式 2.确定动态属性 3.添加事件、组件通信 -
🌰
// 封装input组件 function Zeroinput(props: any) { let [type, setType] = useState(props.type) // input类型 let [isEmpty, setIsEmpty] = useState(false) // 校验是否为空 let [value, setValue] = useState('') // input表单的值 let [flag, setFlag] = useState(false) // 控制表单是否开启校验 // 隐藏密码 const changehide = () => { setType('password') } // 显示密码 const changeshow = () => { setType('text') } // 明密文切换 const eye = () => { // 由于ract的更新机制是重新加载组件,所以此处陆毅不使用监听器 if (type == 'text') { return (<i onClick={() => changehide()} className={'iconfont ' + 'icon-xianshi'}></i>) } else { return (<i onClick={() => changeshow()} className={'iconfont ' + 'icon-yincang'}></i>) } } // 监听 useEffect(() => { if (!value && flag) { // 表单value值为空且已输入过内容 setIsEmpty(true) } else { setIsEmpty(false) } }, [value]) // 受控组件(事件双向绑定) const getValue = (e: any) => { setValue(e.target.value) setFlag(true) // 此时开启表单非空校验 } return ( <div className='zeroinput'> {/* icon图标 */} {props.icon ? <i className={'iconfont ' + props.icon}></i> : ''} {/* input */} <input onInput={(e) => getValue(e)} type={type} placeholder={props.placeholder} value={value} /> {/* 明密文 */} {props.eye ? eye() : ''} {/* 校验提示 */} {isEmpty ? <div className='isEmpty'>不能为空哦~</div> : ''} </div> ) } export default Zeroinput//使用封装的input组件 <Zeroinput placeholder='请输入手机号' type='text' icon='icon-shoujihao' /> <Zeroinput placeholder='请输入密码' type='password' icon='icon-mima' eye />