完成详情页渲染,用到了 react-markdown 来渲染先看效果:
1 在 components 下新建 Detail.js
import React , {Component}from ‘react’;
import {Card, Avatar, Spin, Icon,Comment, Tooltip, List} from ‘antd’;
import PropTypes from ‘prop-types’;
import {connect} from ‘dva’;
import ReactMarkdown from ‘react-markdown’;
import ‘./my.css’;
class Detail extends Component{
render() {
const {Meta} = Card;
return (
<Spin spinning={this.props.loading.global}
size=’large’
tip=” 数据正在加载中 ”>
{typeof(this.props.data.author)==’object’ ? (
<Card>
<Card
type=”inner”
title={<div><Avatar src={this.props.data.author.avatar_url} />
<span style={{fontSize :26}}>{this.props.data.title}</span>
</div>}
extra={
<div>
发布于 {this.props.data.create_at} * 作者{this.props.data.author.loginname}* {this.props.data.visit_count} 次浏览 * 来自 分享
</div>
}
>
<ReactMarkdown source={this.props.data.content} />
</Card>
<Card
type=”inner”
title={this.props.data.reply_count+’ 个回复 ’}>
<List
className=”comment-list”
itemLayout=”horizontal”
dataSource={this.props.data.replies}
renderItem={item => (
<Comment
author={item.author.loginname}
avatar={item.author.avatar_url}
content={<ReactMarkdown source={item.content} />}
datetime={item.create_at}
/>
)}
/>
</Card>
</Card>
) : ”}
</Spin>
)
}
componentWillMount () {
const {par} = this.props
this.props.dispatch({type: ‘detail/find’, payload: { id:par} })
}
}
Detail.propTypes = {
id: PropTypes.string.isRequired,
};
function mapStateToProps(state) {
const {id,data} = state.detail;
return {
id,
data,
loading:state.loading
};
}
// export default ListData;
export default connect(mapStateToProps)(Detail);
用到了 antd 中的一些组件,可以自己去官网参考下怎么用。my.css 里面定义了一些样式,主要解决 markdown 渲染后里面的图片太宽,重新设置宽度。
a{
text-decoration:none;
color:#333;
}
img{
max-width: 1300px;
}
2 在 models 下创建对应的 model detail.js
import * as listService from ‘../services/list’;
export default {
namespace: ‘detail’,
state:{
id:”,
data:{}
},
effects: {
*find({payload: { id} }, {call, put}) {
const result = yield call(listService.find, { id})
yield put({
type: ‘updateData’,
payload: {
result,
id
}
})
}
},
reducers: {
‘updateData'(state, { payload: data}) {
let r = data.result.data
const {id} = data
return {…state,id,data:r}
}
},
subscriptions : {
setup({dispatch, history}) {
}
},
};
3 在 service 中添加获取详情的 api list.js
import request from ‘../utils/request’;
export function query({page,pageSize,type}) {
return request(`/api/v1/topics?page=${page}&limit=${pageSize}&tab=${type}`);
}
export function find({id}) {
return request(`/v1/topic/${id}?mdrender=false`);
}
mdrender 参数设置为 false 来获取 markdown 数据,true 为 html 数据
4 创建详情页 routes/DetailPage.js
import React from ‘react’;
import {connect} from ‘dva’;
import Header from ‘../components/Header’;
import Detail from ‘../components/Detail’;
function DetailPage(props) {
const {params} = props.match
return (
<div>
<Header keys={[‘index’]}/>
<div style={{paddingTop:20,paddingLeft:100,paddingRight:100,paddingBottom:50}}>
<Detail par={params.id}/>
</div>
</div>
);
}
DetailPage.propTypes = {
};
export default connect()(DetailPage);
使用了自己定义的 Header 和 Detail 组件。在 router.js 中邦定路由到页面:
import React from ‘react’;
import {Router, Route, Switch} from ‘dva/router’;
import IndexPage from ‘./routes/IndexPage’;
import DetailPage from ‘./routes/DetailPage’;
function RouterConfig({history}) {
return (
<Router history={history}>
<Switch>
<Route path=”/” exact component={IndexPage} />
<Route path=”/detail/:id” exact component={DetailPage} />
</Switch>
</Router>
);
}
export default RouterConfig;
使用了参数路由,在 DetailPage.js 中, 从 props.match.params 中就可以取到 id 值传给 Detail 组件
5 别忘了在 index.js 中注册 model 以及插件
import dva from ‘dva’;
import ‘./index.css’;
import createLoading from ‘dva-loading’;
// 1. Initialize
const app = dva();
// 2. Plugins
app.use(createLoading());
// 3. Model
app.model(require(‘./models/listdata’).default);
app.model(require(‘./models/detail’).default);
// 4. Router
app.router(require(‘./router’).default);
// 5. Start
app.start(‘#root’);
前面两节课忘说 dva-loading 了,需要在这里使用,才能在组件中获取 loading 属性
6 在 ListData 组件中加入路由跳转详情页
import {Link} from ‘dva/router’;
<Link to={‘/detail/’+item.id}>{item.title}</Link>
使用了 Link 来做跳转,顺带把我们的 Header 组件的跳转也给改了
<Menu.Item key=”index”>
<Link to=”/”><Icon type=”appstore” /> 首页 </Link>
</Menu.Item>
<Menu.Item key=”into”>
<Link to=”/into”><Icon type=”appstore” /> 新手入门 </Link>
</Menu.Item>
<Menu.Item key=”api”>
<Link to=”/api”><Icon type=”appstore” />API</Link>
</Menu.Item>
<Menu.Item key=”about”>
<Link to=”/about”><Icon type=”appstore” /> 关于 </Link>
</Menu.Item>
<Menu.Item key=”reg”>
<Link to=”/reg”><Icon type=”appstore” /> 注册 </Link>
</Menu.Item>
<Menu.Item key=”login”>
<Link to=”/login”><Icon type=”appstore” /> 登陆 </Link>
</Menu.Item>
大功告成看看效果
欢迎关注我的公众号 mike 啥都想搞,学习更多内容。