1.安装npm node.js以获得node.js开发环境,安装yarn作为包管理工具
2.安装脚手架工具create-react-app
3.使用脚手架工具启动一个react项目......

正式开始开发

1.在入口文件 index.js添加
import React from ‘react’
是为了react能够支持JSX语法

2.import App from './APP
App中A必须大写 JSX语法不支持app小写
所有渲染内容挂载到root节点上

3.一个组件中render返回的内容必须整体被包裹在div中
import { Fragment } from 'react'
Fragment用作占位符
用作占位符替代最外层的标签
但是不会再页面中显示

4.this.xxxxxxxxxx.bind(this)为此组件变更作用域
Bind方法放在constructor里面 可以只执行一次 提升性能
改变state数据值 使用setstate方法

关于虚拟DOM

JSX ->createElement ->虚拟DOM(js对象) ->真实DOM
虚拟DOM比对 DIFF算法 不要用index作key值 因为index会随着组件删除被改变
setstate有延时 可以render多个改变的状态
Ref方法 尽量不用 获取DOM
Setstate异步执行 下一个函数放在后面的回调函数里

关于生命周期函数

在某一个时刻 组件会自动调用执行的函数
mounting过程:
1.componentWillMount挂载之前
2.render
3.componentDidMount挂载之后

initialization过程:
Setup props and state

updation过程 :
props:
子组件接受参数 但是如果第一次存在于父组件中 不会触发
如果已经之前存在于父组件里 就会触发
componentsWillReceiveProps
shouldComponentUpdate (true/false)
componentWillUpdate (true)
Render()方法
componentDidUpdate()方法

States:
shouldComponentUpdate true/false
componentWillUpdate (true)
Render
componentDidUpdate

unmounting过程:
componentWillUnmount
把组件从页面中去除

关于提高性能

借助shouldComponentUpdate的方法 可以不用每次输入文本内容都重新渲染子组件

shouldComponentUpdate(nextProps, nextState, nextContext) {
  if (nextProps.content !== this.props.content) {
    return true;
  } else {
    return false;
  }
}

Ajax请求写在componentDidMount函数中 写在只执行一次的函数中
React中写ajax请求
首先import axios 利用Charles中的tool 里的map local 新建一个中间件 接受浏览器的请求 返回 桌面上的todolist.json
拿到res的json内容之后 直接使用setState函数 return一个函数式的声明 将页面中的内容list设置为res中的data数组

axios.get('/api/todolist')
  .then((res)=>{
    console.log(res.data);
    this.setState(()=>({
        list: [...res.data]
    }))
  })
  .catch(()=>{alert('error')})

Tip: 如果要返回对象 不用return 直接函数中返回({aaa:bbb})即可
另外需要使用es6中的语法 将res.data打散 重新传给list

关于transition动画

CSS过度效果 transition
Css动画效果

@keyframs bbb{
	0%
	50%
	100%
}
之前就可以直接使用
.aaa{
	animation: bbb 2s ease-in;
}

在animation里面 最后添加
animation: bbb 2s ease-in forwards forwards能够保存动画最后一帧css的样式
React-transition-group
CSSTransion 属性: in 添加标签 timeouot 持续时间 classNames= ‘fade’ fade对应css中的fade unmountOnExit 组件消失时DOM也消失
onEntered={}里面函数
Sytle.css里
fade-enter 刚入场的时候 fade-enter-active 第二个动执行结束 fade-enter-done 执行完成之后
Fade-exit 刚离开fade-exie-active离开时 fade-exit-done离开完成时
TransitionGroup写在外部 csstransition 写在dom的外部

关于Ant Design

antd使用方法:
yarn add antd
需要什么组件去官网看 需要使用直接先import 再在return里面用
可以直接在标签里添加style改变样式

关于redux

redux-flow
Store相当于图书管理员
react components相当于借书人
reducers相当于记录查询的电脑
action creatores相当于借书人的所有请求

Redux使用流程

Redux使用流程 首先 yarn add redux
1.然后在src目录下创建store文件夹 在store文件夹下创建index.js 通过使用

import { createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer);
export default

2.在store目录下创建reducer.js文件

const defaultState = {
	// 数据内容 随便填写
}
export default (state = defaultState, action) => {
  return state;
}

