钩子项目 -- 实战案例品购物车
嘻嘻
startTransition方法及并发模式
React18之前,渲染是一个单一的、不间断的、同步的事务,一旦渲染开始,就不能被中断
React 18引入并发模式,它允许你将标记更新作为一个transitions,这会告诉React它们可以被中断执行,这样可以把紧急的任务先更新,不紧急的任务后更新
选择高亮:
import { useState } from "react";
function List({query}){
const items = []
const word = 'hello world'
if(query !== '' && word.includes(query)){
const arr = word.split(query)
for(let i=0;i<100;i++){
items.push(<li key={i}>{arr[0]}<span style={{color:'red'}}>{query}</span>{arr[1]}</li> )
}
}
else{
for(let i = 0;i<100;i++){
items.push( <li key={i}>{word}</li> )
}
}
return (
<ul>
{items}
</ul>
)
}
function App(){
const [search,setSearch] = useState('')
const [query,setQuery] = useState('')
const handleChange = (e)=>{
//紧急
setSearch(e.target.value)
//紧急
setQuery(e.target.value)
}
return(
<div>
hello App
<input type="text" value={search} onChange={handleChange}/>
<List query={query}/>
</div>
)
}
export default App
但是它是等所有的都加载完在渲染
有些任务不是和紧急,所以就以缓缓
import { useState ,startTransition } from "react";
function List({query}){
const items = []
const word = 'hello world'
if(query !== '' && word.includes(query)){
const arr = word.split(query)
for(let i=0;i<100;i++){
items.push(<li key={i}>{arr[0]}<span style={{color:'red'}}>{query}</span>{arr[1]}</li> )
}
}
else{
for(let i = 0;i<100;i++){
items.push( <li key={i}>{word}</li> )
}
}
return (
<ul>
{items}
</ul>
)
}
function App(){
const [search,setSearch] = useState('')
const [query,setQuery] = useState('')
const handleChange = (e)=>{
//紧急
setSearch(e.target.value)
//紧急
startTransition(()=>{
setQuery(e.target.value)
})
}
return(
<div>
hello App
<input type="text" value={search} onChange={handleChange}/>
<List query={query}/>
</div>
)
}
export default App
useTransition与useDeferredValue
useTransition是一个让你在不阻塞UI的情况下来更新状态的React Hook,返回一个状态值表示过渡任务的等待状态,以及一个启动该过渡任务的函数
useDeferredValue接受一个值,并返回该值的新副本,该副本将推迟到更紧急的更新之后
import { useState,useTransition } from "react";
function List({query}){
const items = []
const word = 'hello world'
if(query !== '' && word.includes(query)){
const arr = word.split(query)
for(let i=0;i<10000;i++){
items.push(<li key={i}>{arr[0]}<span style={{color:'red'}}>{query}</span>{arr[1]}</li> )
}
}
else{
for(let i = 0;i<10000;i++){
items.push( <li key={i}>{word}</li> )
}
}
return (
<ul>
{items}
</ul>
)
}
function App(){
const [search,setSearch] = useState('')
const [query,setQuery] = useState('')
const [pending,startTransition] = useTransition()
const handleChange = (e)=>{
//紧急
setSearch(e.target.value)
//紧急
startTransition(()=>{
setQuery(e.target.value)
})
}
return(
<div>
hello App
<input type="text" value={search} onChange={handleChange}/>
{pending&& <div>loading...</div> }
<List query={query}/>
</div>
)
}
export default App
刚才输入法和谷歌浏览器都卡了
也是神人了
这样做完之后有loading效果
还有就是我想说分析一大堆给出一个我不需要的结果的deepseek是屑
问了下豆包马上就解决了。。。
还是穿换着用吧
另一个钩子的使用:
import { useState,useDeferredValue } from "react";
function List({query}){
const items = []
const word = 'hello world'
if(query !== '' && word.includes(query)){
const arr = word.split(query)
for(let i=0;i<10000;i++){
items.push(<li key={i}>{arr[0]}<span style={{color:'red'}}>{query}</span>{arr[1]}</li> )
}
}
else{
for(let i = 0;i<10000;i++){
items.push( <li key={i}>{word}</li> )
}
}
return (
<ul>
{items}
</ul>
)
}
function App(){
const [search,setSearch] = useState('')
//得到对应 search一样的值,只不过是一个延迟的副本
const [query,setQuery] = useDeferredValue(search)
const [pending,startTransition] = useTransition()
const handleChange = (e)=>{
setSearch(e.target.value)
}
return(
<div>
hello App
<input type="text" value={search} onChange={handleChange}/>
{pending&& <div>loading...</div> }
<List query={query}/>
</div>
)
}
export default App
useld生成唯一ID值
useId是一个React Hook,可以生成传递给无障碍属性的唯一ID
import React, { useId } from 'react';
function MyInput(){
const password = useId()
return (
<>
<label>
密码:
<input type="password"
aria-describedby={ 'password'+password}/>
</label>
<p id={'password'+password}>
密码至少应该包含18个字符
</p>
</>
)
}
function App(){
return(
<div>
hello App
<MyInput/>
</div>
)
}
export default App
React还有非常不常用的两个钩子:useDebugValue,useSyncExternalStore
在用自定义Hook中打印一些信息用,还是在下载了一些React工具的前提下
知道你不常用了退下吧
实战案例:商品购物车
老实说要下载安装一个axios的库
阿贾克斯。。。
npm i axios
购物车.jsx:
import './购物车.css'
import axios from 'axios'
import { useImmer } from 'use-immer'
import { act, useEffect,memo,useCallback} from 'react'
const Item = memo(function Item({
id,
name,
price,
number,
active,
handleAdd,
handleNumberChange,
}) {
return (
<li className={active ? 'active' : ' '}>
<h3>{name}</h3>
<p>单价:{price}</p>
<p>
数量:
<span className="remove" onClick={() => handleNumberChange(id, -1)}>
-
</span>
<span>{number}</span>
<span className="add" onClick={() => handleNumberChange(id, +1)}>
+
</span>
</p>
<div className="cartbtn" onClick={() => handleAdd(id)}>
{active ? '取消购买' : '添加购物车'}
</div>
</li>
)
}
)
function Cart() {
const [list, setList] = useImmer([])
const all = list.filter((item)=>item.active).reduce((init,item)=> init + item.number*item.price,0)
useEffect(() => {
axios.get('./cartData.json').then((res) => {
setList(res.data.list.map((item) => ({ ...item, active: false })))
})
}, [])
const handleAdd = useCallback ((id) => {
setList((draft) => {
const value = draft.find((item) => item.id === id)
value.active = !value.active
})
},[])
const handleNumberChange = useCallback((id, num) => {
setList((draft) => {
const value = draft.find((item) => item.id === id)
if (value.number === 0 && num < 0) {
return
}
value.number += num
})
},[])
return (
<div className="cart">
<ul>
{list.map((item) => (
<Item
key={item.id}
{...item}
handleAdd={handleAdd}
handleNumberChange={handleNumberChange}
/>
))}
</ul>
<ul>
<Item />
</ul>
<div className="all">
总金额:<span>{all}</span>元
</div>
</div>
)
}
export default Cart
购物车.css:
*{margin: 0; padding: 0;}
li{ list-style: none;}
.cart{ width: 700px; margin: 30px auto;}
.cart ul{ overflow: hidden;}
.cart li{ width: 100px; border: 5px gray dotted; border-radius: 20px; padding: 20px; float: left; margin:10px;}
.cart .remove,.cart .add{ cursor: pointer;}
.cart .cartbtn{ font-size:14px; text-align: center; background: red; color: white; padding: 3px; border-radius: 5px; margin-top: 10px; cursor: pointer;}
.cart li.active{ border-color:red;}
.cart li.active .cartbtn{ background-color: skyblue;}
.cart .all{ text-align: center; margin: 20px 0;}
购物车静态布局.html
<!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>
<style>
*{margin: 0; padding: 0;}
li{ list-style: none;}
.cart{ width: 700px; margin: 30px auto;}
ul{ overflow: hidden;}
li{ width: 100px; border: 5px gray dotted; border-radius: 20px; padding: 20px; float: left; margin:10px;}
.remove, .add{ cursor: pointer;}
.cartbtn{ font-size:14px; text-align: center; background: red; color: white; padding: 3px; border-radius: 5px; margin-top: 10px; cursor: pointer;}
li.active{ border-color:red;}
li.active .cartbtn{ background-color: skyblue;}
.all{ text-align: center; margin: 20px 0;}
</style>
<script src="https://unpkg.com/react@18.2.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18.2.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/babel">
let app = document.querySelector('#app');
let root = ReactDOM.createRoot(app);
let Cart = () => {
return (
<div className="cart">
<ul>
<li className="active">
<h3>香蕉</h3>
<p>单价:5</p>
<p>
数量:
<span className="remove">-</span>
<span>1</span>
<span className="add">+</span>
</p>
<div className="cartbtn">取消购买</div>
</li>
<li>
<h3>香蕉</h3>
<p>单价:5</p>
<p>
数量:
<span className="remove">-</span>
<span>1</span>
<span className="add">+</span>
</p>
<div className="cartbtn">添加到购物车</div>
</li>
<li>
<h3>香蕉</h3>
<p>单价:5</p>
<p>
数量:
<span className="remove">-</span>
<span>1</span>
<span className="add">+</span>
</p>
<div className="cartbtn">添加到购物车</div>
</li>
<li>
<h3>香蕉</h3>
<p>单价:5</p>
<p>
数量:
<span className="remove">-</span>
<span>1</span>
<span className="add">+</span>
</p>
<div className="cartbtn">添加到购物车</div>
</li>
<li>
<h3>香蕉</h3>
<p>单价:5</p>
<p>
数量:
<span className="remove">-</span>
<span>1</span>
<span className="add">+</span>
</p>
<div className="cartbtn">添加到购物车</div>
</li>
<li>
<h3>香蕉</h3>
<p>单价:5</p>
<p>
数量:
<span className="remove">-</span>
<span>1</span>
<span className="add">+</span>
</p>
<div className="cartbtn">添加到购物车</div>
</li>
</ul>
<div className="all">
总金额:<span>5</span>元
</div>
</div>
);
}
let element = (
<Cart />
);
root.render(element)
</script>
</body>
</html>