如何将Django URL作为Props传入React导航栏组件?
嘿,别担心,你遇到的是React和Django协作时非常典型的新手问题——核心原因是两者的渲染时机不匹配,咱们一步步理清楚并解决它:
为什么你的链接无效?
Django的模板标签{% url 'main:index' %}是在服务器端渲染页面时解析的,会被替换成真实的URL路径;但你的React代码是在客户端浏览器里运行的——当浏览器拿到页面时,Django已经完成了模板渲染,而你写在React数组里的{% url ... %}会被当成普通字符串,浏览器根本不认识这个语法,自然无法生成有效链接。
正确的解决方案(适合新手的简单版)
我们可以让Django提前把需要的URL渲染成全局变量,让React直接读取这个变量,而不是在React代码里写Django模板标签。
步骤1:在Django模板中注入全局URL变量
打开你加载React的HTML模板(比如index.html或者base.html),在引入React脚本之前,添加一段全局变量定义:
<script> // 把需要的Django URL提前渲染好,存在window全局对象里 window.djangoUrls = { mainIndex: "{% url 'main:index' %}", // 以后需要其他链接,直接在这里添加即可 // 比如 userProfile: "{% url 'accounts:profile' %}" }; </script>
这样Django服务器渲染页面时,会把{% url %}替换成真实的URL,浏览器加载页面后,window.djangoUrls就会包含正确的路径。
步骤2:修改React代码使用全局变量
更新你的index.js,直接读取全局变量里的URL:
let navbarUrls = [ {key: 0, url: window.djangoUrls.mainIndex, label: "Main Page"} ]; ReactDOM.render(<Navbar urls={navbarUrls} />, document.getElementById('navbar'));
步骤3:修复React组件里的小问题
另外注意,在JSX里不能用class(这是JavaScript的关键字),要改成className,同时把链接的文字也做成可配置的(从props里取):
修改Navbar.js的渲染部分:
import React, {Component} from 'react'; class Navbar extends Component { render() { return ( <nav className="navbar navbar-toggleable-md navbar-light bg-faded"> <button className="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span className="navbar-toggler-icon"></span> </button> {this.props.urls.map(item => ( <a className="navbar-brand" key={item.key} href={item.url}>{item.label}</a> ))} <div className="collapse navbar-collapse" id="navbarSupportedContent"> <ul className="navbar-nav mr-auto"> </ul> <div className="navbar-brand"> <div id="current-time"> </div> </div> </div> </nav> ) } } export default Navbar
进阶方案(如果以后要做前后端分离)
如果你的项目打算做成前后端完全分离的模式,可以让Django写一个简单的API接口,返回所有前端需要的URL映射,然后React在组件componentDidMount(或者用hooks的useEffect)里请求这个接口获取URL。不过这个对纯新手来说稍复杂,先把上面的简单版跑通就好~
这样修改后,你的导航栏链接应该就能正常工作了,本质就是让Django提前把URL处理好,交给React使用,避免在客户端代码里写服务器端的模板语法。
内容的提问来源于stack exchange,提问作者Dominykas55

