React Router v4编程式导航并向目标组件传递JSX
嘿,这个问题问得很实际,我来帮你拆解下可行的方案和安全风险~
dangerouslySetInnerHTML的替代方案 其实React Router的history.push的state参数,除了字符串,还能传递更灵活的内容,完全不用走HTML字符串解析的路子:
1. 直接传递JSX元素(最简便)
如果只是单页内的客户端导航(不需要考虑页面刷新的情况),你可以直接把JSX作为state传递,目标组件直接渲染即可:
// 跳转时的代码 this.props.history.push("/mycomponent", { message: <span>Smiley <i className="far fa-smile"/></span> });
// 目标组件MyComponent class MyComponent extends Component { render() { // 加个兜底判断,避免刷新页面后state丢失报错 const { message } = this.props.location.state || {}; return <div>{message}</div>; } } export default MyComponent;
⚠️ 注意:这种方式的局限是页面刷新后location.state会丢失,因为React Router的state是存在浏览器内存里的,不会持久化。如果需要支持刷新,得看下面的方案。
2. 传递渲染配置(支持刷新)
如果要考虑页面刷新的场景,可以传递一个可序列化的配置对象,在目标组件里根据配置动态渲染JSX:
// 跳转时传递配置 this.props.history.push("/mycomponent", { messageConfig: { text: "Smiley", iconClass: "far fa-smile" } });
// 目标组件MyComponent class MyComponent extends Component { renderMessage() { const { messageConfig } = this.props.location.state || {}; if (!messageConfig) return null; return ( <span> {messageConfig.text} <i className={messageConfig.iconClass}/> </span> ); } render() { return <div>{this.renderMessage()}</div>; } } export default MyComponent;
这种方式的好处是配置是纯JSON格式,可序列化,就算页面刷新,你也可以把配置存在URL参数或者本地存储里恢复,同时完全避免了HTML解析的安全风险。
dangerouslySetInnerHTML的安全性 如果实在要用到它,得先明确它的风险:它会把字符串直接解析成HTML插入到DOM中,如果字符串包含用户输入或来自不可信的数据源,很容易被注入恶意脚本(XSS攻击)。
但如果你的场景满足以下两个条件,是相对安全的:
- 这个HTML/JSX字符串是完全由你的代码生成的,没有任何用户可控的内容;
- 字符串里没有危险内容(比如
<script>标签、onclick这类事件属性)。
比如你例子里的<i className="far fa-smile"/>,是固定的、可控的代码,用起来没问题。但只要字符串里有哪怕一点点用户输入的内容,都绝对不能用这个方法。
优先选择传递JSX元素或者渲染配置的方式,既符合React的组件化逻辑,又安全可靠;只有在字符串完全可控、没有不可信内容的极端场景下,才考虑使用dangerouslySetInnerHTML。
内容的提问来源于stack exchange,提问作者MrSegFaulty

