1.快速搭建开发环境
2.react渲染流程
3.1 jsx基础 概念
3.2 jsx基础 本质
3.3 jsx基础 jsx表达式
3.4 jsx基础 实现列表渲染
3.5 jsx基础 实现条件渲染
3.5 jsx基础 实现复杂的条件渲染
4. react中事件绑定
5.react组建基础使用
扫描二维码关注公众号,回复:
17316622 查看本文章
![](/qrcode.jpg)
6.1 useState
6.2 useState修改状态的规则
7.基础样式控制
8.1评论案例–删除列表
8.2评论案例–tab切换
8.2评论案例–排序
$ npm i --save lodash //安装lodash
import _ from 'loadsh';//引入loadsh
9.classnames优化类名控制
npm install classnames //安装classnames
import classNames from 'classnames';//引入classnames
10.受控表单绑定
11.react中获取DOM
11.1 react中组件通信—父传子
//1. 父组件传递数据 - 在子组件标签上绑定属性
//2. 子组件接收数据 - 子组件通过props参数接收数据
//JSX
//子组件
function Son(props){
return <div>{
props.name }</div>
}
//父组件
function App(){
const name = 'this is app name'
return (
<div>
<Son name={
name}/>
</div>
)
}
11.2 react中组件通信—子传父
//核心思路:在子组件中调用父组件中的函数并传递参数
function Son({
onGetMsg }){
const sonMsg = 'this is son msg'
return (
<div>
{
/* 在子组件中执行父组件传递过来的函数 */}
<button onClick={
()=>onGetMsg(sonMsg)}>send</button>
</div>
)
}
function App(){
const[msg,setMesg]=useState('')
const getMsg = (msg)=>{
console.log(msg)
setMesg(msg)
}
return (
<div>
{
msg}
{
/* 传递父组件中的函数到子组件 */}
<Son onGetMsg={
getMsg }/>
</div>
)
}
11.3 react中组件通信—兄弟传值
// 实现思路: 借助 `状态提升` 机制,通过共同的父组件进行兄弟之间的数据传递
// 1. A组件先通过子传父的方式把数据传递给父组件App
// 2. App拿到数据之后通过父传子的方式再传递给B组件
// 1. 通过子传父 A -> App
// 2. 通过父传子 App -> B
import {
useState } from "react"
function A ({
onGetAName }) {
// Son组件中的数据
const name = 'this is A name'
return (
<div>
this is A compnent,
<button onClick={
() => onGetAName(name)}>send</button>
</div>
)
}
function B ({
name }) {
return (
<div>
this is B compnent,
{
name}
</div>
)
}
function App () {
const [name, setName] = useState('')
const getAName = (name) => {
setName(name)
}
return (
<div>
this is App
<A onGetAName={
getAName} />
<B name={
name} />
</div>
)
}
export default App
11.4 react中组件通信—跨层级组件传值
//1. 使用 `createContext`方法创建一个上下文对象Ctx
//2. 在顶层组件(App)中通过 `Ctx.Provider` 组件提供数据
//3. 在底层组件(B)中通过 `useContext` 钩子函数获取消费数据
//jsx
// App -> A -> B
import {
createContext, useContext } from "react"
// 1. createContext方法创建一个上下文对象
const MsgContext = createContext()
function A () {
return (
<div>
this is A component
<B />
</div>
)
}
function B () {
// 3. 在底层组件 通过useContext钩子函数使用数据
const msg = useContext(MsgContext)
return (
<div>
this is B compnent,{
msg}
</div>
)
}
function App () {
const msg = 'this is app msg'
return (
<div>
{
/* 2. 在顶层组件 通过Provider组件提供数据 */}
<MsgContext.Provider value={
msg}>
this is App
<A />
</MsgContext.Provider>
</div>
)
}
export default App
12.1 react—useEffect基础使用
//useEffect是一个React Hook函数,用于在React组件中创建不是由事件引起而是由渲染本身引起的操作(副作用), 比 如发送AJAX请求,更改DOM等等
//组件渲染完毕之后就需要和服务器要数据,整个过程属于“只由渲染引起的操作”
//1. 参数1是一个函数,可以把它叫做副作用函数,在函数内部可以放置要执行的操作
//2. 参数2是一个数组(可选参),在数组里放置依赖项,不同依赖项会影响第一个参数函数的执行,当是一个空数组的时候,副作用函数只会在组件渲染完毕之后执行一次
//需求:在组件渲染完毕之后,立刻从服务端获取平道列表数据并显示到页面中
import {
useEffect, useState } from "react"
const URL = 'http://geek.itheima.net/v1_0/channels'
function App () {
// 创建一个状态数据
const [list, setList] = useState([])
useEffect(() => {
// 额外的操作 获取频道列表
async function getList () {
const res = await fetch(URL)
const jsonRes = await res.json()
console.log(jsonRes)
setList(jsonRes.data.channels)
}
getList()
}, [])
return (
<div>
this is app
<ul>
{
list.map(item => <li key={
item.id}>{
item.name}</li>)}
</ul>
</div>
)
}
export default App
12.2 react—useEffect依赖参数项
import {
useEffect, useState } from "react"
function App () {
// 1. 没有依赖项 初始 + 组件更新
const [count, setCount] = useState(0)
// useEffect(() => {
// console.log('副作用函数执行了')
// })
// 2. 传入空数组依赖 初始执行一次
// useEffect(() => {
// console.log('副作用函数执行了')
// }, [])
// 3. 传入特定依赖项 初始 + 依赖项变化时执行
useEffect(() => {
console.log('副作用函数执行了')
}, [count])
return (
<div>
this is app
<button onClick={
() => setCount(count + 1)}>+{
count}</button>
</div>
)
}
export default App
12.3 react—useEffect清除副作用
//概念:在useEffect中编写的由渲染本身引起的对接组件外部的操作,社区也经常把它叫做副作用操作,比如在useEffect中开启了一个定时器,我们想在组件卸载时把这个定时器再清理掉,这个过程就是清理副作用
import {
useEffect, useState } from "react"
function Son () {
// 1. 渲染时开启一个定时器
useEffect(() => {
const timer = setInterval(() => {
console.log('定时器执行中...')
}, 1000)
return () => {
// 清除副作用(组件卸载时)
clearInterval(timer)
}
}, [])
return <div>this is son</div>
}
function App () {
// 通过条件渲染模拟组件卸载
const [show, setShow] = useState(true)
return (
<div>
{
show && <Son />}
<button onClick={
() => setShow(false)}>卸载Son组件</button>
</div>
)
}
export default App
13.1 react自定义hook
// 封装自定义Hook
// 问题: 布尔切换的逻辑 当前组件耦合在一起的 不方便复用
// 解决思路: 自定义hook
import {
useState } from "react"
function useToggle () {
// 可复用的逻辑代码
const [value, setValue] = useState(true)
const toggle = () => setValue(!value)
// 哪些状态和回调函数需要在其他组件中使用 return
return {
value,
toggle
}
}
// 封装自定义hook通用思路
// 1. 声明一个以use打头的函数
// 2. 在函数体内封装可复用的逻辑(只要是可复用的逻辑)
// 3. 把组件中用到的状态或者回调return出去(以对象或者数组)
// 4. 在哪个组件中要用到这个逻辑,就执行这个函数,解构出来状态和回调进行使用
function App () {
const {
value, toggle } = useToggle()
return (
<div>
{
value && <div>this is div</div>}
<button onClick={
toggle}>toggle</button>
</div>
)
}
export default App
13.2 reactHooks的使用规则
13.3 封装请求数据的Hook
function useGetList () {
// 获取接口数据渲染
const [commentList, setCommentList] = useState([])
useEffect(() => {
// 请求数据
async function getList () {
// axios请求数据
const res = await axios.get(' http://localhost:3004/list')
setCommentList(res.data)
}
getList()
}, [])
return {
commentList,
setCommentList
}
}
const app =()=>{
//使用
const {
commentList, setCommentList } = useGetList()
}
13.3 封装Item组件的Hook
// 封装Item组件
function Item ({
item, onDel }) {
return (
<div className="reply-item">
{
/* 头像 */}
<div className="root-reply-avatar">
<div className="bili-avatar">
<img
className="bili-avatar-img"
alt=""
src={
item.user.avatar}
/>
</div>
</div>
<div className="content-wrap">
{
/* 用户名 */}
<div className="user-info">
<div className="user-name">{
item.user.uname}</div>
</div>
{
/* 评论内容 */}
<div className="root-reply">
<span className="reply-content">{
item.content}</span>
<div className="reply-info">
{
/* 评论时间 */}
<span className="reply-time">{
item.ctime}</span>
{
/* 评论数量 */}
<span className="reply-time">点赞数:{
item.like}</span>
{
/* 条件:user.id === item.user.id */}
{
user.uid === item.user.uid &&
<span className="delete-btn" onClick={
() => onDel(item.rpid)}>
删除
</span>}
</div>
</div>
</div>
</div>
)
}
const App = () => {
// 渲染评论列表
// 1. 使用useState维护list
// const [commentList, setCommentList] = useState(_.orderBy(list, 'like', 'desc'))
const {
commentList, setCommentList } = useGetList()
// 删除功能
const handleDel = (id) => {
console.log(id)
// 对commentList做过滤处理
setCommentList(commentList.filter(item => item.rpid !== id))
}
return (
<div className="app">
{
/* 评论列表 */}
<div className="reply-list">
{
/* 评论项 */}
{
commentList.map(item => <Item key={
item.id} item={
item} onDel={
handleDel} />)}
</div>
</div>
)
}
export default App
14. redux
<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>
<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
<script>
// 1. 定义reducer函数
// 作用: 根据不同的action对象,返回不同的新的state
// state: 管理的数据初始状态
// action: 对象 type 标记当前想要做什么样的修改
function reducer (state = {
count: 0 }, action) {
// 数据不可变:基于原始状态生成一个新的状态
if (action.type === 'INCREMENT') {
return {
count: state.count + 1 }
}
if (action.type === 'DECREMENT') {
return {
count: state.count - 1 }
}
return state
}
// 2. 使用reducer函数生成store实例
const store = Redux.createStore(reducer)
// 3. 通过store实例的subscribe订阅数据变化
// 回调函数可以在每次state发生变化的时候自动执行
store.subscribe(() => {
console.log('state变化了', store.getState())
document.getElementById('count').innerText = store.getState().count
})
// 4. 通过store实例的dispatch函数提交action更改状态
const inBtn = document.getElementById('increment')
inBtn.addEventListener('click', () => {
// 增
store.dispatch({
type: 'INCREMENT'
})
})
const dBtn = document.getElementById('decrement')
dBtn.addEventListener('click', () => {
// 减
store.dispatch({
type: 'DECREMENT'
})
})
// 5. 通过store实例的getState方法获取最新状态更新到视图中
</script>
15.1 redux与react环境搭建
- 使用 CRA 快速创建 React 项目
npx create-react-app react-redux
- 安装配套工具
npm i @reduxjs/toolkit react-redux
- 启动项目
npm run start
15.2 redux与react实现counter
//store文件下的counterStrore.js
import {
createSlice } from '@reduxjs/toolkit'
const counterStore = createSlice({
// 模块名称独一无二
name: 'counter',
// 初始数据
initialState: {
count: 1
},
// 修改数据的同步方法
reducers: {
increment (state) {
state.count++
},
decrement(state){
state.count--
}
}
})
// 结构出actionCreater
const {
increment,decrement } = counter.actions
// 获取reducer函数
const counterReducer = counterStore.reducer
// 导出
export {
increment, decrement }
export default counterReducer
//stroe文件下的index.js
import {
configureStore } from '@reduxjs/toolkit'
import counterReducer from './modules/counterStore'
const store = configureStore({
reducer: {
// 注册子模块
counter: counterReducer
}
})
export default store
```jsx
//index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
// 导入store
import store from './store'
// 导入store提供组件Provider
import {
Provider } from 'react-redux'
ReactDOM.createRoot(document.getElementById('root')).render(
// 提供store数据
<Provider store={
store}>
<App />
</Provider>
)
import {
useDispatch, useSelector } from 'react-redux'
// 导入actionCreater
import {
inscrement, decrement} from './store/modules/counterStore'
function App () {
const {
count } = useSelector(state => state.counter)
const dispatch = useDispatch()
return (
<div className="App">
<button onClick={
() => dispatch(decrement())}>-</button>
{
count}
<button onClick={
() => dispatch(inscrement())}>+</button>
</div>
)
}
export default App
总结
15.3 redux与react 提交action参数
15.4 redux与react 异步状态操作
//channelStore.js文件
import {
createSlice } from "@reduxjs/toolkit"
import axios from "axios"
const channelStore = createSlice({
name: 'channel',
initialState: {
channelList: []
},
reducers: {
setChannels (state, action) {
state.channelList = action.payload
}
}
})
// 异步请求部分
const {
setChannels } = channelStore.actions
const fetchChannlList = () => {
return async (dispatch) => {
const res = await axios.get('http://geek.itheima.net/v1_0/channels')
dispatch(setChannels(res.data.data.channels))
}
}
export {
fetchChannlList }
```javascript
//在store文件下的index.js文件
import {
configureStore } from "@reduxjs/toolkit"
// 导入子模块reducer
import counterReducer from './modules/counterStore'
import channelReducer from './modules/channelStore'
const store = configureStore({
reducer: {
counter: counterReducer,
channel: channelReducer
}
})
export default store
const reducer = channelStore.reducer
export default reducer
//app.js
import {
useEffect } from 'react'
import {
useDispatch, useSelector } from 'react-redux'
// 导入actionCreater
import {
inscrement, decrement, addToNum } from './store/modules/counterStore'
import {
fetchChannlList } from './store/modules/channelStore'
function App () {
const {
count } = useSelector(state => state.counter)
const {
channelList } = useSelector(state => state.channel)
const dispatch = useDispatch()
// 使用useEffect触发异步请求执行
useEffect(() => {
dispatch(fetchChannlList())
}, [dispatch])
return (
<div className="App">
<button onClick={
() => dispatch(decrement())}>-</button>
{
count}
<button onClick={
() => dispatch(inscrement())}>+</button>
<button onClick={
() => dispatch(addToNum(10))}>add To 10</button>
<button onClick={
() => dispatch(addToNum(20))}>add To 20</button>
<ul>
{
channelList.map(item => <li key={
item.id}>{
item.name}</li>)}
</ul>
</div>
)
}
export default App