如何将 React 组件的自定义钩子与“map”一起使用

Posted

技术标签:

【中文标题】如何将 React 组件的自定义钩子与“map”一起使用【英文标题】:How to use React component's custom hook with "map" 【发布时间】:2021-04-07 21:51:04 【问题描述】:

我正在尝试制作一个Checkbox 组件。

这是我的Checkbox.tsx

import React from "react";
import * as S from "./style";

const Checkbox: React.FC<S.ICheckboxProps> = ( checked, setChecked ) => 
  return <S.StyledCheckbox checked=checked onClick=setChecked />;
;

这是我的useCheckbox.tsx

import  useState  from "react";

export const useCheckbox = (initialState: boolean) => 
  const [checked, _setChecked] = useState<boolean>(initialState);
  const setCheckedToggle = () => _setChecked((prev) => !prev);
  const setCheckedTrue = () => _setChecked(true);
  const setCheckedFalse = () => _setChecked(false);
  return  checked, setCheckedToggle, setCheckedTrue, setCheckedFalse ;
;

export default Checkbox;

效果很好。我可以这样使用

import Layout from "components/Layout";
import  useCheckbox  from "hooks/useCheckbox";
import Checkbox from "components/Checkbox";

const Home = () => 
  const  checked, setCheckedToggle  = useCheckbox(false);
  return (
    <Layout>
      <Checkbox checked=checked setChecked=setCheckedToggle />
    </Layout>
  );
;

export default Home;

但我在List 组件中遇到了问题。

List 有一个Checkbox 组件,我必须将此Listdata 一起使用。

const Home = (data) => 
  return (
    <Layout>
      data.map((d) => <List />)
    </Layout>
  );
;

这种情况下,有没有办法判断列表是否被选中?

如果List 具有useCheckbox,则Home 组件不知道checked 状态。

我应该在Home 组件中使用useCheckbox data.length 次吗?我觉得这样不好。

感谢阅读,新年快乐。

【问题讨论】:

为什么你有两个同名的组件? - 您的代码很好,但您需要在 map() 函数上使用数据之前检查数据是否实际存在。类似于 data.length > 0 && data.map() 【参考方案1】:

如果您希望复选框状态存在于Home 级别,那么您需要Home 组件中的状态,该状态可以处理多个项目,可以是数组或对象。

然后,在您映射 data 的位置,您可以将 checkedsetChecked 作为道具传递给 List,并使用项目索引在 Home 中定义的所有逻辑(或者最好使用 ID,如果有一)与您的Home 状态有关。

这是一个可以在 Home 中使用的钩子示例

import  useState  from "react";

export const useCheckboxes = () => 
  const [checkedIds, setCheckedIds] = useState([]);

  const addToChecked = (id) => setCheckedIds((prev) => [...prev, id]);

  const removeFromChecked = (id) =>
    setCheckedIds((prev) => prev.filter((existingId) => existingId !== id));

  const isChecked = (id) => !!checkedIds.find(id);

  const toggleChecked = (id) =>
    isChecked(id) ? removeFromChecked(id) : addToChecked(id);

  return  isChecked, toggleChecked ;
;

你会这样使用它

const Home = ( data ) => 
  const  isChecked, toggleChecked  = useCheckboxes();

  return (
    <Layout>
      data.map((d) => (
        <List
          key=d.id
          checked=isChecked(d.id)
          toggleChecked=() => toggleChecked(d.id)
        />
      ))
    </Layout>
  );
;

【讨论】:

以上是关于如何将 React 组件的自定义钩子与“map”一起使用的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JEST、Enzyme 在 React 中测试自定义钩子?

使用钩子将 React Context 与 AsyncStorage 结合使用

用 Jest 模拟 React 自定义钩子

为啥 jest 不能为我正在测试的自定义 React 钩子提供 useTranslation 钩子?

如何将 React 钩子(useContext、useEffect)与 Apollo 反应钩子(useQuery)结合起来

用于获取数据的自定义 React 钩子无法正常工作