Table of Contents
之前看完了react官网的教程,写了一个react版本的todo。之后想写一个react版本的poem网站,主要是为了熟悉react和使用react-router。但在查了一圈资料后发现有点难以下手,所以就找了这么一套视频(React16.4 开发简书项目 从零基础入门到实战)全面学习一下。
git地址:https://github.com/tonyzhou1890/react-jianshu
学习内容
- creat-react-app
- 组件化思维
- JSX
- 开发调试工具
- 虚拟DOM
- 生命周期
- React-transition-group
- Redux
- Antd
- UI, 容器组件
- 无状态组件
- redux-thunk
- redux-saga
- Styled-components
- Immutable.js
- redux-immutable
- axios
- react-router
2. React 特点
- 声明式开发
- 可以与其他框架并存
- 组件化
- 单项数据流
- 视图层框架
- 函数式编程
JSX语法
- JSX中自定义标签(组件)需要采用“大骆驼拼写法”。
- 不想显示外层包裹元素可以使用Fragment代替。
- 事件名要用“小骆驼拼写法”。
- 注释:
<div>
{/*注释*/}
</div>
// 或者
<div>
{
// 注释
}
</div>
- 不对标签进行转译:dangerouslySetInnerHTML={{__html: content}}
- 属性映射
| html | jsx |
|---|---|
| class | className |
| for | htmlFor |
数据
- 要改变state里的数据需要调用this.setState方法。
作用域
- 组件内部的方法需要绑定组件作用域。
setState
- setState 可以采用对象写法,但现在不推荐了
this.setState({
item: content
})
- setState 可以采用函数式写法,目前推荐写法
this.setState(() => ({ item: content }))
- setState 采用函数式写法可以提高性能,但是是异步的,如果是获取事件对象的值,要如下处理
handleInputChange(e) {
const value = e.target.value
this.setState(() => ({ inputValue: value }))
}
props
propTypes
- 使用:
import PropTypes from 'prop-types'
……
Component.propTypes = {
a: PropTypes.string.isRequired,
a: PropTypes.func
}
- 多种检测类型:string、func、string……
- 是否必须:isRequired
defaultProps
- 为 props 提供默认值
Component.defaultProps = {
a: 'hello world'
}
ref
- React16 推荐的 ref 参数是一个函数。这个函数的默认参数是 ref 绑定的元素。
- 并不推荐使用 ref。在面向数据编程的思想中,尽量不要直接操作 DOM。
- 在 setState 操作后获取元素的操作会与预期不一样。因为 setState 是异步操作,获取元素时 setState 未完成。解决方法是:setState 的第二个参数是一个回调函数,在这个回调函数里操作 DOM。
虚拟DOM
- 原理:通过 js 对象模拟真实 DOM,当数据发生变化,再生成新的虚拟 DOM,对比旧的虚拟 DOM 和新的虚拟 DOM,收集两者的差异,更新真实的 DOM。因为 js 比 DOM 快很多,所以虚拟 DOM 可以极大地提升性能。
- react diff 算法采用的是同层对比。如果同层发生变化,则子级全部替换。这会消耗性能,但这种 diff 算法简单,节省了 diff 的性能消耗。
声明周期
- 定义:生命周期函数指在某一个时期组件会自动调用执行的函数。

- componentWillMount: 在组件即将被挂载到页面的时刻自动执行。
- componentDidMount: 组件被挂载到页面后自动执行。
- componentWillReceiveProps: 当一个组件从父组件接受了参数,当父组件 render 函数被重新执行,子组件的这个生命周期函数就会被执行。即子组件第一次存在于父组件中不会执行,只有之前已经存在于父组件中才会执行。这个组件会接受两个参数:nextProps、nextState。
- shouldComponentUpdate: 组件被更新之前自动执行。这个声明周期函数需要返回一个布尔值,表明是否需要更新组件。
- componentWillUpdate: 组件被更新之前自动执行。
- componentDidUpdate: 组件更新完成后自动执行。
- componentWillUnmount: 当组件即将被从页面中卸载时自动执行。
css动画
- animation 保留最后一帧的状态需要传递第四个参数为 forwards
.hide {
animation: hide-item 1s ease-in forwards;
}
@keyframes hide-item {
0% {
opacity: 1;
color: red;
}
50% {
opacity: 0.5;
color: green;
}
100% {
opacity: 0;
color: blue;
}
}
- react-transition-group 包可以提供动画的简便实现。
Redux
- Redux = Reducer + Flux

- reducer 可以接受 state, 但是绝不能修改 state
- 要将 store 里数据的变化应用到组件,需要订阅。并且,处理函数要在订阅之前绑定作用域,否则会报错。
class TodoList extends Component {
constructor(props) {
super(props)
this.state = store.getState()
this.handleStoreChange = this.handleStoreChange.bind(this)
store.subscribe(this.handleStoreChange)
}
handleStoreChange() {
this.setState(store.getState())
}
……
}
- action 的 type 可以统一管理——例如写入一个 actionTypes.js 的文件,避免拼写不一致出错以及方便错误排查。
- 对于 action 也可以统一管理,将所有 action 写入一个文件。
- 注意项目:
- store 是唯一的:项目中只有一个 store
- 只有 store 能改变自己的内容
- Reducer 必须是一个纯函数
- api
- createStore
- store.dispatch
- store.getStore
- store.subscribe
redux中间件

- redux 中间件是对 dispatch 的封装。
redux-thunk
- 使用了 redux-thunk 插件后,action 就可以返回函数,而不仅仅是对象。
redux-saga
组件
- 可以将应用内的组件分为 “UI 组件”和“容器组件”
- UI 组件–负责页面的渲染
- 容器组件–处理逻辑
- 无状态组件–纯函数组件。如果一个组件只有 render 方法,可以将其改为一个无状态组件。相比于普通组件(类),无状态组件(函数)的性能更好。UI 组件写成无状态组件更为合适。
React-redux
- react-redux 提供了
<Provider>组件。在这个组件上传递的数据,子组件都可以使用。 - connect 将 store 将组件连接。
styled-components
安装的 styled-components 是 v4.2.0 的,与视频的不一样,所以写法也不一样。
- 没有 injectGlobal 这个 API 了,取而代之的是 createGlobalStyle。这个 API 是用来创建一个组件的。
// 创建css组件
export const Global = 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;
}
`
// 使用css组件
import React, { Fragment } from 'react'
import { Global } from './style.js'
function App() {
return (
<Fragment>
<Global />
<div>
dd
</div>
</Fragment>
);
}
export default App;
react-router
- 安装包为 react-router-dom
npm i react-router-dom -s
import { BrowserRouter, Route } from 'react-router-dom'
- 路径的严格匹配需要添加 exact 属性
- Link 组件必须写在 BrowserRouter 组件里面。比如可以在父组件用 BrowserRouter 包裹子组件,这样子组件就可以使用 Link 了。
immutable.js
- 用来确保数据不被改变。
- immutable 处理过的数据不能通过属性运算符取值,需要通过 get 方法得到值。
import { fromJS } from 'immutable'
const im = fromJS({ p: 1 }) // 错误 console.log(im.p) // 正确 console.log(im.get('p'))
- immutable 处理过的数据的修改需要通过 set 方法实现。
- List 只能把外层数组变成 immutable,而 fromJS 可以将整个全部变成 immutable。
吐槽
- 数据的双向绑定竟然要自己监听事件来实现。
- redux 竟然要自己手动订阅。
- redux、redux-thunk、redux-saga、react-redux…… 还能更蛋疼一点吗-_-