如何在Solid JS中过滤自定义组件子元素?场景切换器查找失效
问题分析与解决方案
核心问题
你当前的代码逻辑错误在于:你试图匹配组件节点的id属性,但实际把id写在了组件返回的DOM元素上。在SolidJS中,props.children里的是组件节点对象,它本身并没有你设置的id——那个id是组件内部渲染的<div>的DOM属性,只有组件渲染后才会出现在真实DOM中,虚拟DOM层面的组件节点根本拿不到这个值,所以find始终返回undefined。
方案一:给组件传递id Props(最贴合你的初始思路)
修改场景组件的调用方式,直接给组件传递id参数:
<SceneSwitcher> <LoadingScene id="loading" /> <AppScene id="app" /> <LoginScene id="login" /> </SceneSwitcher>
然后修改SceneSwitcher的匹配逻辑,读取组件节点的props.id:
export default function SceneSwitcher(props) { const [scene, setScene] = createSignal(""); // ...你的其他逻辑 return ( <> {props.children.find(child => child.props.id === scene()) ?? <div></div>} </> ); }
场景组件不需要改动,SolidJS会自动把传递的id放到props里(即使组件内部没用到这个props也没关系,我们只在SceneSwitcher里用它做匹配)。
方案二:场景映射表(更易维护的方案)
如果后续场景较多,遍历children会越来越麻烦,建议直接在SceneSwitcher内部维护一个场景名称到组件的映射表:
// SceneSwitcher.tsx import LoadingScene from './LoadingScene'; import AppScene from './AppScene'; import LoginScene from './LoginScene'; export default function SceneSwitcher() { const [currentScene, setCurrentScene] = createSignal("loading"); // 定义场景映射 const sceneMap = { loading: <LoadingScene />, app: <AppScene />, login: <LoginScene /> }; // 切换场景时直接调用 setCurrentScene("app") 即可 return ( <> {sceneMap[currentScene()] ?? <div>无匹配场景</div>} </> ); }
这种方式不需要外部传递children,所有场景管理都在SceneSwitcher内部,逻辑更清晰,后续新增场景只需要在sceneMap里加一行就行。
方案三:给组件添加静态标识属性(可选)
如果你不想给组件传递额外props,可以给场景组件添加静态属性:
// LoadingScene.tsx export default function LoadingScene() { return ( <div> <h1>Loading content...</h1> </div> ); } // 添加静态场景ID LoadingScene.sceneId = "loading";
然后在SceneSwitcher里匹配组件的类型静态属性:
export default function SceneSwitcher(props) { const [scene, setScene] = createSignal(""); return ( <> {props.children.find(child => child.type.sceneId === scene()) ?? <div></div>} </> ); }
这种方式适合不想修改组件调用方式的场景,但可读性不如前两种。
内容的提问来源于stack exchange,提问作者Siro
相关产品推荐
相关产品推荐

