新闻发布模块中的未上线,已上线和已下线三个组件中的数据请求方式,页面布局方式等代码相似度高,因此抽离出一个自定义hooks实现代码复用。
首先将state和useEffect中的数据请求抽离出来,自定义hook接受type作为参数,分别代表不同的新闻状态,最后将请求到的数据传给调用该hook的组件
function usePublish(type) {
const [dataSource, setdataSource] = useState([])
const { username } = JSON.parse(localStorage.getItem("token"))
useEffect(() => {
axios.get(`/news?author=${username}&publishState=${type}&_expand=category`).then(res => {
setdataSource(res.data)
})
}, [username , type])
return {
dataSource
}
}
export default usePublish;
比如在已发布中调用该hook(另外两种状态只需要改一下type即可)
export default function Published() {
// type=2 代表已发布
const {dataSource} = usePublish(2)
return (
<div>
// NewsPublish是抽离出来的UI组件,此处省略
<NewsPublish dataSource={dataSource}></NewsPublish>
</div>
)
}
但是每个模块中不同的按钮还对应着不同的功能,比如:
- 待发布中按钮为发布
- 已发布中按钮为下线
- 已下线中按钮为删除
那么就还需要在自定义的hook中分别写好这三种方法然后返回一个对象,每个组件通过解构在返回来的对象中获得自己组建需要的方法。
function usePublish(type) {
const [dataSource, setdataSource] = useState([])
const { username } = JSON.parse(localStorage.getItem("token"))
useEffect(() => {
axios.get(`/news?author=${username}&publishState=${type}&_expand=category`).then(res => {
setdataSource(res.data)
})
}, [username, type])
// 发布方法 提供给Unpublished
const handlePublish = (id) => {
setdataSource(dataSource.filter(item => item.id !== id))
axios.patch(`/news/${id}`, {
"publishState": 2,
"publishTime": Date.now()
}).then(res => {
notification.info({
message: `通知`,
description:
`您可以到【发布管理-已发布】中查看您的新闻`,
placement: "bottomRight"
});
})
}
// 下线方法 提供给Published
const handleSunset = (id) => {
setdataSource(dataSource.filter(item => item.id !== id))
axios.patch(`/news/${id}`, {
"publishState": 3,
}).then(res => {
notification.info({
message: `通知`,
description:
`您可以到【发布管理-已下线】中查看您的新闻`,
placement: "bottomRight"
});
})
}
// 删除方法 提供给Sunset
const handleDelete = (id) => {
setdataSource(dataSource.filter(item => item.id !== id))
axios.delete(`/news/${id}`).then(res => {
notification.info({
message: `通知`,
description:
`您已经删除了已下线的新闻`,
placement: "bottomRight"
});
})
}
return {
dataSource,
handlePublish,
handleSunset,
handleDelete
}
}
export default usePublish;
至于每个方法中所需要的参数id,通过子组件执行父组件传过去的回调函数这种方法传参,还是用Published已发布组件来举例:
export default function Published() {
// type=2 代表已发布 接收到对应的数据和自己组建需求的方法
const { dataSource, handleSunset } = usePublish(2)
return (
<div>
{/* 子组件 通过传递button这个回调函数来获取子组件提供的id */}
<NewsPublish
dataSource={dataSource}
// 父组件接收到子组件传来的id后返回一个<Button>由子组件渲染出来 点击Button就能触发对应的事件了
button={(id) =>
<Button danger onClick={() => handleSunset(id)}>下线</Button>
}
>
</NewsPublish>
</div>
)
}
子组件中通过执行回调函数来传参给父组件,那么父组件就得到了对应的id,就可以将id传入自定义hook返回的对象中解构出来的函数,然后执行相应功能。
// 子组件返回给父组件item.id
{
title: "操作",
render: (item) => {
return <div>
{props.button(item.id)}
</div>
}
}
进行一个归纳总结:
- 自定义的hook中提供好根据type决定的数据和每个使用该hook的组件所需要的方法
- 父组件通过对象解构取得数据和自己需要的方法
- UI层子组件根据不同type所返回的对应dataSource渲染出对应的新闻数据
- 每个父组件的子组件中对应的按钮功能不一样,执行解构出来的方法需要参数,该参数需要由子组件提供
- 父组件传一个回调函数给子组件,子组件执行该函数,以将父组件方法所需的id传回去
- 父组件得到id,执行回调函数,返回一个Button,点击该按钮触发解构出来的方法(发布、下线、删除)