开始仿某个网站。记录一下过程中的一些思考或者遇到的坑。
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 的坑
- 用 fromJS 转化一个对象,会让这个对象包括里面的引用属性也变成 immutable 对象。这个好像没什么坑,不如说挺好的。但是坑在于替换的数据,如果 state 中有一个数据是列表,这个列表被转化成 immutable 对象,然后每次都要替换这个列表,但是如果用其他数据替换这个列表,这个其他数据在 set 之前也要被 fromJS 转化一下。不然就会成为: 所以 data 在传递前也需要先被转化成 immutable 对象。
8. 为什么 reducer 里要返回一个全新的数据
这里引申出了一个新的问题,在 react-redux 中是如何判断重新渲染的呢?
- 每次 state 更新,react-redux 就会在 shouldComponentUpdate 里对 mapStateToProps 里的 state 进行浅比较。
- 由于是浅比较,如果在 reducer 里直接修改了对象的值,浅比较依然会认为你没有改变而不渲染。因为浅比较比较的是引用的地址,前后都是同一个引用地址自然就会被认为没有改变。
9. 为什么改变了 state,却不重新渲染
就是上面的原因,因为在 reducer 直接修改 state 了。
10. immutable.js 的基本原理
immutable.js 并不是深拷贝,因为深拷贝要耗费很大性能。
immutable 使用了持久化数据结构和结构共享的概念。可以参考这篇文章。
比较重要的概念就是:
- 改变了根节点,因此可以保证 prevState !== nextState,浅比较不相等,因此会 re-render。
- 同时只新生成改变的节点到根节点的这段路径,树的另外一部分依然维持着旧节点的引用。如图:
11. 如何在 mapDispatchToProps 中使用 state
并不能,但是可以使用 redux-thunk,在 actionCreators 中可以使用 getState。
export const getMyAction = () => {
return ((dispatch, getState) => {
dispatch( getOtherAction(getState().data) );
})
}