https://note.youdao.com/ynote...

all in js
单向数据流

Fragment:占位符,替换最外层DIV

事件方法绑定
//方法一
<input value={inputVal} onChange={this.handleInputChange.bind(this)} />
<input value={inputVal}
//方法一-传递下标
onChange={this.handleInputChange.bind(this),index} />

//方法2
//this 的绑定放在构造函数里, 这样函数的this 永远指向这个组件
constructor(){

this.handleInputChange = this.handleInputChange.bind(this)

}

handleInputChange(){

console.log(this);

}

改变状态值-setState
setState 可以接受一个参数preState (和构造函数里state保持一致)
preState: 上一次修改之前数据的状态

//方法一
this.setState({

xxx:xxx

})
//方法二 ---新版本推荐语法
this.setState(()=>{

return {
    xxx:xxx
}

})
or
this.setState(()=>({ xxx:xxx }))
注释
{/xxxxxxxxxxxxxxxxxxxxx/}
{/xxxxxxxxxxxxxxxxxxxxxxx/}
className代替样式class
<div className='test'>
dangerouslySetInnerHTML
//<h1>hello world </h1> 相当于 v-html
<div dangerouslySetInnerHTML={{_html:item}}>
</div>
子组件修改父组件内容
子组件如何调用父组件方法,修改父组件的数据?
只需要把父组件的方法传给子组件,子组件就可以通过这个方法间接的操作父组件的数据

传递函数给子组件需要强制把作用域绑定在父组件的this
import Child from "./Child"
class Father extends React.Component{

render(){
    <div>
        <Child showFather={this.handleFather.bind(this)}></Child>
    </div>
}
handleFather(){
    alert('this is Father')
}

}
//子组件调用
this.props.showFather()
propTypes和defaultTypes
import React,{Component} from 'react'
import PropTypes from 'prop-types'

class Test extends Component{

}
Test.propTypes={

content:PropTypes.string,
deleteItem:PropTypes.func,
index:PropTypes.number,
test:PropTypes.string.isRequired,
test2:onOfType([PropTypes.number,PropTypes.string])//两个类型都可以,这两个类型中的一个
test3:arrayOf(PropTypes.number,PropTypes.string)//数组类型,数组的组成内容可以是数字或者字符

}
Test.defaultProps={

test:"hello world"

}
Props,State和Render的关系
当组件的Props或者state发生改变的时候Render函数就会重新执行
父组件的render执行的时候子组件的render也会被执行
虚拟dom
虚拟dom是一个js对象,用来描述真实DOM
在js里面比较js对象不怎么耗性能,但是比较真实的dom会很耗费性能

用数组来描述第一个参数是标签名称,第二个参数是属性,第三个方法是子元素
['div',{id:"test"},['span',{},'hello']]
state 数据
JSX模板
数据+模板结合生成虚拟dom --原始虚拟DOM
用虚拟dom的结构,来生成真实DOM,在页面显示""
state发生变化
数据+模板结生成新的虚拟dom --新的虚拟dom
比较原始虚拟dom和新生成的虚拟dom的区别,区别出有差异的dom
直接操作dom 改变内容
ref
ref 接受一个箭头函数 (数据驱动,尽量不要用ref) ref使用放在setState的第二个函数里面执行, 确保正确

<div ref={(testref)=>{

this.testref = testref

}}></div>
声明周期
某一时刻 组件会自动调用执行的函数 生命周期

render:渲染页面
getDerivedStateFromProps:接受两个参数(props,state)
构造函数执行后执行
state和props更新也会被执行
componentWillMount:组件即将被挂载到页面之前的时候执行(还没有被挂载)
componentDidMount:组件被挂载之后制动执行
shouldComponentUpdate:组件是否更新,返回布尔值类型,组件更新之前执行
componentWillUpdate:组件被更新之前自动,shouldComponentUpdate之后执行,如果shouldComponentUpdate返回true才执行,否则不会被执行
componentDidUpdate:组件完成更新之后会被执行
componentWillReceiveProps:执行需要满足一下条件
当组件从父组件接受了参数
如果这个组件第一次存在于父组件中,不会执行
如果之前已经存在于父组件中,才会执行
componentWillUnmount:这个组件即将从页面中剔除的时候执行
生命周期使用场景
shouldComponentUpdate(nextProps,nextState):接受两个参数
nextProps:接下来我的属性要变成什么样子,nextState 同理;避免组件重复渲染
componentDidMount:函数里来执行ajax请求
性能提升
shouldComponentUpdate:避免渲染
函数作用域绑定放在constroctor函数里做,函数作用域绑定只会执行一次,减少子组件的无谓渲染,
setState:异步函数, 可以把多次性能的改变结合成一次。降低虚拟DOM的比对频率
虚拟dom,同层比对 KEY值比对,提高比对速度
React动画效果
css过渡动画
.show{

opacity:1
transinition:all 1s ease-in;

}
.hide{

opacity:0;
 transinition:all 1s ease-in;

}
css动画效果

