CSS-in-JS技术
eg:代表代码对照
若文章有误,欢迎读者指出
CSS-in-JS简介
CSS-in-JS是一种技术,而不是一个具体的库实现。简单来说CSS-in-JS就是将应用的CSS样式写在JavaScript文件里面,而不是独立为一些css,scss或less之类的文件,这样你就可以在CSS中使用一些属于JS的诸如模块声明,变量定义,函数调用和条件判断等语言特性来提供灵活的可扩展的样式定义。CSS-in-JS在React社区的热度是最高的,这是因为React本身不会管用户怎么去为组件定义样式的问题,而Vue有属于框架自己的一套定义样式的方案。
styled-components 应该是CSS-in-JS最热门的一个库,通过styled-components,你可以使用ES6的标签模板字符串语法,为需要styled-Component定义一系列CSS属性,当该组件的JS代码被解析执行的时候,styled-components会动态生成一个CSS选择器,并把对应的CSS样式通过style标签的形式插入到head标签里面。动态生成的CSS选择器会有一小段哈希值来保证全局唯一性来避免样式发生冲突。
普通外链样式写法 css less sass都是这么用
import './demo.css'
1 2 3 4 5 6 7 8 9 10 11 12 13
| import './demo.css'
class StyledDemo extends Component { render() { return ( <div> <h3>StyledDemo</h3> <div className='box1'>hello world</div> </div> ) } }
|
1 2 3 4
| .box1{ background-color: pink; font-size: 18px; }
|
学习使用CSS-in-JS
用js代码来取代css样式代码,常见,样式文件后缀名应为js或者jsx
安装插件
npm i -S styled-components
定义样式,引入styled,css-in-js技术,样式写在js文件或者jsx文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import styled from 'styled-components'
export const DivStyled = styled.div` background-color: red; font-size: 20px; `
export const DivStyled2 = styled(DivStyled)` /* background-color: red; font-size: 20px; */ height: 40px; `
|
组件中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import React, { Component } from 'react'
import { DivStyled, DivStyled2 } from './demo1'
class StyledDemo extends Component { render() { return ( <div> <h3>StyledDemo</h3> <DivStyled>123</DivStyled> <DivStyled2>1234</DivStyled2> </div> ) } }
export default StyledDemo
|
设置传递属性值过来,支持变量、默认值
组件的某个变量传递给样式组件,外链的样式 css、sass、less都不支持,只要CSS-in-JS可以
样式文件
1 2 3 4 5 6 7
| import styled from 'styled-components'
export const DivStyled3 = styled.div` background-color: blue; font-size: ${props => props.font || '18px'}; //如果有参数传递过来就使用,如果没有就使用默认值 `
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { DivStyled3 } from './demo1'
class StyledDemo extends Component { state = { font: '32px' } render() { return ( <div> <h3>StyledDemo</h3> {/* 支持js组件中的变量【DivStyled3就相当于子组件,传递给样式组件中】 */} <DivStyled3 font={this.state.font}>12345</DivStyled3> </div> ) } }
|
redux的模块化
现在我们已经能够很好的进行redux的数据管理,但是有一个缺点就是所有的代码都写在一个文件中,需要按照模块化开发的规则进行对代码拆分。
目录结构

