应用:生日提醒
目标是构建一个卡片列表,包含头像图片和姓名年龄文本,一个清空列表项的按钮
给<article>
容器设置grid布局,align-items: center;
使子元素在网格区域块内对齐
grid-template-columns: auto 1fr; 左侧自身多大就占据多大 右侧是1fr(除掉左侧占据的空间 剩余有多大就占用多大)
使用useState,它接收一个初始化值,返回一个数组,第一个是状态,第二个是修改状态的函数
在button上绑定onClick函数,点击就调用setPeople([])
应用:旅游新闻列表
目标是创建一个新闻列表,每条新闻包含一个封面图、标题和价格、省略版摘要、不感兴趣按钮。
组件层级 TourList > Tours > Tour
在useEffect中发送API请求,在页面渲染之后马上执行里面的代码
useEffect(() => {
fetchTours();
}, []);
具体的发送API请求的方法:
使用async...await发送和等待接口返回,使用fetch(url)获取API数据;
使用try..catch捕获错误,设置对应的loading加载状态
const fetchTours = async () => {
const res = await fetch('https://.../xxx')
}
TourList里定义removeTour函数,作用是移除单个新闻卡片
使用props,removeTour={removeTour}
一层层传递方法,然后在最内层按钮的点击时调用
const removeTour = (id) => {
const newTours = tours.filter((tour) => tour.id !== id);
setTours(newTours);
};
generate dummy text by entering the number of paragraphs you need
input < 0 => get one paragragh
Only have 8 paragraphs in the database. If your input number is greater than 8, you will only receive the maximum of 8 paragraphs
特性:复制到剪贴板;根据颜色深浅更改文本颜色
依赖库:values.js
navigator.clipboard.writeText()
特性:
CRUD 增加 编辑 删除 清空
LocalStorage
Alert--不同的事件显示不同颜色和提示文本
查找:JSON.parse(localStorage.getItem("list"))
新增:使用new Date().getTime() 给一个新的id,结合输入的name,再使用扩展运算符新增到list里
修改:在父组件中定义editItem方法:使用find()根据id找到编辑的对象;在子组件中将id传递给editItem
删除:接收子组件的id,使用filter()筛选出新数组并赋值
使用useState完成变量初始化,初始值是一个对象,包含show、msg和type三个属性
Alert组件的HTML部分是一个p标签,根据type和msg渲染内容
使用useEffect,每次list数组变更时,在Alert组件内执行代码:3s后清除Alert,返回clearTimeout
清除Alert:
const showAlert = (show = false, type = "", msg = "") => {
setAlert({ show, msg, type });
};
展示Alert:showAlert(true, "success", "value changed");
特性:适应移动端;给菜单切换隐藏增加动画;
情景:封装移动端menu组件,增加menu数据,但是外层的容器高度之前是固定的
- 使用useRef定义一个linksRef,一个linksContainerRef,分别设置到ul和ul外层容器上
- showLinks判断移动端菜单栏是否展开
- 使用useEffect,在依赖项showLinks发生变化时执行部分代码
- 使用
ref.current.getBoundingClientRect().height
获取ul列表的高度 - 如果showLinks为true,通过
style.height
设置容器的高度和ul高度一致;否则就设置为0
实现一个通用组件侧边栏 假设在主页面有一个按钮,控制侧边栏的开关
思路:
使用自定义hook -- useGlobalContext,创建一个全局的上下文管理器,可以在任何地方访问或者修改全局状态
具体实现:
1.在src目录下创建context.js:
1.1.使用React.createContext创建一个AppContext
1.2.创建一个AppProvider,它接收children作为参数,
在这里定义状态或者函数
返回一个AppContext.Provider,通过value属性将任意数据状态或者函数方法 传递出去
1.3最后使用export关键字导出
2.在index.js文件中引入,使用AppProvider包裹应用根组件,这样子组件就可以访问到全局状态了
3.使用:在子组件SideBar中引入,它会返回的是Provider提供的value,e.g. siderbarOpen, setSidebar
如何实现子菜单--根据内容扩展宽高?
移动端导航栏弹窗?
一、创建一个reducer进行组件状态管理
二、在 contexts 中使用 useReducer 函数
引入reducer
使用useReducer,返回一个state和dispatch,接收参数reducer和初始状态值
const [state, dispatch] = useReducer(reducer, initialState);
const initialState = {
cart: cartData,
total: 0,
amount: 0
}
最后,在AppContext.Provider
的value中将 state和increase等方法导出去
三、页面函数绑定
为了更新屏幕内容,用户点击“增加”按钮,调用dispatch函数。将action type 和 商品id 传递过去
const increase = (id) => {
dispatch({ type: "INCREASE", goods: id });
}
React会将当前的state和action一起传递给reducer
reducer会判断当前函数是哪一个,然后进行对应的计算返回一个新的state,
React保存新的state,使用它渲染和更新UI
假设我们要对购物车内某个商品的数量进行增加,判断type是否等于increase,然后对当前购物车数组state.cart进行遍历,如果当前item===action.goodsId,就创建一个新的临时购物车数组,对当前子项的数量进行+1,最后函数结束返回新的state数据
if(action.type==="INCREASE"){
const cartTemp = state.cart.map(item => {
if(item.id === action.goods){
return { ...item, amount: item.amount + 1 };
}
return item
})
return {...state, cart: cartTemp}
}
对于单个商品的增减函数,可以封装成一个函数 toggleAmount 数量变化
创建一个临时购物车数组,通过state.cart进行处理得到的,最终返回新的state和cart数据
首先,判断当前子项的id是否等于action.goods.id,然后再判断action.goods.type是增加还是减少,从而对当前商品项的数量进行+1或者-1,最后使用filter过滤出数组不为0的商品
if (action.type === "TOGGLE_AMOUNT") {
let tempCart = state.cart
.map((cartItem) => {
if (cartItem.id === action.cargo.id) {
if (action.cargo.type === "inc") {
return { ...cartItem, amount: cartItem.amount + 1 };
}
if (action.cargo.type === "dec") {
return { ...cartItem, amount: cartItem.amount - 1 };
}
}
return cartItem;
})
.filter((cartItem) => cartItem.amount !== 0);
return { ...state, cart: tempCart };
}
计算总价和购物车总数量:
在reducer中:建立一个处理总数和总价格的函数 getTotal
使用reduce方法对state.cart数组进行处理,参数是cartTotal和cartItem对象,cartItem解构出当前商品的数量和价格,cartTotal包含总数量amount和总价total两个属性,总数量就是等于商品项的数量累加,总价就是商品单价*商品数量的累加
最后遍历完成后,再使用parseFloat和toFixed方法对总价进行小数格式化
然后将新的state,total, amount返回
if (action.type === "GET_TOTAL") {
let { total, amount } = state.cart.reduce(
(cartTotal, cartItem) => {
const { price, amount } = cartItem;
cartTotal.amount += amount;
const itemTotal = price * amount;
cartTotal.total += itemTotal;
return cartTotal;
},
{
amount: 0,
total: 0,
}
);
// 单独处理总价
total = parseFloat(total.toFixed(2));
return { ...state, total, amount };
}
在context里定义一个useEffect,每次购物车的cart数组发生变化时,计算total