使用react hook做一个小型完整项目(包括二级路由,动态路由,redux,tab切换,列表跳详情,登录, 守卫)
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
项目源码:
参考链接:
https://cloud.tencent.com/developer/article/1468196
https://react.docschina.org/docs/hooks-intro.html
重要代码:
Nav.js:
import React, { useEffect } from 'react'
import { connect } from 'react-redux'
import axios from 'axios'
const Nav = (props) => {
const handleNav = (index, id) => {
props.onSetState('currentIndex', index)
props.onSetState('currentId', id)
axios({
url: `/api/get_list?id=${id}`
}).then(res => {
if (res.data.code === 200) {
props.onSetState('contentList', res.data.data)
}
})
}
useEffect(() => {
axios({
url: '/api/get_nav'
}).then(res => {
if (res.data.code === 200) {
props.onSetState('navList', res.data.data)
}
})
axios({
url: `/api/get_list?id=0`
}).then(res => {
if (res.data.code === 200) {
props.onSetState('contentList', res.data.data)
}
})
}, [])
let { navList, currentIndex } = props
let navListDom = navList.map((item, index) => (
<span
key={item.id}
className={"m-nav-item " + (currentIndex === index ? 'active' : '')}
onClick={handleNav.bind(this, index, item.id)}>
{item.title}
</span>
))
return (
<div>
{navListDom}
</div>
)
}
const mapStateToProps = (state) => {
return {
navList: state.navList,
currentIndex: state.currentIndex
}
}
const mapDispatchToProps = (dispatch) => {
return {
onSetState(key, value) {
dispatch({ type: 'SET_STATE', key, value })
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Nav)
BookList.js:
import React from 'react'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import axios from 'axios'
const BookList = (props) => {
const handleDetail = (id) => {
props.history.push('/index/home/detail/' + id)
}
const handleAdd = (item) => {
if (!localStorage.getItem('username')) {
props.history.push('/login')
}
axios({
url: '/api/add_book',
data: {
item
},
method: 'post'
}).then(res => {
if (res.data.code === 200) {
let { currentId } = props
axios({
url: `/api/get_list?id=${currentId}`
}).then(res => {
if (res.data.code === 200) {
props.onSetState('contentList', res.data.data)
}
})
}
})
}
let { contentList } = props
let listDom = contentList.map(item => (
<div key={item.id}>
{item.title}<button onClick={handleDetail.bind(this, item.id)}>详情</button>
<button onClick={handleAdd.bind(this, item)} className={'m-add-btn ' + (item.is_in_my_book ? "" : 'active')}>收藏</button>
</div>
))
return (
<div>
{listDom}
</div>
)
}
const mapStateToProps = (state) => {
return {
contentList: state.contentList,
currentId: state.currentId
}
}
const mapDispatchToProps = (dispatch) => {
return {
onSetState(key, value) {
dispatch({ type: 'SET_STATE', key, value })
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(BookList))
MyBook.js:
import React, { useState, useEffect } from 'react'
import { connect } from 'react-redux'
import axios from 'axios'
const MyBook = (props) => {
const [selected, setSelected] = useState([])
const [selectAll, setSelectAll] = useState(false)
const handleSelected = (id, e) => {
let { myBook } = props
let selectedClone = JSON.parse(JSON.stringify(selected))
let index = selectedClone.findIndex(item => item === id)
if (e.target.checked) {
selectedClone.push(id)
} else {
selectedClone.splice(index, 1)
}
setSelected(selectedClone)
setSelectAll(selectedClone.length === myBook.length)
}
const handleDelete = (ids) => {
axios({
url: '/api/delete_book',
data: {
ids
},
method: 'post'
}).then(res => {
if (res.data.code === 200) {
props.onSetState('myBook', res.data.data)
}
})
}
const handleDeleteMore = () => {
axios({
url: '/api/delete_book',
data: {
ids: selected
},
method: 'post'
}).then(res => {
if (res.data.code === 200) {
props.onSetState('myBook', res.data.data)
}
})
}
const handleSelectAll = (e) => {
let { myBook } = props
setSelectAll(e.target.checked)
if (e.target.checked) {
let selected = myBook.map(item => item.id)
setSelected(selected)
} else {
setSelected([])
}
}
useEffect(() => {
axios({
url: '/api/get_my_book'
}).then(res => {
if (res.data.code === 200) {
props.onSetState('myBook', res.data.data)
}
})
}, [])
useEffect(() => {
console.log(selected)
})
let { myBook } = props
let myBookDom = myBook.map(item => (
<div key={item.id}>
<input type="checkbox" checked={selected.findIndex(id => id === item.id) >= 0 ? true : false} onChange={handleSelected.bind(this, item.id)} />
{item.title}
<button onClick={handleDelete.bind(this, [item.id])}>删除</button>
</div>
))
return (
<div>
<input type="checkbox" checked={selectAll} onChange={handleSelectAll.bind(this)}></input>全选
<button onClick={handleDeleteMore.bind(this)}>删除</button>
{myBookDom}
</div>
)
}
const mapStateToProps = (state) => {
return {
myBook: state.myBook
}
}
const mapDispatchToProps = (dispatch) => {
return {
onSetState(key, value) {
dispatch({ type: 'SET_STATE', key, value })
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyBook)
hook是2019年2月6号新增加的:
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步