简体   繁体   English

呈现非 React 组件的组件上的命令式逻辑(大部分)

[英]imperative logic on component that renders non-React components (mostly)

I have a React component (let's call it A ) that mainly renders a non-React component (a GIS map) and will on certain occasions display some modal dialogs.我有一个 React 组件(我们称之为A ),它主要呈现一个非 React 组件(一个 GIS 地图),并且在某些情况下会显示一些模式对话框。 These dialogs are the only proper React components that the A component renders and are controlled by A 's local State .这些对话框是A组件呈现的唯一正确的 React 组件,并由A的本地State The GIS map draws some features (polygons) which the component receives through its props , but the logic to draw these features is purely imperative as the GIS map cannot be controlled by React. GIS map 绘制了组件通过其props接收的一些特征(多边形),但绘制这些特征的逻辑是绝对必要的,因为 GIS map 无法由 React 控制。

So I have the following approach:所以我有以下方法:

componentDidUpdate(prevProps, prevState) {
    // check for changes between prevProps and this.props and
    // imperatively draw new polygons on map or remove polygons etc.
}

This works.这行得通。 However it occurred to me that when a new polygon arrives via props , the render is not necessary.然而我突然想到,当一个新的多边形通过props到达时, render是不必要的。 This is because drawing the polygons on the map is done in an imperative way via direct DOM manipulation (through API calls to the GIS library).这是因为在 map 上绘制多边形是通过直接 DOM 操作(通过 API 调用 GIS 库)以命令的方式完成的。 As such, I wrote a shouldComponentUpdate as follows:因此,我写了一个shouldComponentUpdate如下:

shouldComponentUpdate(nextProps, nextState) {
   return !isEqual(nextState, this.state); // isEqual from lodash doing a deep comparison
}

The idea is that I only re-render my component for local state changes (which control a couple of modal dialogs) since these are the only React-controlled parts of the component and require render to be called.这个想法是我只为本地 state 更改(控制几个模态对话框)重新渲染我的组件,因为这些是组件中唯一受 React 控制的部分并且需要调用render The rest of the changes (that affect non-React components) I pick up in componentDidUpdate and enforce imperatively (that was the plan at least).我在componentDidUpdate中选择的 rest 更改(影响非 React 组件)并强制执行(至少这是计划)。

The problem with the new approach is that if shouldComponentUpdate returns false , then componentDidUpdate is not called at all.新方法的问题在于,如果shouldComponentUpdate返回false ,则根本不会调用componentDidUpdate So the only way to get hold of props changes that trigger imperative logic is via componentWillReceiveProps which is however deprecated .因此,获取触发命令式逻辑的props更改的唯一方法是通过componentWillReceiveProps ,但它已被弃用

Any thoughts?有什么想法吗? Is my approach flawed in a deeper level and/or how to deal with this connundrum?我的方法在更深层次上是否存在缺陷和/或如何处理这个难题? Is what I am trying to accomplish achievable only using a functional component approach (as has been suggested by a comment) and can I achieve it with class components as well?我试图实现的目标是否只能使用功能组件方法(正如评论所建议的那样)实现,我也可以使用 class 组件来实现它吗?

Seems to be an interesting problem.似乎是一个有趣的问题。 How are props mapped to your GIS-Widget?道具如何映射到您的 GIS-Widget? React does allow nested elements that are not under react rule ( docu ). React 确实允许嵌套元素不在反应规则( docu ) 之下。

I would ditch the old class based lifecycle functions and implement a functional component with useEffect and useRef hook.我会抛弃旧的基于 class 的生命周期函数,并使用useEffectuseRef钩子实现一个功能组件。

Does the following code somehow resemble your current issue?以下代码在某种程度上类似于您当前的问题吗? Let me know what I got wrong and we can make it work.让我知道我做错了什么,我们可以让它发挥作用。

import React, { useRef, useEffect, useState } from 'react';
import gismap from 'gis-map';

const MyGISWrapper = ({ streets, waterways }) => {
  const map = useRef();

  // only once, on first render
  useEffect( () => { if (map.current) gismap('init', map.current); }, []);

  // update polygons when props change
  useEffect( () => {
    if (map.current) map.current.gismap('update', streets, waterways);
  }, [streets, waterways]);

  // some example modal
  const [showConfirmation, setShowConfirmation] = useState(false);
  const openConfirmation = () => setShowConfirmation(true);
  const closeConfirmation = () => setShowConfirmation(false);

  return (
    <div className="container">
      <div className="gis-map-root" ref={map} />
      <div className="modal-popup-area">
        { showConfirmation && <Confirmation onClose={closeConfirmation} /> }
      </div>
      <button onClick={openConfirmation} />
    </div>
  );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM