高阶组件HOC

react中复用组件的一种姿势,基于react特性组成的一种模式
高阶组件是:参数为组件,返回值为新组件并赋予更多功能的一个函数
image.png
自定义一个随机换色高阶组件:

  1. const Rainbow = (WrappedComponent)=>{
  2. const colors =['red','blue','green','orange','yellow','pink']
  3. const randomColors = colors[Math.floor(Math.random()*6)]
  4. const className = randomcolors + '-text'
  5. return (props) => (
  6. <div className={className}>
  7. <WrappedComponent {...props}>
  8. </div>
  9. )
  10. export default Rainbow
  1. import Rainbow from '../hc/Rainbow'
  2. const Home =()=>{
  3. ...定义Home函数组件
  4. }
  5. export default Rainbow(Home) //当做函数一样调用高阶组件

Home页面每刷新一次,颜色就随机生成一次

React Router

Router有两种模式:History和Hash模式

  • 如果没有后台服务器,就用Hash模式
  • 如果有后台服务器,配置所有路径都到首页才能使用History模式(开了server就算有后台服务器)

Hash模式可以乱用,因为只是Hash值,History模式不可以乱用,需要匹配到后台设定了的路径

  1. class App extends Component{
  2. render(){
  3. return (
  4. <BrowserRouter>
  5. <Navbar/> //只控制Nav的UI展示,实际控制路由跳转渲染的是下面三个Route
  6. <Route path='/' component ={Home}/>
  7. <Route path='/about' component ={About}/>
  8. <Route path='/contact' component ={Contact}/> //子组件可以拿到路由信息
  9. </BrowserRouter>
  10. )
  11. }
  12. }

Router路由对象的三个属性

image.png
首先明确:
在父组件中 各子组件 若是通过路由进行切换渲染展示的,那么子组件可以通过props拿到父组件传来的路由对象的三个对象属性

  • history:可以追踪页面的跳转记录,里面包含各种方法
  • location:当前页面的位置信息,如pathname
  • match:设置路由参数的时候常使用该对象属性,如params

再者注意:
Navbar组件只是负责Nav导航的UI渲染展示,没有路由信息,只有各跳转子组件Route才有路由对象信息,即只要使用了路由来控制的组件,会自动继承路由给我们提供的一些对象
问题:如何才能让没有拥有路由对象信息的Navbar组件拥有 路由对象信息?针对不是路由来控制的 页面跳转
解决:使用高阶组件withRouter
export default withRouter(Navbar)

重定向

方法一:使用钩子:history对象属性的push方法(编程式的重定向)
props.history.push('/about')
image.png
方法二:V6中,使用新增的组件配合组件 or 将 移动到 属性内

  1. <Routes>
  2. <Route path="/home" element={<Home/>} />
  3. <Route path="/" element={<Navigate to="/home"/>}>
  4. <Route path="about" render={() => <Redirect to="about-us" />}
  5. </Routes>

React+axios

JSONPlaceholder 第三方接口,可提供一些用于测试的虚拟数据

请求接口需要在react的哪个生命周期中发起请求?→ 第一阶段完成挂载后请求第三方提供的数据(componentDidMount)

react生命周期大致分为:挂载阶段、更新阶段、卸载阶段
在挂载阶段:先创建constructor进行数据初始化 → 第一次渲染,调用render方法 → 执行对应的数据,进行状态更新

业务一:点击不同Tab跳转到不同post内容页面

  1. 使用Router,在路由文件添加路由跳转信息

<Route path='/:post_id' component={Post}/>

  1. 点击不同Tab,获取其路由参数进行保存,根据获取的URL参数去请求获取对应的数据,并进行渲染展示,

    创建单个Post文件,作为展示博客内容的页面 获取url路由参数:在DOM渲染的时候即componentDidMount钩子中:拿到路由对象的match对象属性 中的 params,创建变量存储params 每篇博客Tab绑定对应的链接在其title上,以便点击跳转,通过Link链接跳转,获取每个Post的id 当保存了params路由参数后,就可以拿着参数去发起axios请求

具体步骤示例如下:

  1. //链接跳转、在父布局路由中添加一个出口
  2. render(){
  3. const {posts} = this.state
  4. const postList = posts.length ? (posts.map(post => {
  5. return (
  6. <div className='post card' key ={post.id}>
  7. <Link to={'/'+post.id}>
  8. <span className='card-title'>{post.title}</span>
  9. </Link>
  10. <p>{post.body}</p>
  11. </div>
  12. )
  13. })) : ()
  14. }
  1. //获取路由参数、发起axios请求
  2. class Post extends Component{
  3. state ={
  4. post:null
  5. }
  6. componentDidMount(){
  7. let id = this.props.match.params.post_id
  8. axios.get('https://jsonplaceholder.typicode.com/posts'/ + id)
  9. .then(res => { this.setState({ post:res.data } )})
  10. }
  11. render(){
  12. const post = this.state.post ? (
  13. <div className='post'>
  14. <h4>{th is.state.post.title}</h4>
  15. <p>{this.state.post.body}</p>
  16. </div>
  17. ) : (
  18. <div className='container'>博客正在加载中...</div>
  19. )
  20. return (
  21. <div className='container'>
  22. {this.state.post}
  23. </div>
  24. )
  25. }
  26. }

Switch组件

作用:只渲染第一个匹配到的路由组件、重定向组件
V6升级为Routes组件
用法:包裹住所有Route组件即可

redux

image.png