(16)详情页开发——② 动态路由(页面路由参数的传递) | React.js 项目实战:PC 端“简书”开发

转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥"前端一万小时"两大明星专栏------"从零基础到轻松就业"、"前端面试刷题",已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

1 需求

本篇我们主要解决上一篇《详情页开发------① "布局"和"数据管理"》末尾的遗留问题。

❓需求:当点击 home 页的数据项(文章列表)时,把点击项的 id 带给"详情页"。

✔️怎么做:动态路由。

2 动态路由

1️⃣打开 home 目录下 components 文件夹里的 Content.js 文件:

jsx 复制代码
import React, {Component} from "react";

import {Link} from "react-router-dom";

import {
  Item,
  Cover,
  Details,
  Title,
  Foot,
  LoadMore
} from "../style";

import { connect } from "react-redux";

import {actionCreators} from "../store";  

class Content extends Component {
  render() {
    
    return(
      <div>
        {
          this.props.articleList.map((item, index) => {
            return (
              <Item key={index}>
                <Cover>
              		{/* 
                   1️⃣-③:❗️同理,由于点击图片也会跳转至相应的"详情页",
                   故这里的"路径"也要变!
                    */}
                  <Link to={"/detail/" + item.get("id")}><img src={item.get("imgUrl")} alt="" /></Link>
                </Cover>

                <Details>
                  
                  {/*
                   ❗️❗️❗️1️⃣-①:在跳转至详情页时,我们可以将其 id 也带上;
                  <Link to="/detail">
                    */}
									<Link to={"/detail/" + item.get("id")}> {/* ❗️❗️❗️1️⃣-②:注意写法~ */}
                    
                    <Title>
                      {item.get("title")}
                    </Title>
                  </Link>
                  <p>
                    {item.get("desc")}
                  </p>

                  <Foot>
                    <Link to="/"><span className="username">{item.get("author")}</span></Link>
                    <span className="iconfont icon-comment">&#xe602;</span><span>{item.get("discuss")}</span>
                    <span className="iconfont icon-heart">&#xe8f4;</span><span>{item.get("love")}</span>
                    <span className="iconfont icon-money">&#xe607;</span><span>{item.get("money")}</span>
                  </Foot>
                </Details>
              </Item>
            )
          })
        } 
      
        <LoadMore
          onClick={() => this.props.getMoreList(this.props.page)}
        >
          加载更多
        </LoadMore>
      </div>
    )
  }
}


const mapStateToProps = (state) => {  
  return { 
    articleList: state.getIn(["home", "articleList"]),
    
    page: state.getIn(["home", "articlePage"])
  }
}


