React 仿简书项目实战
项目源码
github.com/astak16/act…
项目结构
src/common; // 公共组件src/pages; // 页面
src/static; // 静态资源
src/store; // 主 store
App.js; // 根组件
index.css; // 样式
index.js; // 入口文件
重置 css
搜索reset.css,复制过来
styled-components
css文件一旦在一个文件中被引入,会在全局中生效
这样写css会有些问题,当页面中有多个组件时,样式存在被覆盖的风险
我们希望在写样式的时候,每个组件的样式是独立的,不会互相的影响
使用
将
index.css重命名为style.js在
index.js引入style.jsimport"style.js";style.jsimport { injectGlobal } from"styled-components";injectGlobal`
body{
padding: 10px
}
`;
在组件中使用
组件声明
// Header/style.jsimport styled from"styled-components";
exportconst HeaderWrapper = styled.div`
height: 56px;
`;
// Header/index.js
import { HeaderWrapper } from"./style";
classHeaderextendsComponent{
render() {
return<HeaderWrapper></HeaderWrapper>;
}
}
图片使用
在style.js中使用背景图片的话,直接使用background: url('/images/logo.png')是没有效果的,因为webpack在打包的时候,不知道工程目录是啥样的,它会把路径当成字符串
需要这样写
import logoPic from"/images/logo.png";exportconst Logo = style.a`
background: url(${logoPic})
`;
设置属性
import logoPic from"/images/logo.png";exportconst Logo = style.a.attr({
href: "/",
})`
background: url(${logoPic})
`;
参数传递
组件中要传递不同的参数进来,styled提供了函数功能
<RecommendItem key='1' imgURL='/images/1.png'>1</RecommendItem><RecommendItem key='2' imgURL='/images/2.png'>1</RecommendItem>
// style.js
export const RecommendItem = styled.div`
width: 280px;
height: 50px;
background: url(${props => props.imgURL});
background-size: contain;
`
immutable.js
在reducer中,state的数据是不希望被改变的,在写项目的时候,很容易在不知不觉中把state给改了,从而造成异常。
immutable.js可以帮助解决问题,它会生成一个immutable对象,这个对象是不可被改变的。
immutable提供了fromJS的方法,可以把js对象转换成immutable对象
const a = fromJS({ age: 18 });immutable提供了get和getIn两种方法来读取数据
const a = fromJS({age: 18
feature: {
height: 180
}
})
const age = a.get('age')
const height = a.getIn(['feature', 'height'])
// 或者
const height = a.get('feature').get('height')
immutable提供了set和merge两种方法来设置数据。
immutable对象的set方法,会结合之前的immutable对象的值,和设置的值,返回一个全新的对象。它并不会去改之前的immutable数据。
const a = fromJS({age: 18,
name: "uccs",
});
a.set("age", 19).set("name", "tiantain");
// 或者
a.merge({
age: 1,
name: "tiantian",
});
当最外面使用immutable对象时,内部的Object类型的数据也会变成immutable类型,所以在使用set设置时,先要把普通对象变成immutable对象才行。
const a = fromJS({list: [], // 这个 list 也是 immutable 数组
});
const data = [1, 2, 3];
a.set("list", fromJS(data));
immutable.js提供了toJS方法,是为了将immutable对象转换成js对象
const a = fromJS({list: [1, 2, 3],
});
const b = a.toJS();
b[1];
redux-thunk
redux-thunk的作用是可以在action中写函数
redux
首页需要安装redux和react-redux
react-redux是方便在react中使用redux
redux的使用可以看:redux 学习笔记
store/index.js
// store/index.jsimport { createStore, applyMiddleware, compose } from"redux";
import thunk from"redux-thunk";
import reducer from"./reducer";
const store = createStore(reducer, compose(applyMiddleware(thunk))); // 在 store 中使用 redux-thunk
exportdefault store;
store/reducer.js
// 主 store/reducer.jsimport { combineReducers } from"redux-immutable";
import { headerReducer } from"../common/header/store";
exportdefault combineReducers({
header: headerReducer,
});
// 分 header/store/reducer.js
import { Search_Focus } from"./actionType";
import { fromJS } from"immutable";
const defaultState = fromJS({
focused: false, // 默认数据
});
exportdefault (state = defaultState, action) => {
switch (action.type) {
case Search_Focus:
return state.set("focused", action.data);
default:
return state;
}
};
redux-immutable提供了一个combineReducers方法,这个方法用来组合各个拆分出来的reducer。
header/store/actionCreators.js
// header/store/actionCreators.jsimport {Search_Focus} from'./actionType'
const searchFocus = (data) => {
type: Search_Focus,
data
}
exportconst getList = async () => {
return(dispatch) => {
const res = await axios.get('api/header.json')
dispatch(searchFocus(res.data))
}
}
header/store/actionType.js
// header/store/actionType.jsexportconst Search_Focus = "header/search_focus";
App.js
// App.jsimport { Provider } from"react-redux";
import store from"./store";
<Providerstore={store}>
<BrowserRouter>
<div>
<Header />
</div>
</BrowserRouter>
</Provider>;
react-redux有一个核心组件Provider,这个组件有一个store属性,将我们定义的store传给它,这样Provider里面所有组件都有能力去使用store中的数据了
组件连接 store
Provider把store提供给了各组件,但是组件想使用store中的数据,还要做连接
import { connect } from"react-redux";classHeaderextendsReact.Component{}
exportdefault connect()(Header);
react-redux提供了connect方法,connect就是帮助组件和store建立连接的。
connect接收两个参数:mapStateToProps和mapDispatchToProps
import { actionCreators } from"./store/actionCreators";const mapStateToProps = (state) => {
return {
focused: state.getIn(["header", "focused"]),
};
};
const mapDispatchToProps = (dispatch) => {
return {
handleInputFocus() {
dispatch(actionCreators.getList());
},
};
};
exportdefault connect(mapStateToProps, mapDispatchToProps)(Header);
组件中使用this.props.focused
react-router-dom
Route
render方法可以渲染一个东西exact完全匹配路径exact为false时,/和/detail都能匹配上
component渲染组件
import { BrowserRouter, Route } from"react-router-dom";import Home from"./pages/home";
import Detail from"./pages/detail/loadable";
functionApp() {
return (
<Provider store={store}>
<BrowserRouter>
<div>
<Route path="/" exact component={Home} />
<Route path="/detail/:id" exact component={Detail} />
</div>
</BrowserRouter>
</Provider>
);
}
export default App;
动画
换一换旁边有个icon,每次点击的时候,这个icon需要转动起来。
每次点击的时候只要改变icon的trannform: rotate() 的值就可以了。每次增加 360°
通过ref可以获取到react渲染出来的真实节点。
<SearchInfoSwitch onClick={() => handleChangePage(this.spinIcon)}><i className='iconfont spin'
ref={icon => this.spinIcon = icon}
></i>
换一批</SearchInfoSwitch>
handleChangePage(spin) {
let originAngle = spin.style.transform.replace(/[^0-9]/ig, '')
if (originAngle)
originAngle = parseInt(originAngle, 10)
else
originAngle = 0
spin.style.transform = `rotate(${originAngle + 360}deg)`
}
其他
用
Link代替a做跳转,可以做到按需加载PureComponent组件等价于Component+shouldComponentUpdatedangerouslySetInnerHTML={{__html: '<div>文本</div>'}}可以渲染HTML内容<Route path='/detail/:id'/>路由参数获取this.props.match.params.id异步组件
redux-immutable,使用异步组件时需要用withRouter,export default connect(mapState, mapDispatch)(withRouter(Detail));// detail/loadable.jsimport React from"react";
import Loadable from"react-loadable";
const LoadableComponent = Loadable({
loader: () =>import("./"),
loading() {
return<div>正在加载</div>;
},
});
exportdefault () => <LoadableComponent />;
// App.js
import Detail from "./pages/detail/loadable";
总结
路由

项目技术栈:
react-router:路由react-redux:数据挂你工具react-loadable: 按需加载react-transition-group:动画redux-immutable:将state变成immutable对象redux-thunk:可以在action中使用函数styled-components:局部样式axios:ajax请求
以上是 React 仿简书项目实战 的全部内容, 来源链接: utcz.com/a/36364.html
