React项目中redux-tooltip与react-simple-maps的Hook集成问题
看起来你遇到的核心问题是redux-tooltip的Tooltip组件无法正确读取Redux中的状态,同时没有触发tooltip的显示/隐藏动作。作为Redux新手,这几个基础点很容易踩坑,我来一步步帮你解决:
1. 修正Redux状态的读取路径
你当前的useSelector路径是错误的:
const tooltipState = useSelector(state => { return state.tooltip.default });
redux-tooltip的reducer返回的状态是直接挂载在state.tooltip下的(因为你在combineReducers里把它命名为tooltip),并没有嵌套的default属性。正确的写法应该是:
const tooltipState = useSelector(state => state.tooltip);
不过其实你不需要手动读取这个状态传给Tooltip——因为redux-tooltip提供的<Tooltip />组件已经通过connect高阶组件自动连接到Redux了,只要你的store结构正确,它会自己读取状态。
2. 给地图元素添加tooltip触发事件
你现在的Geography组件没有绑定鼠标事件,所以Redux里的tooltip状态永远不会被更新,Tooltip自然无法显示。你需要在<Geography>上添加onMouseEnter和onMouseLeave来触发show和hide动作:
<Geography key={i} geography={geography} projection={projection} // 添加鼠标事件 onMouseEnter={(event) => { const countryCode = geography.properties["Alpha-2"]; const countryName = geography.properties["NAME"]; const value = dict[countryCode] || 0; // 触发tooltip显示动作,传入内容和位置 dispatch(show({ content: ( <div className="tooltip-content"> <h3>{countryName}</h3> <p>数值: {value}</p> </div> ), position: { x: event.clientX + 10, // 偏移一点避免遮挡鼠标 y: event.clientY + 10 } })); }} onMouseLeave={() => { // 触发tooltip隐藏动作 dispatch(hide()); }} // ... 你的style属性不变 />
这样当鼠标 hover 到地理区域时,Redux中的tooltip状态会被更新,Tooltip组件就能感知到并显示内容了。
3. 关于next-redux-wrapper的误解
你提到示例用了next-redux-wrapper,但这个HOC是Next.js专属的Redux集成方案,用于在服务端渲染场景下同步store状态。你现在用的是普通React应用(通过ReactDOM.render和BrowserRouter),完全不需要这个工具——你当前的store配置(用Provider包裹App)是正确的,不用纠结这个点。
4. 验证Tooltip组件的正确性
确保你导入的Tooltip是redux-tooltip提供的已连接组件,它会自动从Redux读取show、content、position等状态,不需要你手动传props:
import { Tooltip, actions } from "redux-tooltip";
你当前的<Tooltip />写法是对的,只要Redux状态被正确更新,它就会正常显示。
完整修改后的地图组件片段
import { useSelector, useDispatch } from "react-redux"; import { ComposableMap, ZoomableGroup, Geographies, Geography, Markers, Marker } from "react-simple-maps"; import { scaleLinear } from "d3-scale"; import { Tooltip, actions } from "redux-tooltip"; const Detail = props => { const exposureScale = scaleLinear() .domain([0, props.val]) .range(["white", "#f39c12"]); const dispatch = useDispatch(); const { show, hide } = actions; // 如果你不需要手动使用tooltip状态,可以去掉这行 // const tooltipState = useSelector(state => state.tooltip); return ( <div> <ComposableMap> <ZoomableGroup disablePanning={true}> <Geographies geography={json} disableOptimization={false}> {(geographies, projection) => geographies.map((geography, i) => { const countryCode = geography.properties["Alpha-2"]; // 初始化dict值 if (!dict[countryCode]) dict[countryCode] = 0; return ( <Geography key={i} geography={geography} projection={projection} onMouseEnter={(event) => { const countryName = geography.properties["NAME"]; const value = dict[countryCode]; dispatch(show({ content: ( <div> <h4>{countryName}</h4> <p>数值: {value}</p> </div> ), position: { x: event.clientX + 10, y: event.clientY + 10 } })); }} onMouseLeave={() => dispatch(hide())} style={{ default: { fill: exposureScale(dict[countryCode]), stroke: "#607D8B", strokeWidth: 0.75, outline: "none" }, hover: { fill: "#607D8B", stroke: "#607D8B", strokeWidth: 0.75, outline: "none" }, pressed: { fill: "#FF5722", stroke: "#607D8B", strokeWidth: 0.75, outline: "none" } }} /> ); })} </Geographies> </ZoomableGroup> </ComposableMap> <Tooltip /> </div> ); }; export default Detail;
最后检查点
- 确认你的
dict变量是可正确访问的(比如在组件内初始化或者作为props传入) - 打开Redux DevTools,查看当鼠标hover时,
tooltip状态是否有变化(show变为true,content有值) - 如果还是报错,可以检查
redux-tooltip的版本,确保和你的Redux版本兼容(比如Redux 4.x以上)
内容的提问来源于stack exchange,提问作者Raph117

