【问题标题】:Passing data into a React component within existing app将数据传递到现有应用程序中的 React 组件
【发布时间】:2022-01-07 15:14:27
【问题描述】:

我有一个管理产品的现有 PHP 应用程序。每个产品可以有多个图像。目前添加或删除图像的过程都是通过 PHP 服务器端处理的,因此每个操作都需要加载页面。

由于这是一个现有的大型应用程序,我希望对其进行改进,其中之一是用一个反应组件替换这个图像添加/删除部分。

所以,我确实做到了。我创建了一个名为 ImageManager 的组件并将其渲染为一个带有 id 的 div。

editProduct.html.twig

<div id="image-manager" data-js-images="{images: ['1.jpg', '2.jpg', '3.jpg']}"></div>

app.js

// Grab element & props
const element = document.getElementById('image-manager');
const props = element.dataset;

// Render it
ReactDOM.render(<ImageManager {...props} />, element);

到目前为止很简单。这是我的组件... ImageManager.js

import React, {Fragment, useState, useEffect} from 'react';

const ImageManager = ({jsImages}) => {

    const [images, setImages] = useState([]);

    // When jsImages changes
    useEffect(() => {
        setImages(jsImages);
    }, [jsImages]);

    return (
        <Fragment>
            <div className="row">
                {images.map((img, idx) => {
                    return (
                        <div key={idx} className="col-2">
                            <img src={img}/>

                            <button type="button" className="btn btn-danger" onClick={() => {
                                // Remove it
                                const imagesCopy = [...images];
                                imagesCopy.splice(idx, 1);
                                setImages(imagesCopy);
                            }}>Remove</button>
                        </div>
                    );
                })}
            </div>
        </Fragment>
    );
};

export default ImageManager;

这一切都很好,但是......我遇到的问题是一些常规的非反应 JS 在此组件之外添加和处理了新图像。处理图片上传并从服务器返回新文件名的页面没有其他地方的按钮。

所以我的问题是,如何让我的 ImageManager 组件知道有一个新图像?似乎组件没有选择更改“data-js-images”属性。我猜这只会被读取一次,如果更新则什么都不会发生。

如果我重新渲染组件并合并到我的新图像中,然后将其传递给“data-js-images”属性,那么它工作正常,但我觉得重新渲染整个组件不是“正确的” " 这样做的方法?

需要明确的是,没有顶级组件或类似的东西。 只有一个 app.js 文件和一堆 HTML。

任何帮助将不胜感激! 谢谢

【问题讨论】:

  • 不确定我的建议是否有效,但既然你说新图像是在 vanilla js 中处理的,你为什么不尝试在那里处理图像事件的变化并基于此渲染您的反应组件?
  • 我确实是这样实现的,这样当添加新图像时,它会有效地破坏现有的 div 并重新渲染组件。它确实有效,但这感觉有点不对劲。我很感激考虑到我想要实现的目标,没有真正需要过于挑剔,我只是想确保我以正确的方式做到这一点。
  • 在您使用的 react 组件中使用 useEffect (即使它不能正常工作,因为答案解释正确),它只会在每次图像更改时重新渲染组件。所以无论哪种方式,你都会重新渲染你的组件。在反应中做这件事完全没问题。

标签: javascript reactjs react-component


【解决方案1】:

这里没有使用 useEffect 钩子,因为您只渲染一次组件并且不更改道具。你应该观察带有 data 属性的 html 元素,当它发生变化时你应该更新组件的 props。

你可以使用 MutationObserver 构造函数,例如

const observer = new MutationObserver((mutations, observer) => {
    // Do something when the element changes
});

observer.observe(element, {
    attributes: true
});

我自己没有测试过,但它应该可以工作。 其他的看看thisattricle

【讨论】:

  • 我已经尝试过了,它确实有效,但这意味着我的组件必须处理两个方向的数据更改,即组件进行更改(例如删除图像)和外部应用程序进行更改(例如添加图片)。因此,如果我的组件删除了一个图像,这会触发对“images”的状态更新,进而更新 div“data-js-images”属性,进而触发观察者,该观察者再次调用“setImages”状态更新。我想我正在寻找一种可以拥有单个数据对象并对其进行操作的方法?
  • 如果您的组件直接删除图像,则更新 data-js-images(例如,加上数据库的其他内容)而不是您的组件状态。这样你就可以处理 data-js-images 更新,然后它会触发 useEffect 钩子。我知道这看起来像是绕道而行,但是您的组件只会重新渲染一次。这样你只需要操作 data-js-images。
  • 这比我做的更有意义!真的很好用,谢谢!
猜你喜欢
  • 2018-01-25
  • 2017-05-08
  • 2021-09-26
  • 2018-01-06
  • 2020-11-24
  • 1970-01-01
  • 2012-07-07
  • 2020-09-23
  • 2022-06-30
相关资源
最近更新 更多