Javascript 将redux存储传递给react dom/server';s renderToString()方法

Javascript 将redux存储传递给react dom/server';s renderToString()方法,javascript,reactjs,redux,react-redux,mapbox-gl-js,Javascript,Reactjs,Redux,React Redux,Mapbox Gl Js,我有一个常规的React应用程序(CRA)。在应用程序的一部分中,我使用Mapbox来显示地图,要呈现弹出窗口,我需要传入一个html内容字符串来呈现。我仍然希望使用React来呈现弹出窗口,而不是传入原始html,因此我执行以下操作: const renderedContent = renderToString( <Popup port={port} poiType={poiType} activeView={activeView}

我有一个常规的React应用程序(CRA)。在应用程序的一部分中,我使用Mapbox来显示地图,要呈现弹出窗口,我需要传入一个html内容字符串来呈现。我仍然希望使用React来呈现弹出窗口,而不是传入原始html,因此我执行以下操作:

const renderedContent = renderToString(
    <Popup
      port={port}
      poiType={poiType}
      activeView={activeView}
      isPortsOnly={isPortsOnly}
      locations={locations}
    />
  )
用html字符串创建一个弹出窗口


这正如预期的那样有效现在我的问题是:我不想在弹出组件中使用redux。两者都发送一个事件,并读取全局状态。我该怎么做?我真的可以这样做吗?


我试过的 如果我试图在弹出组件中使用
redux
,我会收到以下错误消息:


错误:找不到react redux上下文值;请确保组件包装在一个

中,这很有趣!我已经对以下代码进行了修改,滚动查看一些解释:

Popup.js

import React, { useRef, useEffect } from "react";
import { connect } from "react-redux";
import { Popup } from "mapbox-gl";

import { zoomAction } from "./ActionCreators";

const CustomPopup = ({ zoomAction, lng, lat, zoom, map }) => {
  const popUpRef = useRef(null);

  useEffect(() => {
    if (popUpRef.current && map) new Popup().setLngLat([lng, lat]).setDOMContent(popUpRef.current).addTo(map);
  }, [popUpRef, map, lng, lat]);

  const zoomIn = () => {
    zoomAction();
    map.zoomIn(zoom);
  };

  return (
    <div ref={popUpRef}>
      <h1>Hello World!</h1>
      <button onClick={zoomIn}>zoom in (currently {zoom})</button>
    </div>
  );
};

const mapStateToProps = (state) => {
  return { ...state };
};

const mapDispatchToProps = { zoomAction };

export default connect(mapStateToProps, mapDispatchToProps)(CustomPopup);
import React, { useMemo, useState } from "react";
import MapboxGl from "mapbox-gl";
import { connect } from "react-redux";

import "mapbox-gl/dist/mapbox-gl.css";
import "./MapGl.css";

import Popup from "./Popup";

MapboxGl.accessToken = "pk.eyJ1IjoibmljZXk3MjMxMSIsImEiOiJja2hrdGE4MHkwMGxxMndteDRucGIyMDVqIn0.MKokCfCrE8VskLRUNGO0hw";

const MapGl = ({ zoom, lng, lat }) => {
  const [isLoaded, setIsLoaded] = useState(false);
  const map = useMemo(() => {
    if (isLoaded)
      return new MapboxGl.Map({
        container: document.querySelector(".mapContainer"),
        style: "mapbox://styles/mapbox/streets-v11",
        center: [lng, lat],
        zoom: zoom
      });
  }, [isLoaded]);

  return (
    <div>
      <div ref={() => setIsLoaded(true)} className="mapContainer" />
      {map && <Popup map={map} />}
    </div>
  );
};

const mapStateToProps = (state) => {
  return { ...state };
};

export default connect(mapStateToProps)(MapGl);
.mapContainer {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
}
import React from "react";

import "./App.css";

import MapGl from "./MapGl";

export default () => {
  return <MapGl />;
};
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";

import "./index.css";

import store from "./Store";
import App from "./App";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);
import { createStore } from "redux";

const initialState = {
  lng: -96,
  lat: 37.8,
  zoom: 3
};

function rootReducer(state = initialState, action) {
  switch (action.type) {
    case "zoom":
      return { ...state, zoom: state.zoom + 1 };
    default:
      return state;
  }
}

let store = createStore(rootReducer);

export default store;
export const zoomAction = () => ({
  type: "zoom"
});
App.js

import React, { useRef, useEffect } from "react";
import { connect } from "react-redux";
import { Popup } from "mapbox-gl";

import { zoomAction } from "./ActionCreators";

const CustomPopup = ({ zoomAction, lng, lat, zoom, map }) => {
  const popUpRef = useRef(null);

  useEffect(() => {
    if (popUpRef.current && map) new Popup().setLngLat([lng, lat]).setDOMContent(popUpRef.current).addTo(map);
  }, [popUpRef, map, lng, lat]);

  const zoomIn = () => {
    zoomAction();
    map.zoomIn(zoom);
  };

  return (
    <div ref={popUpRef}>
      <h1>Hello World!</h1>
      <button onClick={zoomIn}>zoom in (currently {zoom})</button>
    </div>
  );
};

const mapStateToProps = (state) => {
  return { ...state };
};

const mapDispatchToProps = { zoomAction };

export default connect(mapStateToProps, mapDispatchToProps)(CustomPopup);
import React, { useMemo, useState } from "react";
import MapboxGl from "mapbox-gl";
import { connect } from "react-redux";

import "mapbox-gl/dist/mapbox-gl.css";
import "./MapGl.css";

import Popup from "./Popup";

