使用create-react-app快速搭建开发环境
执行命令: npx create-react-app react-basic
1. npx Node.js工具命令,查找并执行后续的包命令
2. create-react-app 核心包(固定写法),用于创建React项目
3. react-basic React项目的名称(可以自定义)
创建React项目的更多方式 https://zh-hans.react.dev/learn/start-a-new-react-project
JSX基础-概念和本质
概念:JSX是JavaScript和XML(HTML)的缩写,表示在JS代码中编写HTML模版结构,它是React中编写 UI模版的方式
jsx语法
1:定义虚拟DOM时 不要写引号
2:标签中混入js表达式要用{}
3:样式的类名指定不要用class,要用className
4:内联样式要用style={{key:value}} 的形式去写
5:只有一个根标签
6:标签必须是闭合的
7:标签首字母:
(1):小写首字母,转为html的同名元素,html没有对应标签报错<good></good>
(2):大写首字母,react就去找对应组件渲染,没有定义组件则报错<Good></Goo
function App() { const list = [1, 2, 3, 4, 5]; const flag = true; const show1 = (e) => { console.log(e); }; const show2 = (e, val) => { console.log(val); console.log(e); }; const show3 = (val) => { return (e) => { console.log(val); console.log(e); } }; return ( <div className="App"> <header className="app"> {list.map((item) => { return <li key={item}>{item}</li>; }) } {flag && <p>Hello World</p>} {flag ? <p>Hello World</p> : <p>Hello World</p>} <button onClick={show1}>绑定事件没有参数</button> <button onClick={(e) => show2(e, 'zs')}>绑定事件传递参数1</button> <button onClick={show3('ls')}>绑定事件传递参数2</button> </header> </div> ); } export default App;
hook
useState
import { useState } from 'react';
function HookUseState() {
const [num, setNum] = useState(10);
{
/*
1. useState是一个函数,返回值是一个数组
2. 数组中的第一个参数是状态变量,第二个参数是set函数用来修改状态变量
3. useState的参数将作为count的初始值
*/
}
const setNumber = () => {
// num++ //无视图变化
setNum(num + 1)
}
const [person, setPerson] = useState({
name: 'zs',
age: 18
})
const setPer = () => {
// person.name = 'ls' //无视图变化
setPerson({
name: 'ls',
age: 20
})
}
return (
<div>
<button onClick={setNumber}>useState: {num}</button>
<button onClick={setPer}>useState对象: {person.name},{person.age}</button>
</div>
);
}
export default HookUseState;
useContext
1. 使用createContext方法创建一个上下文对象Ctx
2. 在顶层组件(App)中通过 Ctx.Provider 组件提供数据
3. 在底层组件(B)中通过 useContext 钩子函数获取消费数据
import { createContext,useContext } from 'react';
const MyContext = createContext()
function HookUseContext() {
// 跨级通信
const msg = '我叫张三'
return (
<div>
<MyContext.Provider value={msg}>
<div>HookUseContext</div>
<Ason></Ason>
</MyContext.Provider>
</div>
);
}
function Ason() {
// 跨级通信
const msg = useContext(MyContext)
return (
<div>
<div>A:{msg}</div>
<Bson></Bson>
</div>
);
}
function Bson() {
// 跨级通信
const msg = useContext(MyContext)
return (
<div>B:{msg}</div>
);
}
export default HookUseContext;
useEffect
useEffect(()=>{},[])
参数1是一个函数,可以把它叫做副作用函数,在函数内部可以放置要执行的操作
参数2是一个数组(可选参),在数组里放置依赖项,不同依赖项会影响第一个参数函数的执行,当是一个空数组的时候,副作用函数 只会在组件渲染完毕之后执行一次
import { useState, useEffect } from 'react';
const URL = 'http://geek.itheima.net/v1_0/channels'
function HookUseEffect() {
const [list, setList] = useState([])
let [count, setCount] = useState(1)
let timer = null
useEffect(() => { //没有依赖 初始渲染执行一次 和 任何数据组件更新时执行
console.log(111);
})
useEffect(() => {//初始渲染只执行一次
console.log(222);
timer = setInterval(() => {
console.log('定时器');
}, 1000)
async function getList() {
const res = await fetch(URL)
const { data } = await res.json()
setList(data.channels)
}
getList()
}, [])
useEffect(() => { //初始渲染执行一次 或 特定依赖更新时执行
console.log(333);
}, [count])
useEffect(() => { //卸载时执行
return () => {
console.log(444);
clearInterval(timer)
}
}, [])
const setN = () => {
setCount(count + 1)
}
return (
<div>
<h1>useEffect使用</h1>
{
list.map((item) => <div key={item.id}>{item.name}</div>)
}
<div>{count}
<button onClick={setN}>count++</button>
<button onClick={setN}>定时</button>
</div>
</div>
);
}
export default HookUseEffect;
useMemo
const monthGroup =useMemo(() => { //类似计算属性
return _.groupBy(billList,(item)=>dayjs(item.date).format('YYYY-MM') )
}, [billList])
const monthResult = useMemo(() => {
const pay = currentMonthList.filter(item => item.type === 'pay').reduce( (acc,cur) => acc + cur.money,0)
const income = currentMonthList.filter(item => item.type === 'income').reduce( (acc,cur) => acc + cur.money,0)
return {pay,income,total:pay +income}
},[currentMonthList])
useLocation
// 1. 获取当前路由路径
const location = useLocation()
console.log(location.pathname)
自定义hook
import { useState } from "react";
/*
封装自定义hook通用思路
1.声明一个以use打头的函数
2.在函数体内封装可复用的逻辑(只要是可复用的逻辑)
3.把组件中用到的状态或者回调return出去(以对象或者数组)
4、在哪个组件中要用到这个逻辑,就执行这个函数,解构出来状态和回调进行使用I
*/
function useToggle() {
const [flag, setFlag] = useState(true)
const toggleShow = () => {
setFlag(!flag)
}
return { flag, toggleShow }//其他组件要用就return
}
function MyHook() {
// 自定义显示隐藏的hook基本分析
// const [flag, setFlag] = useState(true)
// const toggleShow = () => {
// setFlag(!flag)
// }
const { flag, toggleShow } = useToggle()
return (
<div>
{flag && <h1>自定义hook</h1>}
<button onClick={toggleShow}>toggle</button>
</div>
);
}
export default MyHook;
总结HOOK的使用规则
动态样式className
<div className={`cur ${id == xxx.id && 'active'}`}></div> 动态样式和多个样式
排序通过lodash
classNames优化类名管理
npm i classnames
import classNames from 'classname'
className={classNames('cur',{active: id == xxx.id})}
cur是静态类名 active是动态类名
表单控件
handleSubmit = (event) => {
event.preventDefault();
const {username, password} = this
alert(`用户名:${username.value}密码:${password.value}`)
}
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input ref={c=>this.username = c} type="text" name='username'/>
密码:<input ref={c=>this.password = c} type="text" name='password'/>
<button>登录</button>
</form>
state = {
username: 'qwe',
password: '123'
}
handleSubmit = (event) => {
event.preventDefault();
const { username, password } = this.state
alert(`用户名:${username}密码:${password}`)
}
saveUsername = (event) => {
// console.log(event.target.value);
this.setState({ username: event.target.value })
}
savePassword = (event) => {
// console.log(event.target.value);
this.setState({ password: event.target.value })
}
render() {
return (
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveUsername} value={this.state.username} type="text" name='username' />
密码:<input onChange={this.savePassword} value={this.state.password} type="text" name='password' />
<button>登录</button>
</form>
)
}
}
ref
<script type="text/babel">//用的jsx要写text/babel
class Person extends React.Component {
showData = () => {
const { input1 } = this.refs
alert(input1.value)
}
showData1 = () => {
const { input2 } = this.refs
alert(input2.value)
}
// ref是字符串( 不推荐 )
render() {
return (
<div>
<input ref="input1" type="text" placeholder="点我提示" />
<button onClick={this.showData}>点我</button>
<input ref="input2" onBlur={this.showData1} type="text" placeholder="失去焦点提示" />
</div>
)
}
}
// 渲染到组件到页面
// 需求1在页面上展示的年龄都大一岁
// 在传递数据时,传递数字年龄age={18} 字符串数字age="20"
ReactDOM.render(<Person />, document.getElementById('test1'))
</script>
<script type="text/babel">//用的jsx要写text/babel
class Person extends React.Component {
// 推键
myRef1 = React.createRef()//调用放回一个容器 可以存储被ref标识的节点(一人一个专人专用)
myRef2 = React.createRef()//调用放回一个容器 可以存储被ref标识的节点
showData = () => {
alert(this.myRef1.current.value)
}
showData1 = () => {
alert(this.myRef2.current.value)
}
// ref是字符串( 不推荐 )
render() {
return (
<div>
<input ref={this.myRef1} type="text" placeholder="点我提示" />
<button onClick={this.showData}>点我</button>
<input ref={this.myRef2} onBlur={this.showData1} type="text" placeholder="失去焦点提示" />
</div>
)
}
}
// 渲染到组件到页面
// 需求1在页面上展示的年龄都大一岁
// 在传递数据时,传递数字年龄age={18} 字符串数字age="20"
ReactDOM.render(<Person />, document.getElementById('test1'))
</script>
<script type="text/babel">//用的jsx要写text/babel
class Person extends React.Component {
showData=()=>{
const { input1 } = this
alert(input1.value)
}
showData1=()=>{
const { input2 } = this
alert(input2.value)
}
// ref是字符串( 不推荐 有效率上的问题 )
// currentNode 就是<input type="text" placeholder="点我提示"/>
render() {
return (
<div>
<input ref={(currentNode)=>{this.input1 = currentNode}} type="text" placeholder="点我提示"/>
<button onClick={this.showData}>点我</button>
<input ref={(currentNode)=>{ this.input2= currentNode}} onBlur={this.showData1} type="text" placeholder="失去焦点提示"/>
</div>
)
}
}
// 渲染到组件到页面
// 需求1在页面上展示的年龄都大一岁
// 在传递数据时,传递数字年龄age={18} 字符串数字age="20"
ReactDOM.render(<Person/>, document.getElementById('test1'))
</script>
<script type="text/babel">//用的jsx要写text/babel
const App =( props) => {
console.log(props);
const inputRef = React.useRef(null)
const btn = React.createRef()
const [n, setN] = React.useState(0)
function addNum() {
setN(n+1)
console.log(inputRef.current.value);
console.log(btn.current);
}
return (
<div className='App'>
<input ref={inputRef} />
{n}
<button ref={btn} onClick={addNum}>+1</button>
</div>
)
}
// 渲染到组件到页面
ReactDOM.render(<App name='zs'/>, document.getElementById('test'))
</script>
插件
日期插件 : dayjs
随机id插件 : uuid
props
function PropsAndMore() {
const getData = (data) => {
console.log(data);
};
return (
<div>
<Son name={'zs'} age={19} getData={getData}>
<span>solt</span>
</Son>
</div>
);
}
function Son(prop) {
console.log(prop);
const { name, age } = prop;
const toData = () => {
// 父组件调用子组件方法
prop.getData('son');
};
return (
<div>
<h1>son</h1>
{name}-{age}-{prop.children}
<button onClick={toData}>getData</button>
</div>
);
}
export default PropsAndMore;