1,文件解释
App.test.js自动化测试文件
manifest.json pwa配置文件 可以访问图标快捷方式
2,PWA progressive web application 写网页的形式写手机app 断网的时候第二次访问也可以看到第一次访问的页面
import registerServiceWorker from './registerServiceWorker';
3,react16 有占位符
Fragment 可以解决render函数外层的div的问题
import {Fragment} from 'react'
...
<Fragment></Fragment>
4,定义数据(state负责存储数据)
constructor(props){
super(props);
this.state={
inputValue:'',
list:[]
}
//绑定到组件this的方法
this.handleClick = this.handleClick.bind(this)
}
5,用setState改变state数据
this.setState({
inputValue:e.target.value
})
6,immutable state不允许我们做任何改变
7,不自动转义(但是容易被攻击)
dangerouslySetInnerHTML={{__html:item}}
8,htmlFor
<label htmlFor="area"></label>
<input id="area"/>
9,父组件向子组件传值(属性传值)
父组件:content={item}
子组件:this.props.content
9,子组件向父组件传值
父组件:
content={item}
index={index}
deleteItem={this.handleItemDelete.bind(this)}
子组件:
this.props.content
this.props.index //获取index值
this.props.deleteItem(this.props.index)
10,数据验证propTypes
import PropTypes form 'prop-types'
TodoItem.propTypes={
content:PropTypes.string,
index:PropTypes.number,
deteleItem:PropTypes.func,
test:PropTypes.string.isRequired //验证数据必需传值如果没值就会给出警告(warning)
}
如果 test 没有被传值可以设置默认值
TodoItem.defaultProps={
test:'hello world'
}
11,prop state render的关系
- 当组件state或prop发生变化时,render函数就会重新运行
- 当父组件的render函数运行时,它的子组件都将被重新运行一次
12,react的虚拟DOM(同层比对)
- 1,state 数据
- 2,JSX 模版
- 3,模版+数据 生成虚拟DOM(虚拟DOM就是一个JS对象,用它来描述真实的DOM) (损耗了性能)(虽然损耗了性能,但是相比真实DOM损耗的很少)
['div',{id:"abc"},['span',{},'hello react']]
- 4,用虚拟DOM的结构生成真实的DOM,来显示
<div id="abc"><span>hello react</span></div>
- 5,state发生变化
- 6,数据+模版生成新的虚拟DOM (极大的提升了性能)
['div',{id:"abc"},['span',{},'hello react']]
- 7,比较原始的虚拟DOM和新的虚拟DOM的区别,差异是
span的内容 (极大的提升了性能) - 8,直接操作DOM,改变
span的内容
13,react中ref的使用
ref属性来帮助我们获取已经挂载的元素的 DOM 节点
我们可以给任意代表 HTML 元素标签加上 ref 从而获取到它 DOM 元素然后调用 DOM API。
但是记住一个原则:能不用 ref 就不用。
特别是要避免用 ref 来做 React.js 本来就可以帮助你做到的页面自动更新的操作和事件监听。多余的 DOM 操作其实是代码里面的“噪音”,不利于我们理解和维护。
14,生命周期
生命周期函数指在某一时刻组件会自动调用执行的函数
componentWillMount:在组件即将被挂载到页面的时刻自动执行,在render之前执行(第一次挂载被执行)
render:页面挂载时执行
componentDidMount:组件在挂载到页面之后自动执行,在render之后执行(第一次挂载被执行)
shouldComponentUpdate:组件被更新之前,会自动被执行(必须有布尔类型的返回值,true:被更新,false:不会被更新)
componentWillUpdate:组件被更新之前,会自动被执行,它在shouldComponentUpdate之后被执行,
如果shouldComponentUpdate返回true才执行,返回false就不会被执行
componentDidUpdate:组件更新完成之后,会自动被执行
componentWillReceiveProps:一个组件要从父组件接受参数;只要父组件的render函数重新被执行了,子组件这个生命周期函数就会被执行(如果这个组件第一次存在于父组件中,不会被执行,如果这个组件之前已经存在于父组件中,才会执行)
componentWillUnmount:当组件即将被从页面中剔除的时候才会被执行
15,生命周期使用场景
- 父组件更新渲染的时候,子组件也跟着更新(只有content发生变化的时候才更新)(性能优化)
shouldComponentUpdate(nextProps,nextState){
if(nextProps.content!==this.props.content){
return true
}else{
return false
}
}
- Ajax请求放在
componentDidMount函数里(安装Axios)
16,react-transition-group(过渡动画组件)
17,Redux=Reducer+Flux
-
yarn add redux安装redux -
Store的创建
在src创建store/index.js
import {createStore} from 'redux';
import reducer from './reducer'
const stroe = createStore(reducer);
export default store;
创建Reducers传递给store
在src创建store/reducer.js
const dfaultState={
inputValue:'',
list:[]
}
export default (state=defaultState,action) =>{
return state;
}
18,ActionTypes的拆分
- 创建store/actionTypes.js
export const CHANGE_INPUT_VALUE= 'change_input_value'
export const ADD_TODO_ITEM= 'add_todo_item'
export const DELETE_TODO_ITEM= 'delete_todo_item'
- 在todoList2.js中引用
import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM} from './store/actionTypes'
- 替换之前的值(change_input_value,add_todo_item,delete_todo_item)
...
type:CHANGE_INPUT_VALUE,
...
19,使用actionCreator统一创建action
- 创建store/actionCreator.js
import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM} from './actionTypes';
export const getInputChangeAciton = (value)=>({
type:CHANGE_INPUT_VALUE,
value
})
export const getAddItemAciton = ()=>({
type:ADD_TODO_ITEM
})
export const getDeleteItemAciton = (index)=>({
type:DELETE_TODO_ITEM,
index
})
- 在todoList2.js中引用
import {getInputChangeAciton,getAddItemAciton,getDeleteItemAciton} from './store/actionCreator'
- 替换
...
const action = getInputChangeAciton(value)
...
-
store 是唯一的
-
只有store能改变自己的内容
-
reducer 必须是纯函数(reducer可以接收state,但是不能修改state;纯函数是指给定固定的输入,就一定会有固定的输出,而且不会有任何副作用)
20,无状态组件
无状态组件:这个组件只有render函数的组件叫做无状态组件
// 无状态组件
const TodoListUI = (props)=>{
return(
<Fragment >
<div style={{marginTop:"20px",marginLeft:"20px"}}>
{/* input框 */}
<Input
placeholder="todo info"
style={{width:"300px",marginRight:"10px"}}
value={props.inputValue}
onChange={props.handleInputChange}/>
<Button onClick={props.handleBtnClick} type="primary">确定</Button>
</div>
<List
style={{width:"500px",marginTop:"20px",marginLeft:"20px"}}
bordered
dataSource={props.list}
renderItem={(item,index) => (<List.Item onClick={(index)=>{props.handleItemDelete(index)}}>{item}</List.Item>)}
/>
</Fragment>
)
}
21,redux-thunk
-
redux 的中间件redux-thunk安装:
yarn add redux-thunk -
在store/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),
);
const store = createStore(reducer, enhancer);
中间件解决异步代码拆分,可以是action返回一个函数
22,redux-saga
-
redux 的中间件redux-saga安装:
yarn add redux-saga -
在store/index.js里导入和引用
import {createStore,applyMiddleware,compose} from 'redux';
import createSagaMiddleware from 'redux-saga';
import TodoSagas from './sagas';
const sagaMiddleware = createSagaMiddleware();
const enhancer = composeEnhancers(
applyMiddleware(sagaMiddleware),
);
sagaMiddleware.run(TodoSagas);
- sagas.js
import {takeEvery,put} from 'redux-saga/effects';
import {GET_INIT_LIST} from './actionTypes'
import { getInitDataAction } from './actionCreator';
import axios from 'axios';
function* getLists(){
const res = yield axios.get('http://localhost:3003/list');
const action = getInitDataAction(res.data);
yield put(action)
}
function* mySaga() {
yield takeEvery(GET_INIT_LIST, getLists);
}
export default mySaga;
- actionType.js
export const GET_INIT_LIST="get_init_list"
- actionCreator.js
export const getInitList = (data)=>({
type:GET_INIT_LIST,
data
})
23,react-redux
-
react-redux的安装:
yarn add react-redux -
在index.js引入react-redux:
import {Provider} from 'react-redux';
import store from './store'
const App =(
<Provider store={store}>
<TodoList/>
</Provider>
)
ReactDom.render(App,document.getElementById('root'));
Provider把store提供给了Provider里面所有的内部组件(比如:TodoList)
- TodoList如何获取store,在TodoList.js中
import {connect} from 'react-redux';
...
render(){
const {value,handleInputChange,list,handleClick,handleDelete} = this.props;
return(
<div>
<div>
<input value={value}
onChange={handleInputChange}/>
<button onClick={handleClick}>确定</button>
</div>
<ul>
{list.map((item,index)=>{
return(
<li
key={index}
onClick={handleDelete}>{item}</li>
)
})}
</ul>
</div>
)
}
...
//连接规则(TodoList与store连接)store.state
const mapStateToProps = (state)=>{
return {
value:state.value
}
}
//store.dispatch,props
const mapDispatchToProps = (dispatch)=>{
return{
changeValue(e){
const action ={
type:'change',
value:e.target.value
}
dispatch(action)
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);