这样redux中的store和reducers都分别创建完毕
reducers可以看做记事本 store可以看做管理员
3.同时 在totolist.js中 直接引入store中的index.js 可以简写
import store from ‘./store’;
同时 在constructor中 使用
this.state = store.getState();
就可以用state拿到store中所有的数据

reducer可以接受state 但是绝对不能修改state

在reducer中判断action.type是否=== 然后return newState

JSON.parse(JSON.stringfy(value)) // javascript深拷贝

在组件中 使用订阅者模式

store.subscribe(this.handleStoreChange);
只要store发生改变 那么救护执行subscribe中的子函数 handleStoreChange方法

在handleStoreChange方法中 使用setState方法 重新加载数据 数据就从store中用getState重新获取

handleStoreChange() {
  this.setState(store.getState());
}

再来一遍 btn上挂载一个方法

static handleBtnClick() {
  const action = {
    type: 'add_todo_item'
  };
  store.dispatch(action);
}

返回一个action 然后dispatch到store中
store收到action 交给reducer
在reducer中 将newState的list push进inputValue

可以将actionTypes抽离出来放到一个公共文件 actionTypes.js文件中 不用字符串
也可以将公共的创建action抽离出来 新建一个acitonCreators文件 再在totolist.js文件中引入

redux补充:

Store必须是唯一的 只有store能够改变自己的内容 reduer中不可以改变store
Reducer必须是纯函数 纯函数是指给定固定的输入 就一定会有固定的输出 而且不会有任何副作用
核心API
createStore
store.dispatch
store.getState
store.subscribe

UI组件负责页面渲染 容器组件负责页面逻辑
Todolist todolisUI 互相之间传递要用的数据 函数
如果一个组件只有一个render函数 那么就是一个无状态组件
可以不用class extend 直接用下面的写法

const aaa = (props)=> {
	return (
		<div>
	)
}

关于redux-thunk

使用redux-thunk 是redux的中间件 进行ajax请求
使用多个中间件 参照git官网 redux-devtool-extion 有使用方法
1.在index.js中先配置

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(
  applyMiddleware(thunk),
  // other store enhancers if any
);
const store = createStore(
  reducer,
  enhancer
);

TodoList.js中 action可以从一个对象拓展成一个函数
函数也可以直接使用store.dispatch(action)触发redux
在函数中在执行一遍redux的流程 创建action的对象 然后dispatch
Redux的中间件 指的是action和store之间

redux-saga

在store中的index.js文件中
import createSagaMilddleware from ‘redux-saga’;

const sagaMiddleware = createSagaMilddleware();
const enhancer = composeEnhancers(
  applyMiddleware(sagaMiddleware),
);
const store = createStore(
  reducer,
  enhancer
);
sagaMiddleware.run(todoSagas);

Redux-saga需要额外创造新建一个sagas.js文件 文件中需要定义一个生成器函数 并且将其暴露出来 生成器函数的写法(es6)

import { takeEvery } from 'redux-saga/effects';
function* mySaga() {
	yield takeEvery(接收到的action,执行的函数(最好也是生成器的形式))
}

因为已经在index中进行了配置 所以sagas.js也可以接收到派发的action
执行的生成器函数里 最好不要用promise的写法 直接使用
function* aaa(){}这样的函数写法
内部的话
const res = yield axios.get(url)
可以使用try catch 的方法部捕获错误

React-redux

第一个核心API: Provider 能够获取store中的内容供provider中的组件使用
import { Provider } from ‘react-redux’;
第二个核心API: connect方法
第一个参数 将state与props映射 第二个 将dispatch与props映射
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);

项目正式开始

create-react-app 该删的都删掉
为了管理样式 使用styled-components
引入全局样式 style.js
;

import { createGlobalStyle } from ‘styled-components’
export const globalStyle = createGlobalStyle`
123{
	123
}
`

再到子组件中以组件的形式包裹
将组件拆分 新建一个Header文件夹

import styled from 'styled-components';
import logoPic from '../../statics/logo.png'

export const HeaderWrapper = styled.div`
  position: relative
  height: 56px;
  border-bottom: 1px solid #f0f0f0
`;
export const Logo = styled.a.attrs({
  href: '/' // 链接跳转
})`
  position: absolute
  top: 0;
  left: 0;
  display: block;
  height: 56px;
  width: 100px;
  background: url(${logoPic});// 引入图片
  background-size: contain;
`;