React 18 开发备忘录
记录 React18 环境下基础功能与常用 hook ,用于备查。
开发环境
node V20
React V18
JSX
在JS中使用HTML模板结构
function App() {
return (
<div classname="App">
this is App
</div>
)
}
export default App
列表渲染
数据循环渲染
const list = [
{ id: 1, name: 'Vue' },
{ id: 2, name: 'React' },
{ id: 3, name: 'Uni-app' }
]
function App() {
return (
<div classname="App">
{/* 列表渲染 */}
<ul>
{ list.map(el => (
<li key={el.id}>{el.name}</li>
)) }
</ul>
</div>
)
}
export default App
条件渲染
基础条件渲染
通过标识符逻辑判断是否渲染 html 模板
let flag = true
let loading = false
function App() {
return (
<div classname="App">
{/* 条件渲染 */}
{flag && <span>render</span>}
{loading ? <span>loading...</span> : <span>render</span>}
</div>
)
}
export default App
复杂条件渲染
通过函数与标识符判断需要渲染的 HTML 模板
const flag = 1
function getTemplate() {
if(flag === 0) {
return <div>0</div>
} else if (flag === 1) {
return <div>1</div>
} else {
return <div>2</div>
}
}
function App() {
return (
<div classname="App">
{/* 复杂条件渲染 */}
{ getTemplate() }
</div>
)
}
export default App
事件绑定
元素上通过 on 绑定事件
function App() {
const handleClick = () => {
console.log('click')
}
return (
<button onClick={handleClick}>click</button>
)
}
组件基础使用
函数作为渲染组件时函数名首位大写
const Button = () => {
return <button>click</button>
}
function App() {
return (
<div className="App">
<Button></Button>
</div>
)
}
export default App
基础样式控制
● 原始样式控制: 通过模板字符串逻辑判断渲染需要的样式类
● 通过 classnames 类优化库渲染
.title-row {
background: grey;
}
.actived {
color: #ff0036;
}
import './app.css'
import classNames from 'classnames'
function App() {
let flag = true
return (
<div className="App">
{/* 基础控制 */}
<div className={`title-row ${flag && 'actived'}`}>
hello!
</div>
{/* 通过classnames 优化类名控制 */}
<div
className={classNames('title-row', 'actived': flag)}
>
hello!
</div>
</div>
)
}
export default App
React Hook
useState
● useState 是一个函数, 返回值是一个数组.
● 数组中的第一个参数是状态, 第二个参数是用来修改状态默认状态首位大写并加前缀set, 如下所示 title 与 setTitle.
● useState的参数作为状态的初始值.
import { useState } from 'react'
function App() {
{/* 基础类型的设置与修改 */}
let [title, setTitle] = useState('hello')
const handleClick = () => {
setTitle('title is change')
}
{/* 对象类型的设置与修改 通过结构与属性覆盖 */}
let [form, setForm] = useState({ name: 'liump' })
function handleChangeForm() {
setForm({
...form,
name: 'mpliu'
})
}
return (
<div onClick={handleClick}>
{ title }
</div>
)
}
useEffect
场景: 在组件渲染完毕之后,立即从服务端获取数据并显示到页面中
● 参数1是一个函数, 可以把它叫做副作用函数, 在函数内部可以放置要执行的操作.
● 参数2是一个数组, 在数组里放置依赖项, 不同依赖项会影响第一个参数函数的执行, 如果是空数据, 副作用函数只会在组件渲染完毕后之后执行一次
import {useEffect} from 'react'
useEffect(
() => {
},
[]
)
副作用清除, 例如销毁定时器
import {useEffect} from 'react'
useEffect(() => {
const timer = setInterval(() => {
console.log('setInterval')
}, 1000)
return () => {
clearInterval(timer)
}
},[])
useMemo
在组件每次重新渲染的时候缓存计算结果
import { useState, useMemo } from 'react'
function fib (n) {
console.log('计算函数执行了')
if(n<3) return 1
return fib(n-2) + fib(n-1)
}
function App() {
const [count1, setCount1] = useState(0)
const result = useMemo(()=>{
return fib(count1)
}, [count1])
const [count2, setCount2] = useState(0)
console.log('组件重新渲染了')
return (
<div className="App">
this is app
<button onClick={() => setCount1(count1 + 1)}>
change count1: {count1}
</button>
<button onClick={() => setCount2(count2 + 1)}>
change count2: {count2}
</button>
</div>
)
}
export default App
useRef
what? 获取 DOM 的 hook
why?需要获取 DOM 并操作
where?函数组件中通过 useRef
how?
● 通过 useRef 申明状态
● 在元素上通过 ref 与申明的状态名绑定
import { useRef } from 'react'
function App() {
const inputRef = useRef(null)
const inputDom = () => {
console.dir(inputRef.current)
}
return (
<div className="App">
<input
type="text"
ref={inputRef}
></input>
<button onClick={inputDom}>
获取DOM
</button>
</div>
)
}
useNavigate
react-router-dom 路由跳转 hook
import { useNavigate } from 'react-router-dom'
const navigate = useNavigate()
const handleToDetail = (id: string) => {
// 路由跳转
navigate('/home?id='+id)
}
useSearchParame
react-router-dom 获取路由参数hook
// 路由带参调整
navigate('/article?id=1001&name=jack')
// 获取路由参数 hook
const [params] = useSearchParams()
let id = params.get('id')
受控表单绑定
● 通过 value 绑定状态
● 通过 on 事件触发变更状态
import {useState} from 'react'
function App() {
let [userName, setUserName] = useState('')
const handleChangeUserName = (e) {
setUserName(e.target.value)
}
return (
<div className="App">
<input
value={userName}
onChange={handleChangeUserName}
/>
</div>
)
}
export default App
组件通信
父传子
● props 可传递任意的数据(数字、字符串、布尔值、数组、对象、函数、JSX)
● props 是只读对象(父组件的数据只能由父组件修改)
<Son
name={appName}
age={20}
isTrue={false}
list={['React', 'axios']}
obj={{name: 'liump'}}
cb={ () => console.log('callback')}
child={ <span>child</span> }
></Son>
props 接收的属性
props
age: 20
cb: f cb() {}
child: <span/>
isTrue: false
list: ["React", "axios"]
name: "this is app name"
obj: {name: "liump"}
例如
function Son(props) {
console.log(props)
return <div>this is son, {props.name}, jsx: {props.child}</div>
}
function App() {
const name = "this is app name"
return (
<div>
<Son
name={name}
age={20}
isTrue={false}
list={['React', 'axios']}
obj={{name: 'liump'}}
cb={ () => console.log('callback')}
child={ <span>child</span> }
></Son>
</div>
)
}
export default App
父传子-children
场景: 当我们把内容嵌套在子组件标签中时, 父组件会自动在名为 children 的 prop 属性中接收该内容
function Son(props) {
console.log(props)
return <div>this is son, {props.children}</div>
}
function App() {
return(
<div>
<Son>
<span>this is span</span>
</Son>
</div>
)
}
export default App
子传父
function Son({onGetMsg}) {
const sonMsg = 'this is son msg'
return (
<div>
this is Son
<button onClick={() => onGetMsg(sonMsg)}>
sendMsg
</button>
</div>
)
}
function App() {
const getMsg = (msg) => {
console.log(msg)
}
return (
<div>
this is App
<Son onGetMsg={getMsg}/>
</div>
)
}
export default App
兄弟组件通信
通过共同的父组件传递消息
● A组件先通过子传父的方式把数据传给父组件App
● App拿到数据后通过父传子的方式再传递给B组件
import {useState} from 'react'
function A({getAName}){
const name = 'this is A name'
return (
<div>
this is A component,
<button onClick={() => getAName(name)}>send</button>
</div>
)
}
function B({aName}) {
return(
<div>
this is B component
{aName}
</div>
)
}
function App() {
const getAName = (name) => {
console.log(name)
setAName(name)
}
let [aName, setAName] = useState('')
return (
<div>
this is App
<A onGetAName={getAName}></A>
<B aName={aName}></B>
</div>
)
}
export default App