react-项目中自定义hooks小demo

loading 2022年12月20日 87次浏览

新闻发布模块中的未上线,已上线和已下线三个组件中的数据请求方式,页面布局方式等代码相似度高,因此抽离出一个自定义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,点击该按钮触发解构出来的方法(发布、下线、删除)