MapboxGl.accessToken = "pk.eyJ1IjoibmljZXk3MjMxMSIsImEiOiJja2hrdGE4MHkwMGxxMndteDRucGIyMDVqIn0.MKokCfCrE8VskLRUNGO0hw";

const MapGl = ({ zoom, lng, lat }) => {
  const [isLoaded, setIsLoaded] = useState(false);
  const map = useMemo(() => {
    if (isLoaded)
      return new MapboxGl.Map({
        container: document.querySelector(".mapContainer"),
        style: "mapbox://styles/mapbox/streets-v11",
        center: [lng, lat],
        zoom: zoom
      });
  }, [isLoaded]);

  return (
    <div>
      <div ref={() => setIsLoaded(true)} className="mapContainer" />
      {map && <Popup map={map} />}
    </div>
  );
};

const mapStateToProps = (state) => {
  return { ...state };
};

export default connect(mapStateToProps)(MapGl);
.mapContainer {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
}
import React from "react";

import "./App.css";

import MapGl from "./MapGl";

export default () => {
  return <MapGl />;
};
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";

import "./index.css";

import store from "./Store";
import App from "./App";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);
import { createStore } from "redux";

const initialState = {
  lng: -96,
  lat: 37.8,
  zoom: 3
};

function rootReducer(state = initialState, action) {
  switch (action.type) {
    case "zoom":
      return { ...state, zoom: state.zoom + 1 };
    default:
      return state;
  }
}

let store = createStore(rootReducer);

export default store;
export const zoomAction = () => ({
  type: "zoom"
});
ActionCreators.js

import React, { useRef, useEffect } from "react";
import { connect } from "react-redux";
import { Popup } from "mapbox-gl";

import { zoomAction } from "./ActionCreators";

const CustomPopup = ({ zoomAction, lng, lat, zoom, map }) => {
  const popUpRef = useRef(null);

  useEffect(() => {
    if (popUpRef.current && map) new Popup().setLngLat([lng, lat]).setDOMContent(popUpRef.current).addTo(map);
  }, [popUpRef, map, lng, lat]);

  const zoomIn = () => {
    zoomAction();
    map.zoomIn(zoom);
  };

  return (
    <div ref={popUpRef}>
      <h1>Hello World!</h1>
      <button onClick={zoomIn}>zoom in (currently {zoom})</button>
    </div>
  );
};

const mapStateToProps = (state) => {
  return { ...state };
};

const mapDispatchToProps = { zoomAction };

export default connect(mapStateToProps, mapDispatchToProps)(CustomPopup);
import React, { useMemo, useState } from "react";
import MapboxGl from "mapbox-gl";
import { connect } from "react-redux";

import "mapbox-gl/dist/mapbox-gl.css";
import "./MapGl.css";

import Popup from "./Popup";

MapboxGl.accessToken = "pk.eyJ1IjoibmljZXk3MjMxMSIsImEiOiJja2hrdGE4MHkwMGxxMndteDRucGIyMDVqIn0.MKokCfCrE8VskLRUNGO0hw";

const MapGl = ({ zoom, lng, lat }) => {
  const [isLoaded, setIsLoaded] = useState(false);
  const map = useMemo(() => {
    if (isLoaded)
      return new MapboxGl.Map({
        container: document.querySelector(".mapContainer"),
        style: "mapbox://styles/mapbox/streets-v11",
        center: [lng, lat],
        zoom: zoom
      });
  }, [isLoaded]);

  return (
    <div>
      <div ref={() => setIsLoaded(true)} className="mapContainer" />
      {map && <Popup map={map} />}
    </div>
  );
};

const mapStateToProps = (state) => {
  return { ...state };
};

export default connect(mapStateToProps)(MapGl);
.mapContainer {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
}
import React from "react";

import "./App.css";

import MapGl from "./MapGl";

export default () => {
  return <MapGl />;
};
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";

import "./index.css";

import store from "./Store";
import App from "./App";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);
import { createStore } from "redux";

const initialState = {
  lng: -96,
  lat: 37.8,
  zoom: 3
};

function rootReducer(state = initialState, action) {
  switch (action.type) {
    case "zoom":
      return { ...state, zoom: state.zoom + 1 };
    default:
      return state;
  }
}

let store = createStore(rootReducer);

export default store;
export const zoomAction = () => ({
  type: "zoom"
});

第一件事是将
setHtml
替换为
setDOMContent
,它接受现有的DOM节点而不是字符串。其次,
renderToString
的使用与服务器端呈现相关联,这是一种情景呈现。在本例中,我创建了一个带有按钮的弹出窗口,该按钮发送缩放操作以更新存储以及同步地图对象本身。您可以看到应用于地图的新缩放值以及弹出窗口内更新的存储值。

尝试在弹出窗口控制器所在的位置创建一个函数,该函数将分派某些内容并将其传递给该组件。我的意思是:

const doSomething = () => {
  dispatch(do());
};

const renderedContent = renderToString(
  <Popup
    port={port}
    poiType={poiType}
    activeView={activeView}
    isPortsOnly={isPortsOnly}
    locations={locations}
    onDoSomething={doSomething}
  />
)
const doSomething=()=>{
调度(do());
};
const rendercontent=renderToString(
)

看看这篇文章,希望它能帮助你@Boudyhesham在这篇文章中看不到任何相关内容。你能说得更具体些吗?@eivindml我的回答能解决你的问题吗?如果缺少某些内容,请告诉我。您可以在弹出窗口中添加一些选择器/引用,然后查找此dom元素,然后使用您需要的任何事件添加EventListenerwant@eivindml我的答案对你有用吗?谢谢你!我很确定这将解决我的问题,但还没有时间完全实现它。我将对我已经完全测试过的结果发表评论。但是我给了你赏金,因为我很确定这就是我要找的