基础

React Fiber

16版本及16版本中的一些底层实现

选择Vue 或 React

React 灵活性,复杂的业务
Vue 更丰富API,灵活性有限制,更面向用户的选择

serviceWorker

PWA :progressive web application
把页面放到缓存中
import * as serviceWorker from './serviceWorker';

immutable 思想

state 不允许我们做任何的修改
Immutable Data 就是一旦创建,就不能再被更改的数据。

代码优化

关于再 render 函数中渲染 this.props.xxx 或者 this.state.xxx

  1. props: {
  2. type: 'stringType',
  3. name: "jack"
  4. }
  5. state: {
  6. value: '123',
  7. list: [1,2,3]
  8. }
  9. // 原始用法
  10. <div type={this.props.type} name={this.props.name}/>
  11. <div value={this.state.type} list={this.state.name}/>
  12. // 优化写法,通过解构赋值,先保存下来
  13. let {type, name} = this.props
  14. let {value, list: bookList} = this.state // 解构的时候 可以重新命名
  15. // 优化用法
  16. <div type={type} name={name}/>
  17. <div value={type} list={booklist}/>

bind 修改 this 指向的时候

原始写法:是再绑定事件的时候,用 bind 修改 this 指向;
优化写法:bind 改变 this 指向的操作,可以提前在 组件的 constructor 中实现;
我的写法:习惯在定义 事件的时候,采用 函数表达式 + 箭头函数

setState 异步方法

  1. handle_1(){
  2. this.setState({
  3. name: "ming"
  4. })
  5. }
  6. handle_2(){
  7. this.setState({
  8. name: this.state.name
  9. })
  10. }
  11. // good
  12. handle_1_good(){
  13. this.setState(() => ({name: "ming"}))
  14. }
  15. handle_2_good(){
  16. this.setState((prevState) => ({
  17. name: prevState.name
  18. })
  19. }

生命周期

生命周期函数是指子啊某一个时刻组件会自动执行的函数。

在子组件的 shouldComponentUpdate 中,判断是否需要更新子组件

  1. shouldComponentUpdate(nextProps, nextState){ // 接收两个参数
  2. if(nextProps.xxx !== this.props.xxx){
  3. return true
  4. }
  5. return false
  6. }

在 componentDidMount 中发送 Ajax 请求

过渡和动画

  • 切换 className, 写样式
  • react-transition-group

    UI组件和容器组件的拆分

    无状态组件

    中间件

    redux-thunk

    redux-thunk的配置:

    使得调用 thunk 的同时,也可以正常使用 redux-dev-tool

    1. // store/index.js
    2. import { createStore, applyMiddleware, compose } from 'redux'
    3. import ReduxThunk from 'redux-thunk'
    4. import reducer from './reducer'
    5. const reduxConfig =
    6. window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
    7. const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
    8. ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
    9. : compose
    10. const enhancer = composeEnhancers(applyMiddleware(ReduxThunk))
    11. const store = createStore(reducer, enhancer)
    12. export default store

    在组件中应用

    之后我们可以讲之前在 componentDidMount 中定义的 ajax 请求,放到 actionCreator.js 中处理。

    1. // TodoList.js 组件中的请求
    2. componentDidMount() {
    3. axios
    4. .get('https://jsonplaceholder.typicode.com/todos?_limit=5')
    5. .then(res => {
    6. const data = res.data
    7. const action = initListAction(data) // 以前的 action 只能是 一个对象,引用了 thunk 之后,可以是 函数了
    8. store.dispatch(action)
    9. })
    10. const action = getTodoListData() // 在 actionCreator 中创建的 action
    11. console.log(action)
    12. store.dispatch(action)
    13. }

    在actionCreator.js 中进行配置

    1. // actionCreator.js
    2. export const getTodoListData = () => {
    3. return dispatch => { // 直接接收 一个 dispatch 参数,调用的时候不用加 store 了
    4. axios
    5. .get('https://jsonplaceholder.typicode.com/todos?_limit=5')
    6. .then(res => {
    7. const data = res.data
    8. const action = initListAction(data)
    9. dispatch(action)
    10. // console.log(data)
    11. })
    12. }
    13. }

    redux-saga

    redux-saga 的配置

    1. // store/index.js
    2. import { createStore, applyMiddleware, compose } from 'redux'
    3. import createSagaMiddleware from 'redux-saga'
    4. import reducer from './reducer'
    5. import TodoSagas from './sagas' ##
    6. const reduxConfig =
    7. window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
    8. // create the saga middleware
    9. const sagaMiddleware = createSagaMiddleware() ##
    10. const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
    11. ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
    12. : compose
    13. const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware)) ##
    14. const store = createStore(reducer, enhancer)
    15. // then run the saga
    16. sagaMiddleware.run(TodoSagas) ##
    17. export default store

    create sagas.js

    1. // sagas.js
    2. function* mySaga() {
    3. // yield takeLatest("USER_FETCH_REQUESTED", fetchUser);
    4. }
    5. export default mySaga

    把 componentDidMount 中的请求,放到 sagas.js 文件中请求

    在 todolist 组件中,创建派发了一个action

    1. componentDidMount() {
    2. const action = getInitSagaAction()
    3. store.dispatch(action)
    4. console.log('saga', action)
    5. }

    之前在创建 store 的时候,使用了 saga 中间件,进行了基础的配置,

  • 引入createSagaMiddleware

  • 创建一个 SagaMiddleware: const sagaMiddleware = createSagaMiddleware()
  • 使用 这个 middle ware:

    1. const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware))
  • 创建 sagas.js并引入,run起来

    1. // then run the saga
    2. sagaMiddleware.run(TodoSagas)
  • 编写 sagas 文件,一定要导出了个 generator 函数;在这个 函数中,写了一些 判断 type 的逻辑

  • 匹配到 type ,执行方法,在这个方法中,创建一个 action, 派发给 store, store 传递给 reducer ,然后 reducer 判断到 type = init… , 就会执行 更新 list,然后更新 state

