styled-components 管理样式
combineReducer对数据拆分管理
Immutable.js来管理store中的数据
使用redux-immutable统一数据格式
Redux-thunk发送ajax + immutable.js处理时要注意的点
结构赋值- -简化代码
styled-components
在一个js中引入一个css文件会对这个文件中的所有组件的样式生效,这就可能造成组件之间样式相互的影响,我们希望的是组件之间是相互独立的没有意外的耦合关系,为了解决这个问题,我们使用styled-components
使用步骤:
- 将css文件修改成js文件,引入这个js文件
- 在style.js定义全局样式,使用createGlobalStyle来生命全局样式,这里我们reset css来统一的浏览器样式
全局样式的定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
import { createGlobalStyle } from 'styled-components'; export const GlobalStyle = createGlobalStyle` html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } `; |
全局样式的使用app.js,这个是挂载到root下的那个app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import React, { Component,Fragment } from 'react'; import Header from './common/header/index.js' import {GlobalStyle} from './style' class App extends Component { render() { return ( <Fragment> <GlobalStyle/> <Header/> </Fragment> ); } } export default App; |
指定元素的样式,实际上是创建一个带样式的组件
1 2 3 4 5 6 |
import styled from 'styled-components'; export const HeaderWrapper = styled.div` height:56px; background:red; `; |
然后直接使用<Header />即可
使用图片链接
常规的再css使用图片是url(../../xxxx,png);
但是由于webpack打包的时候会把这个url解析成字符串,这样就找不到资源了,import这个资源,然后用多行文本嵌变量的语法${xxx},
这里还是用attrs,可以将便签的属性href=’/’放在这里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import styled from 'styled-components'; import logoPic from '../../statics/logo.png'; export const HeaderWrapper = styled.div` position: relative; height: 56px; border-bottom: 1px solid #f0f0f0 `; export const Logo = styled.a.attrs({ href: '/' })` position: absolute; top: 0; left: 0; display: block; width: 100px; height: 56px; background:url(${logoPic}); background-size:contain `; |
一行css布局nav
JSX
1 2 3 4 5 6 7 |
<Nav> <NavItem className='left active'>首页</NavItem> <NavItem className='left'>下载App</NavItem> <NavItem className='right'>登录</NavItem> <NavItem className='right'>Aa</NavItem> <NavSearch></NavSearch> </Nav> |
CSS 这里使用了 &.class的语法,就是设置一个NavItem标签共有的样式然后针对该标签的每个不同class设定不同的样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
export const NavItem = styled.div` line-height: 56px; font-size: 17px; padding:0 15px; color: #333; &.left{ float: left; } &.right{ float: right; color: #969696; } &.active{ color:#ea6f5a } `; |
&::修改组件下placehoder的颜色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
export const NavSearch = styled.input.attrs({ placeholder: '搜索' })` width: 160px; height: 38px; padding: 0 20px; box-sizing: border-box; border: none; outline: none; border-radius: 19px; background: #eee; margin-top: 9px; margin-left:20px; font-size: 14px; &::placehoder{ color:#999 } `; |
combineReducer对数据拆分管理
reducer.js中之前我们写了很多的逻辑,这样很不方便管理,之前说过reducer相当于图书馆的笔记本,我们需要对其进行拆分,拆分的思路就是每个组件给它一个小的笔记本,总体有一个大的笔记本记录每一个小的笔记本。
Header组件的reducer.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
const defaultState = { focused: false }; export default (state = defaultState, action)=>{ if(action.type === 'search_focus'){ const newState = JSON.parse(JSON.stringify(state)); newState.focused = true; return newState; } if(action.type === 'search_blur'){ const newState = JSON.parse(JSON.stringify(state)); newState.focused = false; return newState; } return state; } |
为了减少路径长度,在header的reducer的统计目录使用一个index.js把它导出出去
1 2 3 |
import reducer from './reducer'; export { reducer } |
总的reducer.js取一个别名接收header的reducer
1 2 3 4 5 6 7 8 |
import {combineReducers} from 'redux'; import {reducer as headerReducer} from '../common/header/store'; const reducer = combineReducers({ header: headerReducer }); export default reducer; |
Immutable.js来管理store中的数据
之前我们说过,reducer是不能沟修改state的值的,我们需要对这个概念实时的警惕不要做错,但是有时候还是会不小心改到state出现异常并且难以调试,Immutable.js是一个第三方模块,是facebook团队历时三年开发的,可以生成一个immutable的对象,是一个不可改变的对象。所以,可如果我们让state是一个immutable对象,也就是不可改变的,那么就不用担心会出问题了。
引入immutable.js(要先yarn add安装)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import * as constants from './constants'; import { fromJS } from 'immutable'; const defaultState = fromJS({ focused: false }); export default (state = defaultState, action)=>{ if(action.type === constants.SEARCH_FOCUS){ // immutable对象的set方法,会结合之前immutable对象的值和设置的值,返回一个全新的对象 return state.set('focused',true) } // 原来的方式 要按上面的方式进行替换 if(action.type === constants.SEARCH_BLUR){ const newState = JSON.parse(JSON.stringify(state)); newState.focused = false; return newState; } return state; } |
使用,注意,immutable的数据是不可以使用类似focused: state.header.focused的语法来获取,要使用.get方法才能获取
1 |
focused: state.header.get('focused') |
使用redux-immutable统一数据格式
之前我们在调用focued这个immutable对象的使用了.get方法
1 2 3 4 5 |
const mapStateToProps = (state) => { return { focused: state.header.get('focused') } }; |
但是这样是不太好的,因为前面是按照js对象获取,后面是按immutable对象的方法来获取,这样是不统一的.redux-immutable就解决了这样的问题。使用很简单,之前我们的combineReducers这个方法是从redux里来的
1 2 3 4 5 6 7 8 |
import {combineReducers} from 'redux'; import {reducer as headerReducer} from '../common/header/store'; const reducer = combineReducers({ header: headerReducer }); export default reducer; |
现在我们从redux-immutable中加载这个方法,它也提供了一个combineReducers函数,这样我们就让state也变成了一个immutable对象,然后就可以这样获取
1 2 3 4 5 |
const mapStateToProps = (state) => { return { focused: state.get('header').get('focused') } }; |
我们也可以使用immutable对象提供的getIn方法,这个方法接收一个数组,代表从state里面取header里面focus的值,与上面的写法效果是完全一样的,推荐下面这个写法。
1 2 3 4 5 |
const mapStateToProps = (state) => { return { focused: state.getIn(['header','focus']) } }; |
immutable对象还有很多其他 的API,可以参考这里https://facebook.github.io/immutable-js/
Redux-thunk发送ajax + immutable.js处理时要注意的点
在之前的文章中提到过,使用redux-thunk可以使action返回一个函数给redux,因此我们就可以在这个函数中进行ajax的请求拿到数据,如下
actionCreator.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import * as constants from './constants'; import axios from 'axios'; import {fromJS} from 'immutable'; export const searchFocus = () => ({ type: constants.SEARCH_FOCUS }); export const searchBlue = () => ({ type: constants.SEARCH_BLUR }); const changeList = (data) => ({ // 由于之后再reducer中的数据是immutable类型,因此在这里将接口的数据编程immutable的类型 type: constants.CHANGE_LIST, data: fromJS(data) }); export const getList = () => { return (dispatch) => { axios.get('/api/headerList.json').then((res)=>{ const data = res.data; dispatch(changeList(data.data)); }).catch(()=>{ console.log("error"); }) } }; |
- 需要注意的是,这里我们会将通过dsipatch方法交给reducer,而在reducer中由于我们使用了immutable.js,因此state其实是一个immutable对象,而我们如果按照常规的方法直接将接口的数据给reducer的进行处理的话,就会导致我们将一个非immutable对象的值赋给了immutable的state,这肯定是有问题的,由于我们都是在actionCreator中处理逻辑,因此我们直接在actionCreator中,创建action的时候直接使用immutable提供的fromJS将data转换成immutable类型之后再交给reducer来统一类型。
- 异步处理逻辑全部放在actionCreator处理
reducer.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import * as constants from './constants'; import { fromJS } from 'immutable'; const defaultState = fromJS({ focused: false, list:[] }); export default (state = defaultState, action)=>{ if(action.type === constants.SEARCH_FOCUS){ // immutable对象的set方法,会结合之前immutable对象的值和设置的值,返回一个全新的对象 return state.set('focused',true) } if(action.type === constants.SEARCH_BLUR){ return state.set('focused',false) } if(action.type === constants.CHANGE_LIST){ return state.set('list',action.data); } return state; } |
结构赋值
在之前的代码中我们使用了很多this.props.xxx来获取变量,其实我们可以使用结构赋值来进行代码的优化从而简化这些变量的表达方式。
1 |
const {focused,list } =this.props; |
这样我们就可以直接使用focused和list则两个变量了,除了可以对值进行这样的操作也可以对方方法使用。