@keyframes hide-iten{

0%{
    opacity:1;
    color:red;
}
50%{
    opacity:0.5;
    color:green;
}
100%{
    opacity:0;
    color:blue;
}

}
//forwards:当动画完成后,保持最后一个属性值(在最后一个关键帧中定义)
animation: hide-item 2s ease-in forwards;

React-transition-group
CSSTransition

<CSSTransition
in={showValidationMessage}
timeout={300}
classNames="message"
unmountOnExit
onExited={() => {

this.setState({
  showValidationButton: true,
});

}}
/>
//
in={showValidationMessage}
timeout:动画执行时间
classNames:类名前缀(fade)
unmountOnExit:隐藏之后dom被移除

.fade-enter{

  opacity:0;

}
.fade-enter-active{

  opacity:1;
  transition:opacity 1s easy-in;

}
.fade-enter-done{

   opacity:1;

}
.fade-exit{

  opacity:1

}
.fade-exit-active{

opacity:0;
 transition:opacity 1s easy-in;

}
.fade-done{

  opacity:0

}
CSSTransition会自动的给dom添加一些样式,什么时候添加这个样式由“in”来控制
动画执行会在dom元素挂载css类:.fade-enter,.fade-enter-active,.fade-active.done,.fade-exit, .fade-exit-active, .fade-exit-done
.fade-enter:当动画执行入场动画时,也就是showValidationMessage由flase变成true的时候,在入场动画执行的第一个时刻,组件会给div挂载.fade-enter,刚要入场还没有入场的时候的状态
.fade-enter-active:入场动画执行的第二个时刻,到入场动画执行完成之前。dom上一直会有这个fade-enter-active
.fade-active.done:当整个入场动画执行完成之后,.fade-active.done会被添加到dom元素
React-transition-groupJS实现动画
classNames={{
appear: 'my-appear',
appearActive: 'my-active-appear',
enter: 'my-enter',
enterActive: 'my-active-enter',
enterDone: 'my-done-enter,
exit: 'my-exit',
exitActive: 'my-active-exit',
exitDone: 'my-done-exit,
}}

<CSSTransition
onExited={() => {

this.setState({
  showValidationButton: true,
});

}}
//钩子函数(和生命周期函数一样,在某一个时刻自动执行的函数)
onEntered={(el)=>{

el.style.color = "red"

}}

onEntered:入场动画执行完成之后执行,该钩子执行,接受一个参数el(CSSTransition内部包裹的元素) el.style.color = "red"
onEnter:入场动画执行第一帧的时候执行
onEntering:入场动画第二帧,到结束之前执行
第一次进入页面加动画
第一次展示也要动画效果 appear=true

<CSSTransition appear={true} />
改功能会在动画执行的第一帧 添加==.fade-appear==

<div class="fade-active fade-appear">
动画第二帧,已经整个动画执行的过程中 添加.fade-appear-active

TransitionGroup
多个动画

UI组件和容器组件的拆分
UI组件负责容器的渲染-傻瓜组件
容器组件负责页面的逻辑-容器组件
无状态组件
一个组件如果只有render函数的时候,可以改写成无状态组件

性能会更高,因为它就是一个函数,而不是一个类,所以没有生命周期函数
定义UI组件,或者没有逻辑操作 只需要渲染的时候可以定义为无状态组件
const test=(props)=>{

render(){
    return (
        <div>{props.test}</div>
    )
}

}
Redux
实例图: 类似于一个图书馆借书流程

React Components:用户
Action Creators:借书的动作(告诉管理员要借什么书)
Store:图书馆管理员负责所有图书的管理(store是唯一的,只有store能改变自己的内容,store拿到reduce返回的数据,再对数据进行更新,reduce只是对数据做处理)
Reducers:记录本,记录所有的数据(必须是一个纯函数--给定固定的输入,就一定会有固定的输出,而且不会有任何副作用)
React Components
Action Creators
Store
Reducers
(1)
(2) dispatch(action)
(3)(previousState,action)
(4) (newState)
(5)(state)
React Components
Action Creators
Store
Reducers
reduce