然后不仅仅 reducer 能接收到 这个 action,还有 sagas.js 中的 mySaga 函数 也能接收到这个 action。然后通过 takeEvery 这个函数,声明了 ,如果接收到 类型 为 GET_INIT_LIST_SAGA的 action,就执行第二个参数的 方法 fetchInitList, 然后就会执行这个方法,然后就可以将异步的一些逻辑写在这里,就实现了 我们想要将 异步 逻辑 拆分到 sagas 文件中管理的 需求。

  1. import { takeEvery, put } from 'redux-saga/effects'
  2. import { GET_INIT_LIST_SAGA } from './actionTypes'
  3. import axios from 'axios'
  4. import { initListAction } from './actionCreators'
  5. function* fetchInitList() {
  6. console.log('abc')
  7. // axios.get('https://jsonplaceholder.typicode.com/todos?_limit=5').then(res => {
  8. // const data = res.data
  9. // const action = initListAction(data)
  10. // // store.dispatch(action)
  11. // put(action)
  12. // })
  13. // const res = yield axios.get(
  14. // 'https://jsonplaceholder.typicode.com/todos?_limit=5'
  15. // )
  16. // const action = initListAction(res.data)
  17. // yield put(action)
  18. try {
  19. const res = yield axios.get(
  20. 'https://jsonplaceholder.typicode.com/todos?_limit=5'
  21. )
  22. const action = initListAction(res.data)
  23. yield put(action)
  24. } catch (e) {
  25. console.log('请求失败')
  26. }
  27. }
  28. // generator 函数
  29. function* mySaga() {
  30. yield takeEvery(GET_INIT_LIST_SAGA, fetchInitList)
  31. }
  32. export default mySaga

react-redux

  1. // src/index.js
  2. import React from 'react'
  3. import ReactDOM from 'react-dom'
  4. import TodoApp from './TodoApp'
  5. import { Provider } from 'react-redux' # 提供器
  6. import store from './store'
  7. const App = (
  8. <Provider store={store}>
  9. <TodoApp />
  10. </Provider>
  11. )
  12. ReactDOM.render(App, document.getElementById('root'))
  1. // store/index.js
  2. import { createStore } from 'redux'
  3. import reducer from './reducer'
  4. const store = createStore(reducer)
  5. export default store
  1. // TodoList.js
  2. import React, { Component } from 'react'
  3. import { Input, Button, List } from 'antd'
  4. import 'antd/dist/antd.css'
  5. // import store from './store'
  6. import { connect } from 'react-redux'
  7. class TodoApp extends Component {
  8. // constructor(props) {
  9. // super(props)
  10. // this.state = store.getState()
  11. // }
  12. render() {
  13. return (
  14. <div style={{ margin: '20px' }}>
  15. <Input
  16. style={{ width: '300px', marginRight: '10px' }}
  17. placeholder="add new todo"
  18. value={this.props.inputValue}
  19. onChange={this.props.handleInputChange}
  20. ></Input>
  21. <Button type="primary">添加</Button>
  22. <List
  23. style={{ width: '300px', marginTop: '10px' }}
  24. bordered
  25. dataSource={[]}
  26. renderItem={(item, index) => {
  27. return <List.Item onClick={() => {}}>123</List.Item>
  28. }}
  29. />
  30. </div>
  31. )
  32. }
  33. }
  34. const mapStateToProps = state => {
  35. # 连接规则,把 state 中的数据 映射成组件的 props
  36. return {
  37. inputValue: state.inputValue,
  38. list: state.list
  39. }
  40. }
  41. const mapDispatchToProps = dispatch => {
  42. # store.dispatch 映射到 props
  43. return {
  44. handleInputChange(e) {
  45. console.log(e.target.value)
  46. const action = {
  47. type: 'change_input_value',
  48. value: e.target.value
  49. }
  50. dispatch(action)
  51. }
  52. }
  53. }
  54. export default connect(mapStateToProps, mapDispatchToProps)(TodoApp) # 连接器
  1. // reducer.js
  2. const defaultState = {
  3. inputValue: 'hello',
  4. list: ['world']
  5. }
  6. export default (state = defaultState, action) => {
  7. if ((action.type = 'change_input_value')) {
  8. const newState = JSON.parse(JSON.stringify(state))
  9. newState.inputValue = action.value
  10. return newState
  11. }
  12. return state
  13. }