首页 > 解决方案 > 如何使用 useContext 和 useRef 正确连接反应组件

问题描述

我想在使用外部库(leafletjs)的组件的按钮onclick事件调用方法之后。这是基本示例。我的按钮只是在 Context 中设置 true 或 false 值。

import React, { useContext } from "react";
import Button from "@material-ui/core/Button";
import { ToolContext } from "../../../context/ToolContext";

function IsochroneTool() {
  let {
    generateIso,
    setGenerateIso,
  } = useContext(ToolContext);

  return (
    <>
      <Button
        size={"small"}
        onClick={() => {
          setGenerateIso(true);
        }}
      >
        Generate
      </Button>
    </>
  );
}

export default IsochroneTool;

在我的 Map 组件中有一个 useEffect 钩子,它在上下文变化时很容易受到攻击并执行一些逻辑。

export default function Map(props) {
    let {
        generateIso, setGenerateIso,
    } = useContext(ToolContext)
    const mapRef = useRef(null);

    useEffect(() => {
            mapRef.current = L.map(props.id, {
                editable: true,
                zoomControl: false,
                contextmenu: true,
                maxZoom: 20,
                minZoom: 6,
                doubleClickZoom: false,
                contextmenuWidth: 120,
            })
        }, []
    );



    useEffect(() => {
        if (generateIso) {
          // do my stuff add or remove objects and layers from mapRef.current 
          // or call some internal methods of leaflet 
          
        //   L.marker([0,0]).addTo(mapRef.current)

        }
        setGenerateIso(false)
    }, [generateIso])

    useGenerateIsoHook(generateIso, mapRef.current)

    return (
        <>
                <div
                    ref={mapRef}
                    id={props.id} style={{
                    position: "absolute",
                    // top: 0,
                    // left: 0,
                    width: "100%",
                    height: "calc(100vh - 64px)",
                }}>
                </div>
        </>
    );
}

代码运行良好,但如何编写更简单?这是对的吗?问题是在我的上下文中,有很多 const 需要做一些检查,因为 useEffect 被触发了。我想写一些自定义钩子来在不同的地图组件中使用这个函数

这是虚拟示例

export const useGenerateIsoHook =  (removeIsoTrigger, myref) => {
    useEffect(() => {
        if (generateIso) {
            // do my stuff add or remove objects and layers to mapRef.current 
          }
          setGenerateIso(false)
    }, [generateIso])

}

如何正确编写它们?

标签: reactjsreact-hooksleafletuse-effect

解决方案


没有“正确”的方式来编写您所描述的内容,只有最适合您需求的解决方案。因此,我的回答将是主观的,但您似乎对我可以帮助您的自定义钩子感兴趣。

首先,您可以在自定义挂钩中挂钩它,然后通过 return 语句传递方法。其次,这里不需要useEffect,你真正想要的是当你需要生成地图时的回调。您可以使用回调更新上下文

我假设你有一个父“提供者”组件传递上下文,所以你是一个回调而不是一个标志:

const isoContext = createContext({
  onGenerateIso: undefined,
  setOnGenerateIso: undefined
});

const Provider = () => {
  const [onGenerateIso, setOnGenerateIso] = useState(() => null);
  const contextValue = {
    onGenerateIso,
    setOnGenerateIso
  };

  return (
    <isoContext .Provider value=contextValue>
    ...
    </isoContext .Provder>
  );
}
export const useGenerateIsoHook = () => useContext(isoContext);

在 Map 组件中使用钩子设置回调

  const { setOnGenerateIso } = useGenerateIsoHook();
  const generateIso = useCallback(() => {
    if (myMapRef.current) {
      // do stuff with map ref
    }
  }, [myMapRef]);

  useEffect(() => {
    setOnGenerateIso(generateiso);
  }, [generateiso]);

在 Tool 组件中使用回调:

const { onGenerateIso } = useGenerateIsoHook();

<Button
   size={"small"}
   disabled={typeof(onGenerateIso) !== 'function'}
   onClick={() => onGenerateIso()}
>
   Generate
</Button>

推荐阅读