整个home页面中的reducer逻辑会合并到store中的reducer中,同时home页面的actions、reducer均依赖actionTypes的自定义规则,home调用的是actions中导出的方法
安装插件
react-redux就是redux给我们提供一些高阶组件[引入connect组件],能解决的问题是:使用它以后我们不需要在每个组件中再去手动订阅数据的更新了。
npm i -S redux react-redux
定义Provider,在程序主文件index.js文件中,定义Provider,此处类似于之前跨组件通信处的Provider一样,旨在让全局的组件共享store中的数据
index.js文件
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { Provider } from 'react-redux' import store from './store' import { HashRouter } from 'react-router-dom' import App3 from './App3'
ReactDOM.render( <Provider store={store}> <HashRouter> <App3 /> </HashRouter> </Provider>, document.getElementById('root') )
|
App3.js文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import React, { Component } from 'react' import { Switch, Route } from 'react-router-dom' import Home from './03views/home/Home.jsx' export default class App3 extends Component { render() { return ( <div> <h3>App3</h3> <Switch> <Route path="/home" component={Home} /> </Switch> </div> ) } }
|
在store文件夹中创建store.js文件,创建store并抛出store(全局共享数据)
1 2 3 4
| import { createStore } from 'redux' import reducer from './reducer' const store = createStore(reducer) export default store
|
在store目录下的reducer.js文件中合并每个页面reducer.js逻辑
1 2 3 4 5 6 7 8 9 10
| import { combineReducers } from 'redux'
import homeReducer from '../03views/home/reducer'
const reducer = combineReducers({ home: homeReducer, }) export default reducer
|
到actionTypes.js文件中定义规则
1
| export const increType = 'home/afaefafefe'
|
书写reducer逻辑【store中的reducer是负责整合,这个写在home目录下的reducer.js中】
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { increType } from './actionTypes' const defaultState = { num: 100 } const reducer = (state = defaultState, actions) => { if (actions.type === increType) { return { num: state.num + actions.incre } } return state }
export default reducer
|
书写actions.js文件与其仓库reducer.js对接
1 2 3 4 5 6 7 8 9
| import { increType } from './actionTypes'
export const increActions = (incre) => { return { type: increType, incre } }
|
引入到Home组件中使用
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
| import React, { Component } from 'react'
import { connect } from 'react-redux'
import { increActions } from './actions'
class Home extends Component { render() { return ( <div> <h4>Home</h4> <p>{this.props.mynum}</p> <button onClick={() => this.props.handleClick(1)}>+1</button> </div> ) } }
const mapStateToProps = state => ({ mynum: state.home.num }) const mapDispatchToProps = dispatch => ({ handleClick(a) { dispatch(increActions(a)) } }) export default connect(mapStateToProps, mapDispatchToProps)(Home)
|
immutable.js
Immutable.js出自Facebook,是最流行的不可变数据结构的实现之一。它实现了完全的持久化数据结构,使用结构共享。所有的更新操作都会返回新的值,但是在内部结构是共享的,来减少内存占用(和垃圾回收的失效)。
持久化数据结构:这里说的持久化是用来描述一种数据结构,指一个数据,在被修改时,仍然能够保持修改前的状态,即不可变类型。
结构共享:ImmutableJS使用先进的tries(字典树)技术实现结构共享来解决性能问题,当我们对一个Immutable对象进行操作的时候,ImmutableJS会只clone该节点以及它的祖先节点,其他保持不变,这样可以共享相同的部分,大大提高性能。
使用immutable优缺点:
优点:
- 降低mutable带来的复杂度
- 节省内存
- 历史追溯性
- 拥抱函数式编程
缺点:
- 需要重新学习api
- 资源包大小增加(源码5000行左右)
- 容易与原生对象混淆:由于api与原生不同,混用的话容易出错
安装插件
npm i -S immutable
常用Api
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
|
const map1 = Map({ a: 1, b: 2, c: 3}) const map2 = Map({ a: 1, b: 2, c: 3})
console.log(map1 === map2) console.log(map1.equals(map2))
const list1 = List([1, 2]); const list2 = list1.push(3, 4, 5);
console.log(list2.get(0));
const list1 = List([ 1, 2, 3 ]); const list2 = List([ 4, 5, 6 ]); const list3 = list2.concat(list1); console.log(list3.toArray())
const imState = fromJS({ name: 'lisi', users: ['aa', 'bb'] })
console.log(imState.get('users').get(1)) console.log(imState.getIn(['users', 0]))
const state = imState.toJS() console.log(state);
const newState = imState.set('name', 'zhangsan') const newState = imState.setIn(['name'], 'zhangsan') const newState = imState.update('count', value => value + 1) const newState = imState.updateIn(['count'], value => value + 1)
|
注意:组件中state使用的时候不建议直接把state转换成immutable对象。
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
| import React, { Component } from 'react' import immutable from 'immutable' export default class ImmuDemo extends Component {
constructor(props){ super(props) this.username = React.createRef() this.state = { arr:immutable.fromJS([ {id:1,name:'大壮'}, {id:2,name:'二翠'}, ]) } } handleClick = () => { var obj = { id: new Date().getTime(), name:this.username.current.value } this.setState({ arr:immutable.fromJS([...this.state.arr.toArray(),obj]) }) } render() { return ( <div> <h3>ImmuDemo案例</h3> <input type="text" ref={ this.username }/> <button onClick={ this.handleClick }>添加</button> <ul>{ this.state.arr.map(item=>{ return <li key={ item.get('id') }>姓名:{ item.get('name') }</li> })}</ul> </div> ) } }
|