上节课我们介绍了用NavLink
来代替Link
编写路由链接,那么这节课我们来介绍一下关于NavLink
的封装。
回顾
在开始介绍NavLink
的封装之前,我们来对上节课的内容来做一个简单的回顾
NavLink
可以自动根据点击状态追加className
,默认active
NavLink
可以根据activeClassName
来指定追加的className
以上就是上节课的主要内容,那么接下来我们来说一下关于NavLink
应该如何封装。
为什么要封装
我们先来回顾一下我们之前的代码,我们两个导航项,那么我们就要写两个NavLink
,但是如果我们的导航项一多,那么是不是就要在App
组件中一直添加NavLink
?而且我们写NavLink
的时候,每个NavLink
之间的重复内容是不是特别多啊?唯一不同的就是展示内容和to
属性。
那么这样的话,如果我们要写十几个导航项的话,那么我们就要写十几个NavLink
,这样我们代码的优化空间是不是就特别大啊?所以说我们要对这一部分来做一个封装。
如何封装
其实封装也很简单,那么我们现在来做一个组件叫MyNavLink
,这个组件呢我们在里面把所有重复的东西都封装好,然后我们在App
中渲染这个组件的时候,只把不同的内容传进去是不是就好了?就像这样<MyNavLink to="/test">Test</MyNavLink>
?
那么我来问大家,这个MyNavLink
组件是路由组件还是一般组件?
这个组件是不是我们自己写出来渲染的?而且to
属性是不是也是我们自己传的?所以说这个组件是不是一般组件啊?
实现封装
既然我们已经有了封装的思路了,那么我们来实现一下吧:
// MyNavLink 组件 import { NavLink } from 'react-router-dom' export default class MyNavLink extends Component { render() { const {to} = this.props; return ( <NavLink className="list-group-item" to={to}>About</NavLink> ); } } // App 组件 export default class App extends Component { render() { return ( <div> ... <div className="list-group"> <MyNavLink to="/about" /> <MyNavLink to="/home" /> </div> ... </div> ); } }
我们把暂时不需要关注的代码先隐藏一下,我们来看MyNavLink
组件,首先,我们既然要实现我们自己的一个对NavLink
的二次封装,那么是不是要基于NavLink
?那么我们就要导入NavLikn
。因为我们说了,要通过props
来传入to
属性,那么我们是不是要在MyNavLink
组件中来接收啊?那么MyNavLink
组件中的to
属性就不能再写死了。
然后我们再来看App
组件,我们手动渲染MyNavLink
组件,而且正常传入了to
属性,那让我们来看一下效果吧:
我们也能切换,但是有一个问题就是我们这两个导航栏为什么都是About
呢?因为我们在MyNavLink
组件中给写死了,现在我们有一个问题,我们该怎么实现动态渲染展示的内容?
当然我们也可以通过props
传进去啊,但是我们来回顾一下NavLink
人家什么处理的?我们现在渲染MyNavLink
是不是自闭合标签啊?但是NavLink
不是自闭合的啊,人家有开始标签,结束标签,还有标签体展示内容。那么我们怎么实现呢?我们学过接收props
,但是我们是不是梗本没学过如何去接收标签体内容啊?
但是实际上呢,标签体内容也是一个特殊的props
吗,我们来改一下代码:
export default class MyNavLink extends Component { render() { const {to} = this.props; console.log(this.props); return ( <NavLink className="list-group-item" to={to}>About</NavLink> ); } } // App 组件 export default class App extends Component { render() { return ( <div> ... <div className="list-group"> <MyNavLink to="/about">About</MyNavLink> <MyNavLink to="/home">Home</MyNavLink> </div> ... </div> ); } }
我们来看,我们在App
组件中不用自闭合标签了,我们也像NavLink
一样传一个标签体内容进去,然后我们去MyNavLink
标签打印一下props
看一下:
我们可以看到控制台中输出的对象里面有一个属性叫做children
,这个属性的值就是我们的标签体内容,那么这下好了。我们改一下代码实现我们预期的效果吧:
export default class MyNavLink extends Component { render() { const {to, children} = this.props; return ( <NavLink className="list-group-item" to={to}>{children}</NavLink> ) } }
App
组件中我们之前已经做了修改了,这里就不在赘述了,我们来看MyNavLink
组件,我们从props
中接到children
然后作为NavLink
的标签体内容,然后我们来看一下效果:
这次展示就正常了,而且我们点击导航项切换也正常。但是大家有没有觉得这么写有些麻烦?我们开始标签,标签体,结束标签。这么长,那么如果我让他自闭和不写标签体的话行不行呢?我们来试一下:
export default class MyNavLink extends Component { render() { const {to, children} = this.props; return ( <NavLink className="list-group-item" to={to} children={children} /> ) } }
来看代码,这是什么意思?我们是不是直接传了children
属性?既然标签体内容默认是children
属性,那么我们直接给指定children
属性不就得了嘛,那我们来看一下效果:
展示也还是没问题,可是我们还是会觉得麻烦,因为我to
写了一个属性,children
又写了一个属性,如果我有是个属性要往里面传那还一个个去写吗?我们不是可以这么写吗:
export default class MyNavLink extends Component { render() { return ( <NavLink className="list-group-item" {...this.props} /> ) } }
这是不是props
批量传入啊?而且连解构赋值都省了。
以上便是封装MyNavLink
的主要内容。
总结
- 标签体内容是一个特殊的
props
属性 - 用批量传入
props
来减少代码冗余
Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.
Link of this article:https://work.lynchow.com/article/wrap_navlink_component/