src/pages/detail/
store文件夹:actionCreator.js / constants.js /index.js / reducer.js
index.js
style.js
style.js
import styled from 'styled-components';
export const DetailWrapper = styled.div`
overflow:hidden;
width:620px;
margin:0 auto;
padding-bottom:100px;
`;
export const Header = styled.div`
margin:50px 0 20px 0;
line-height:44px;
font-size:34px;
color:#333;
font-weight:bold;
`;
export const Content = styled.div`
color:#2f2f2f;
img {//img标签
width:100%;
}
p{ //P标签
margin:25px 0;
font-size:16px;
line-height:30px;
}
`;
import React,{ Component }from 'reat';
import { DetailWrapper,Header }from './style';
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}} />
//{this.props.content}发现展示的仅仅是一个字符串 为了显示成标签我们需要dangerouslySetInnerHTML 写完以后把此行删掉
</DetailWrapper>
)
}
componentDidMount(){
this.props.getDetail(this.props.match.params.id);
}
}
const mapStateToProps =(state) => ({
title:state.getIn(['detail','title']),
content:state.getIn(['detail','content'])
}); //({})返回一个对象
const mapDispatchToProps= (dispatch) => ({
getDetail(id){
dispatch(actionCreators.getDetail(id));
}
})
export default connect(mapStateToProps,mapDispatchToProps)(Detail);
store/reducer.js
import { fromJS }from 'immutable';
import * as constants from './constants';
const defaultState = fromJS({
title:''
content:‘’
});
export default (state = defaultState ,action)=> {
switch(action.type){
case constants.CHANGE_DETAIL:
return state.merge({
title:action.title
content:action.content
})
default:
return state;
}
}
index.js
import reducer from './reducer';
import * as actionCreators from './actionCreators';
import * as constants from './constants';
export { reducer,actionCreators,constants };
“<img src=''><p><b></b></p><p></p>”//形成字符串,中间没有空格,用单引号包裹
//复制粘贴到content
/api/detail.json
{
"success":true,
"data":{
"title":"标题"
"content":"
"
}
}
constants.js
export const CHANGE_DETAIL ='detail/CHANGE_DETAIL';
actionCreators.js
import axios from 'axios';
import * as constants from './constants';
const changeDetail =(title,content) => ({
type:constants.CHANGE_DETAIL,
title,
content
})
export const getDetail =(id) => {
return (dispatch)=>{
axios.get('/api/detail.json?id=' + id).then((res) => {
const result =res.data.data;
dispatch(changeDetail(result.title,result.content));
})
}
}
控制台里Network的XHR里显示的是接口里的数据
动态路由:
第一种:
这个id我们从this.props返回的对象里
在match.params.id
<link key={index} to={'/detail/' +item.get('id')}>
App.js
<Route path='/detail/:id' exact component={...}>
第二种:
<link key={index} to={'/detail?id=' +item.get('id')}>
App.js
<Route path='/detail' exact component={...}>
但是这种this.props.match.params里没有id了
在location.search里 解析一下 比较麻烦 建议用第一种
异步组件
打开Network里的JS,发现各个页面点击只加载一个bundle.js,如果这个js文件很大会导致时间很长,此时我们需要点击一个页面只加载那个页面的js,需要异步组件
react-loadable github
detail里创建loadable.js
import Loadable from 'react-loadable';
import React from 'react';//使用JSX必须引入
const LoadableComponent =loadable({
loader:() => import ('./'),//import这里指异步加载
loading(){
return <div>正在加载</div>
}//加载页面 显示临时的
});
export default () => <loadableComponent />
App.js
这样引用就可以让它成为异步组件
import Detail from './pages/detail/loadable.js';
但是这样组件index.js里获取不到路由里的信息了 this.props.match.param.id就找不到了 也没有params
如何解决?
import { withRouter } from 'react-router-dom';
导出那一行改为 connect(...,...)(withRouter(Detail));
项目上线流程
XAMPP软件:
后端开发目录在htdocs里
api文件夹
然后我们在浏览器里可以找到这些接口
localhost/api/…
然后我们在简书(你的前端文件)目录下运行npm run build
然后发现多了build的文件夹 这些就是上线需要的文件
把build里的文件全部放到htdocs里 完成了上线