前端学习笔记(二十二)--styled component, immutable.js

616 阅读4分钟

开始仿某个网站。记录一下过程中的一些思考或者遇到的坑。

1. styled component

由于 css 是全局作用的,经常会有 class 名字冲突,全局污染等情况出现。
而像 styled-component 这种工具,能够写出 css-in-js 风格的代码,以组件的形式声明 CSS,让其只用在想用的地方。

1.1 属性传值

可以通过 props 往 css 里传值:

const myColor = "red";
<Header color={myColor}>
export const StyledHeader = styled.div`
  color: ${props => { return props.color }}
`
// 其实就是附加了样式的 React 组件,完全可以当普通组件用
// 因此命名也应该首字母大写

1.2 样式继承

可以通过样式继承,复用 css 代码:

export const A = styled.div`
  ...
  ...
`
export const B = styled(A)`
  /* 已经继承了 A 组件的样式,
  *  然后可以加上自己的样式,
  *  也可以重载。
  */
`

1.3 给已有组件添加样式

用的还是上面的语法,styled(<Component>):

class Header extends React.Component {
  /*各种代码*/
}

const StyledHeader = styled(Header)`
  /*各种样式*/
`

这样就给 Header 组件附加了样式并取名为 StyledHeader

2. reset.css

每个浏览器都有自己的默认样式,为了去除这些略有不同的样式,导入 reset.css ,以避免出现在不同网站上的样式不同的状况。

3. 伪元素引入图标字体

阿里的 iconfont 一般是通过 html 引入的,如果想要在伪元素里引入则需要以下格式:
除了引入 font-family 等以外,伪元素的 content 要两个转义符号。网上的各种方法都是只写一个转义符号很坑。

4. input 的伪元素看不见

这里是因为对伪元素的含义不了解导致的错误,如果给 input 加了伪元素,那其实是相当于 <input>::after</input>,这样子伪元素并不是跟在 input 后面,而是在 input 里面。而 input 是一个自闭合标签,放在里面是没有意义的。
因此如果想要在 input 后面加东西,应该定义的是 input 的父元素的伪元素,而不是 input 本身的伪元素。

5. immutable.js

在 reducer 里是不能改变 state 的,但是人是很容易犯错的,有时候没有意识到改了 state,就会出现一些比较难以发现的 bug。因此 facebook 推出了 immutable.js 迫使我们无法改变 state。
immutable.js 对象使用 get 和 set 获取和修改值,set 会返回一个全新的修改了指定值后的对象。

6. redux-immutable

如果使用 redux 自带的 combineReducer 生成一个大的 reducer,那么会造成下面这样的不协调:

state = {
  smallReducer: {/*这个是 immutable.js 创建的对象,不可变*/}
}
// 但是外面的 state是由 combineReducer 创建的,是可变的,这不好

使用 redux-immutable 提供的专门的 combineReducer ,可以让最外层的 state 也不可变。

7. immutable.js 的坑

  1. 用 fromJS 转化一个对象,会让这个对象包括里面的引用属性也变成 immutable 对象。这个好像没什么坑,不如说挺好的。但是坑在于替换的数据,如果 state 中有一个数据是列表,这个列表被转化成 immutable 对象,然后每次都要替换这个列表,但是如果用其他数据替换这个列表,这个其他数据在 set 之前也要被 fromJS 转化一下。不然就会成为: 所以 data 在传递前也需要先被转化成 immutable 对象。

8. 为什么 reducer 里要返回一个全新的数据

这里引申出了一个新的问题,在 react-redux 中是如何判断重新渲染的呢

  1. 每次 state 更新,react-redux 就会在 shouldComponentUpdate 里对 mapStateToProps 里的 state 进行浅比较
  2. 由于是浅比较,如果在 reducer 里直接修改了对象的值,浅比较依然会认为你没有改变而不渲染。因为浅比较比较的是引用的地址,前后都是同一个引用地址自然就会被认为没有改变。

9. 为什么改变了 state,却不重新渲染

就是上面的原因,因为在 reducer 直接修改 state 了。

10. immutable.js 的基本原理

immutable.js 并不是深拷贝,因为深拷贝要耗费很大性能。
immutable 使用了持久化数据结构和结构共享的概念。可以参考这篇文章
比较重要的概念就是:

  1. 改变了根节点,因此可以保证 prevState !== nextState,浅比较不相等,因此会 re-render。
  2. 同时只新生成改变的节点到根节点的这段路径,树的另外一部分依然维持着旧节点的引用。如图:

11. 如何在 mapDispatchToProps 中使用 state

并不能,但是可以使用 redux-thunk,在 actionCreators 中可以使用 getState。

export const getMyAction = () => {
  return ((dispatch, getState) => {
    dispatch( getOtherAction(getState().data) );
  })
}