创建流程
1.创建数据管理仓库

yarn add redux
创建store 文件夹, 创建index.js(store 代码存放位置) index.js

import {createStore} from 'redux';
//第二步创建reducer.js后 引入reducer
import reducer from './reducer.js'
const store = createStore()
export default store
2.创建reducer.js(负责对全局数据的更改)
根据用户派发的action和value来对state做操作,然后返回新的newstate(固定写法)
reducer可以接受state但是绝对不能修改state,所以我们要定义一个新的newState

//state:存储所有的数据
//设置默认值
const defaultState = {

inputVal:'',
list:[],

}
export default (state=defaultState,action)=>{

let newState = JSON.parse(JSON.stringify(state))
switch (action.type) {
    case 'change_input_value':
        newState.inputVal = action.value;
        return newState;
        break;
    case 'add_item':
        newState.list.push(newState.inputVal);
        newState.inputVal = ""
        return newState;
        break;
    default:
        return state
}
return state

}
3.在文件中引入,获取数据

store.getState():获取store数据
store.dispatch(action):设置更改store数据;(action={type:'',val})
import React from 'react'
import store from 'store/index.js'
class text extends React.component{

constructor(props){
    super(props)
    this.state = store.getState()
    //订阅store状态,发生改变时回调函数自动执行
    store.subscribe(()=>{
        this.setState(store.getState())
    )
}
submitSatate(val){
    const action ={
        type:'change_input_value',
        value:val
    }
}

}
Redux-thunk中间件
将异步请求或者复杂的逻辑放到action里来执行
https://github.com/reduxjs/re...;
如何引入

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';

// Note: this API requires redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
如何使用 普通的action creator返回的是一个对象

export const getTodoList=(data)=>(

{
    type:'TODOLIST',
    data
}

)
使用redux-thunk 可以在里面返回一个异步函数

//返回action
export const initListAction =(data)=({

type:"INIT_LIST_ACTION",
data,

})
export const getTodoList =()=>{

return (dispacth)=>{
    axios.get(url).then((res)=>{
        const data = res.data;
        const action = initListAction(data)
        dispatch(action)
    })
}

}
在业务代码中使用

componentDidMount(){

const action = getTodoList();
store.dispatch(action)

}
store.dispatch(action)调用的时候action会自动被执行(此时action是redux-thunk返回的一个函数) redux-thunk
中间件是在 action--store中间做操作

Redux-saga 中间件
https://github.com/redux-saga... 后续补上

React-Redux的使用
第三方模块,可以帮助我们在React中更加方便的使用Redux

核心API
Provider:连接Store,Provier内部的组件都有能力获取到Store里的内容了
connect:让组件和sotre做连接
安装--首配置

npm install --save react-redux

//更目录下的index 引入 react-redux,store
import { Provider } from 'react-redux'
import store from './store/index'
//将要渲染在更目录下的组件用provider包裹起来(Provider其实就是一个组件)
//将store作为属性值传递给provider,provider内部的组件都有能力获取store
const App = (

<Provider store={store}>
    <TodoList />
</Provider>

)
//将App作为组件 传递给ReactDOM.render方法
ReactDOM.render(<TodoList />, document.getElementById('root'));
组件内使用,使用Props来获取状态或者派发dispatch

import {connect} from 'react-redux';

class TodoList extends Component{

render(){
    return {
        <div>
        </div>
    }
}

}

const mapStateToProps = (state) => {
return {

   inputVal: state.inputVal,
   list: state.list

}
}
//将Store的dispatch方法挂载到Props方法上
//自动disPatch(方法可以直接返回{type:xxx,value:xxx})
const mapDispatchToProps = (dispatch) => {
return {

   changeInputValue(e) {
       let inputVal = e.target.value
       const action = {
           type: 'change_input_value',
           inputVal
       }
       dispatch(action)
   },

}
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoList)
请求拦截
//拦截请求
axios.interceptors.request.use(config => {

console.log(config)
return config

})

//拦截响应
axios.interceptors.response.use(response => {
console.log(response)

return response

})


菠菜
92 声望6 粉丝