const mapDispatchToProps = (dispatch) => { 
  return {
    getMoreList(page) { 
      const action = actionCreators.getMoreList(page);  
      dispatch(action) 
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Content);  

返回页面查看(当点击 home 页的文章列表某项时,跳转至"详情页",并传递给"详情页"了一个 id ------1):

❌但"详情页"变为空白,不显示了!为什么呢?

2️⃣进入 src 目录下的 App.js 文件:

jsx 复制代码
import React, { Component } from "react";

import {GlobalStyle} from "./style";

import {GlobalIconStyle} from "./statics/iconfont/iconfont";

import {BrowserRouter, Route} from "react-router-dom";

import Header from "./common/header";

import Home from "./pages/home";
import Detail from "./pages/detail";

import { Provider } from "react-redux";

import store from "./store";

class App extends Component  {  
  render() {  
    return (
      <div>
        <GlobalStyle />
        <GlobalIconStyle />
 
        <Provider store={store}>             
          <BrowserRouter>
            <div>
              <Header />
      
              <Route path="/" exact component={Home}></Route>  {/*❗️*/}
                  
              {/*
               ❗️2️⃣-①:由于路径要"完全"匹配 /detail 时,才会进入 Detail 组件。
               但 /detail/1 和 /detail 不完全匹配,所以上边会出现空白页面。
               可以怎么修改呢?
              <Route path="/detail" exact component={Detail}></Route>
                */}
              
              {/*
               2️⃣-②:可以改写为 /detail/:id,给路径传递一个额外的"参数"id;
                */}
              <Route path="/detail/:id" exact component={Detail}></Route>
            </div>
          </BrowserRouter>
        </Provider>

      </div>
    );
  }
}

export default App; 

返回页面查看(详情页正常显示,且有了 id 为 1 这个"参数"):

❓既然"详情页"有了 1 这个"参数",Detail 组件应该怎样去拿到这个"参数"呢?

3️⃣打开 detail 目录下的 index.js 文件:

jsx 复制代码
import React, {Component} from "react";

import {
  DetailWrapper,
  Header,
  Content
} from "./style.js";

import {connect} from "react-redux";

import {actionCreators} from "./store"; 

class Detail extends Component {
  
  render() {

    // ❗️❗️❗️3️⃣-①:在控制台打印一下 this.props 有些什么东西?
    console.log(this.props);

    return(
      <DetailWrapper>
        <Header>{this.props.title}</Header>
     
        <Content 
          dangerouslySetInnerHTML={{__html: this.props.content}}
        />

      </DetailWrapper>
    )
  }
  
  componentDidMount() { 
    this.props.getDetail();
  }
}

const mapStateToProps = (state) => { 
  
  return {  
    title: state.getIn(["detail", "title"]),  
    content: state.getIn(["detail", "content"]) 
  }

}


const mapDispatchToProps = (dispatch) => {  
  return {
    getDetail() {  
      const action = actionCreators.getDetailData();
      
      dispatch(action)
    
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Detail);  

3️⃣-②:在 home 页下随便点开一篇文章(我点击的是第 2 篇文章 ),并查看控制台。会打印出一个"对象",点开这个对象,它下边有一个 match 属性,点开 matchparams 下就会有第 2 篇文章id

✔️因此,"Detail 组件"可以通过 this.props.match.params.id 来准确地获取到上一个页面传递过来的 id 值。

4️⃣返回 detail 目录下的 index.js 文件:

jsx 复制代码
import React, {Component} from "react";

import {
  DetailWrapper,
  Header,
  Content
} from "./style.js";

import {connect} from "react-redux";

import {actionCreators} from "./store"; 

class Detail extends Component {
  
  render() {
    return(
      <DetailWrapper>
        <Header>{this.props.title}</Header>
     
        <Content 
          dangerouslySetInnerHTML={{__html: this.props.content}}
        />

      </DetailWrapper>
    )
  }
  
  /*
  ❗️❗️❗️4️⃣-①:页面挂载完成,去异步获取详情页"数据"时,
  给这个"异步函数"传递一个"上一页传递过来的 id 值";
   */
  componentDidMount() {  
    this.props.getDetail(this.props.match.params.id); // ❗️❗️❗️
  }
}

const mapStateToProps = (state) => { 
  
  return {  
    title: state.getIn(["detail", "title"]),  
    content: state.getIn(["detail", "content"]) 
  }

}


const mapDispatchToProps = (dispatch) => {  
  return {
    getDetail(id) { /*
    								4️⃣-②:相应地,这里会拿到一个"参数"id;
                     */
      const action = actionCreators.getDetailData(id); /*
      																								 4️⃣-③:在调用 actionCreators 
      																								 时,我把这个 id 传给它;
                                                        */
      
      dispatch(action)
    
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Detail);  

4️⃣-④:打开 detail 目录下 store 文件夹中的 actionCreators.js 文件;

javascript 复制代码
import axios from "axios";

import {CHANGE_DETAIL_DATA_ACTION} from "./actionTypes";

import {fromJS} from "immutable";


const changeDetailDataAction = (result) => ({
  type: CHANGE_DETAIL_DATA_ACTION,

  title: fromJS(result.title),
  content: fromJS(result.content)
})


export const getDetailData = (id) => { // ❗️4️⃣-⑤:接收到这个 id;
  
  return(dispatch) => {
    
    /*
    ❗️❗️❗️4️⃣-⑥:然后在请求"接口"时,我就可以把这个 id 传给后端;
    axios.get("/api/detailData.json")
     */
    axios.get("/api/detailData.json?id=" + id) // ❗️❗️❗️
      .then((res) => {
        const result = res.data.data;
      
        const action = changeDetailDataAction(result);
      
        dispatch(action); 
      })
      .catch(() => {alert("error")})
  }
}

返回页面查看(我在 home 页点击的任意文章,其"数据请求"的路径上都会带有各自的 id 参数。如此一来,后端就可以根据这些不同的 id 为我们返回不同的内容 ):

下一篇,我们进入"登录页"的编码,不难,但包含的知识点挺多。

祝好,qdywxs ♥ you!

相关推荐
轻口味1 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王1 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀2 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪2 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef4 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6414 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻5 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云5 小时前
npm淘宝镜像
前端·npm·node.js