共计 8225 个字符,预计需要花费 21 分钟才能阅读完成。
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);
}
改变状态值 -setStatesetState 可以接受一个参数 preState (和构造函数里 state 保持一致)preState: 上一次修改之前数据的状态
// 方法一 this.setState({
xxx:xxx
})// 方法二 — 新版本推荐语法 this.setState(()=>{
return {
xxx:xxx
}
})orthis.setState(()=>({ xxx:xxx}))注释{/xxxxxxxxxxxxxxxxxxxxx/}{/xxxxxxxxxxxxxxxxxxxxxxx/}className 代替样式 class<div className=’test’>dangerouslySetInnerHTML//<h1>hello world </h1> 相当于 v-html<div dangerouslySetInnerHTML={{_html:item}}></div> 子组件修改父组件内容子组件如何调用父组件方法,修改父组件的数据? 只需要把父组件的方法传给子组件,子组件就可以通过这个方法间接的操作父组件的数据
传递函数给子组件需要强制把作用域绑定在父组件的 thisimport 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 和 defaultTypesimport 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 改变内容 refref 接受一个箭头函数 (数据驱动,尽量不要用 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-groupCSSTransition
<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 ComponentsAction CreatorsStoreReducers(1)(2) dispatch(action)(3)(previousState,action)(4) (newState)(5)(state)React ComponentsAction CreatorsStoreReducersreduce
创建流程 1. 创建数据管理仓库
yarn add redux 创建 store 文件夹,创建 index.js(store 代码存放位置) index.js
import {createStore} from ‘redux’;// 第二步创建 reducer.js 后 引入 reducerimport reducer from ‘./reducer.js’const store = createStore()export default store2. 创建 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.0const store = createStore(rootReducer, applyMiddleware(thunk)); 如何使用 普通的 action creator 返回的是一个对象
export const getTodoList=(data)=>(
{
type:’TODOLIST’,
data
}
)使用 redux-thunk 可以在里面返回一个异步函数
// 返回 actionexport 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
核心 APIProvider: 连接 Store,Provier 内部的组件都有能力获取到 Store 里的内容了 connect: 让组件和 sotre 做连接安装 – 首配置
npm install –save react-redux
// 更目录下的 index 引入 react-redux,storeimport {Provider} from ‘react-redux’import store from ‘./store/index’// 将要渲染在更目录下的组件用 provider 包裹起来(Provider 其实就是一个组件)// 将 store 作为属性值传递给 provider,provider 内部的组件都有能力获取 storeconst 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
})