react总结
一、三大部分state、prop、ref
props
MyComponent.propTypes = {
// 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
// 可以被渲染的对象 numbers, strings, elements 或 array
optionalNode: React.PropTypes.node,
// React 元素
optionalElement: React.PropTypes.element,
// 用 JS 的 instanceof 操作符声明 prop 为类的实例。
optionalMessage: React.PropTypes.instanceOf(Message),
// 用 enum 来限制 prop 只接受指定的值。
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
// 可以是多个对象类型中的一个
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),
// 指定类型组成的数组
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
// 指定类型的属性构成的对象
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
// 特定 shape 参数的对象
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
// 任意类型加上 `isRequired` 来使 prop 不可空。
requiredFunc: React.PropTypes.func.isRequired,
// 不可空的任意类型
requiredAny: React.PropTypes.any.isRequired,
// 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error('Validation failed!');
}
}
}
}
二、生命周期
旧的生命周期:
初始化阶段:
constructor–>componentWillMount(消息订阅、发送请求)–>render–>componentDidMount
数据类型
更新阶段:
(componentWillReceiveProps组件传值是接收新的值nextPorps)–>shouldComponentUpdate(控制组件更新的“阀门”一般返回true,返回false就结束nextPorps,nextState)–>componentWillUpdate–>render–>componentDidUpdate
卸载:
componentWillUnmount
(卸载DOM:ReactDOM.unmountComponentAtNode(document.getElementById(‘test’)))
新的生命周期
初始化阶段:
constructor–>getDerivedStateFromProps(含有两个参数,第一个参数是传递过来的prop,第二个是state,返回新的state,不能使用this)–>render–>compoenetDidMount
跟新阶段:
getDerivedStateFromProps->shouldComponentUpdate–>render–>getsnapsshotBeforeUpdate(得到修改之前的快照)–>componentDidUpdate(接受三个参数preProps,preState,snapshotValue)
卸载组件: 由ReactDOM.unmountComponentAtNode()触发
componentWillUnmount()
相关面试题:
1.react的生命周期都有哪些
2.React废除了哪些生命周期为什么
废弃了componentWillmount、componentWillUpdate、componentWillDerivedProps
原因是这三个函数秀在render之前,因为fiber的出现,很可能出现因为优先级任务的出现打断现有任务,导致他们被执行多次
3.React16x中props改变后在那个生命周期中处理
getDerivedStateFromProps
4.react性能优化在那个生命周期,优化的原理是什么
shouldComponentUpdate ,原理是diff算法
5.state和props触发更新的生命周期分别有什么区别
在16之前props变化调用componentwillDeceivePops,state调用componentShouldUpdate
在16之后都一起调用getDerivedStatefromProps
6.react中发起网络请求应该在那个生命周期中执行,为什么
componnetDidMount, componentDidMount方法中的代码,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载。此外,在这方法中调用setState方法,会触发重新渲染。所以,官方设计这个方法就是用来加载外部数据用的,或处理其他的副作用代码。与组件上的数据无关的加载,也可以在constructor里做,但constructor是做组件state初绐化工作,并不是做加载数据这工作的,constructor里也不能setState
7.react16中新的生命周期有哪些
getDerivedStateFromProps/getSnapshotBeforeUpdate
组件通信
1.props
父传子:
父组件:todos={todos}
子组件:const {todos} = this.props
(yarn add prop-types import PropTypes from ‘prop-types’)
//对接收的props进行:类型、必要性的限制
static propTypes = {
todos:PropTypes.array.isRequired,
updateTodo:PropTypes.func.isRequired,
deleteTodo:PropTypes.func.isRequired,
}
子传父:
子组件调用父组件传递的方法,通过参数传递值
子组件:
handleDelete = (id)=>{
if(window.confirm('确定删除吗?')){
this.props.deleteTodo(id)
}
}
父组件:
deleteTodo = (id)=>{
//获取原来的todos
const {todos} = this.state
//删除指定id的todo对象
const newTodos = todos.filter((todoObj)=>{
return todoObj.id !== id
})
//更新状态
this.setState({todos:newTodos})
}
2.消息订阅-发布
工具库:PubSubJS 下载:yarn add pubsub-js --save
使用:
import PubSub from 'pubsub-js' //引入
PubSub.publish('delete', data) //发布消息
PubSub.subscribe('delete', function(data){ }); //订阅
发布消息:
PubSub.publish('atguigu',{isFirst:false,isLoading:true})
订阅消息:第二个参数的横线代表消息名称,可以不用管
componentDidMount(){
this.token = PubSub.subscribe('atguigu',(_,stateObj)=>{
this.setState(stateObj)
})
}
componentWillUnmount(){
PubSub.unsubscribe(this.token)
}
3.集中式管理
redux
4.context 生产者-消费者模式
//创建Context对象
const MyContext = React.createContext()
const {Provider,Consumer} = MyContext
生产者(祖先组件)
<Provider value={{username,age}}>
<B/>
</Provider>
中间组件
class B extends Component {
render() {
return (
<div className="child">
<h3>我是B组件</h3>
<C/>
</div>
)
}
}
消费者(子组件)
<Consumer>
{value => `${value.username},年龄是${value.age}`}
</Consumer>
1.父子组件的通信方式
props
2.跨级组件的通信方式
消息订阅-发布、集中式管理、conText(用的少)
3.非嵌套组件的通信方式
消息订阅-发布、集中式管理
4.如何解决props层级过深的问题
context 或集中管理redux
5.组件通信方式有哪些
redux
原始redux
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lH6hStwy-1627349634767)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\1626054235119.png)]
1.action
在redux中建立action.js,在次文件中生成action对象,提供给组件使用:用store.dispatch来分发
生成action对象:
//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})
//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
// 当检查到返回的不是对象时,会自动识别为异步anction传入dispath,就不需要用store去调用dispath了
export const createIncrementAsyncAction = (data,time) => {
return (dispatch)=>{
setTimeout(()=>{
dispatch(createIncrementAction(data))
},time)
}
}
// 若为异步action,需要在store.js中配置中间键applyMiddleware(thunk)
export default createStore(countReducer,applyMiddleware(thunk))
store.js
用于暴露一个store对象,整个应用只有一个store
/*
该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/
//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//暴露store
export default createStore(countReducer,applyMiddleware(thunk))
reducer.js
获取action中的action对象,接收prestate和action对象,同过action中的type匹配来执行不同的动作
/*
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import {INCREMENT,DECREMENT} from './constant'
const initState = 0 //初始化状态
export default function countReducer(preState=initState,action){
// console.log(preState);
//从action对象中获取:type、data
const {type,data} = action
//根据type决定如何加工数据
switch (type) {
case INCREMENT: //如果是加
return preState + data
case DECREMENT: //若果是减
return preState - data
default:
return preState
}
}
redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写使用subscribe
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
ReactDOM.render(<App/>,document.getElementById('root'))
store.subscribe(()=>{
ReactDOM.render(<App/>,document.getElementById('root'))
})
在组件中直接导入action然后分发
//加法
increment = ()=>{
const {value} = this.selectNumber
store.dispatch(createIncrementAction(value*1))
}
//减法
decrement = ()=>{
const {value} = this.selectNumber
store.dispatch(createDecrementAction(value*1))
}
react-redux
redux中的内容和上面一样,多了一个容器组件用来连接UI和redux
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rvvIvNvH-1627349634773)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\1626056509855.png)]
容器组件中的connect
connect()() 第一次调用传递两个参数mapStateToProps–映射状态,mapDispathToProps–映射操作状态的方法返回值是一个对象;第二次调用的参数是UI组件
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'
//引入connect用于连接UI组件与redux
import {connect} from 'react-redux'
//使用connect()()创建并暴露一个Count的容器组件
export default connect(
state => ({count:state}),
//mapDispatchToProps的一般写法
/* dispatch => ({
jia:number => dispatch(createIncrementAction(number)),
jian:number => dispatch(createDecrementAction(number)),
jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
}) */
//mapDispatchToProps的简写
{
jia:createIncrementAction,
jian:createDecrementAction,
jiaAsync:createIncrementAsyncAction,
}
)(Count)
## 5.求和案例_react-redux优化
(1).容器组件和UI组件整合一个文件
(2).无需自己给容器组件传递store,给包裹一个即可。
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)
(3).使用了react-redux后也不用再自己检测redux中状态的改变了subscribe,容器组件可以自动完成这个工作。
(4).mapDispatchToProps也可以简单的写成一个对象
(5).一个组件要和redux“打交道”要经过哪几步?
(1).定义好UI组件—不暴露
(2).引入connect生成一个容器组件,并暴露,写法如下:
connect(
state => ({key:value}), //映射状态
{key:xxxxxAction} //映射操作状态的方法
)(UI组件)
(4).在UI组件中通过this.props.xxxxxxx读取和操作状态
多个reducer
在store.js中使用combineReducers将reducers合并
import {createStore,applyMiddleware,combineReducers} from 'redux'
//汇总所有的reducer变为一个总的reducer
const allReducer = combineReducers({
he:countReducer,
rens:personReducer
})
在container中若要用其他的redux,就要在改文件暴露完
export default connect(
state => ({yiduiren:state.rens,he:state.he}),//映射状态
{jiaYiRen:createAddPersonAction}//映射操作状态的方法
)(Person)
1.对redux的理解,主要解决什么问题
redux是一种状态管理器,是一种解决组件通信和数据共享的解决方案,主要包含store–储存当前state的对象
action–接受state的改变指令;reducer–action的处理器,解决问题:1、组件通信、2.通过对象驱动组件进入生命周期
2.redux原理及工作流程
组件中通过store.dispath分发action给store,store接收到action后,将节后到的action和之前的state一起传递给reducer,reducer通过匹配action中的type,执行相应的操作,最后store改变state来进行页面数据驱动
2.redux原理及工作流程
3.redux中的异步请求怎么处理
4.redux怎么实现属性传递,介绍一下原理 发布者订阅者模式
5.redux中间键是什么,接收几个参数,科里化函数两端的参数具体是什么
6.redux请求中间键如何处理并发
7.redux状态管理器和变量挂载到window有什么区别
redux中的state要改变只能通多reducer,要出发reducer就需要触发相应的action,所以redux跟晒数据的入口只有action,数据是单向的,而window上锁挂载的数据是可以任意修改的,无限的,这样的程序非常不可控
8.mobox和redux有什么区别
store是应用管理数据的地方,在Redux应用中,我们总是将所有共享的应用数据集中在一个大的store中,而Mobx则通常按模块将应用状态划分,在多个独立的store中管理。
9.redux和vuex有什么区别,他们的共同思想是什么
10.redux中间键是怎么拿到store和action的,然后怎么处理
11.redux中的connect有什么作用
hooks
1.statehook
让函数式组件也可以有state状态,并进行状态数据的读写操作
const [count,setCount] = React.useState(0)
function add(){
//setCount(count+1) //第一种写法
setCount(count => count+1 )
}
uesState:参数是第一次初始化的值,返回值是包含两个元素的数组,第一个为内部当前状态值,2个是更新状态值的函数
2.effect hook
让函数式组件有生命周期函数
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等 相当于componentWillUNmount
}
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行相当于componentDidMount,有值的话就相当于componentUpdate
React.useEffect(()=>{
let timer = setInterval(()=>{
setCount(count => count+1 )
},1000)
return ()=>{
clearInterval(timer)
}
},[])
3.ref hook
储存、查找组件内的标签或任意其他数据
语法: const refContainer = useRef()
作用:保存标签对象,功能与React.createRef()一样
const myRef = React.useRef()
//提示输入的回调
function show(){
alert(myRef.current.value)
}
<input type="text" ref={myRef}/>
1.对react hook的理解,他的原理是什么
2.为什么useState要使用数组而不是对象
3.react hook解决了哪些问题
Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数
4.react hook 的使用限制有哪些
5.useEffect与useLayoutEffect的区别
6.react hook在平时开发中需要注意哪些问题,原因是什么
7.react hooks和声明周期的关系
render props
实现自荐内部动态传入带内容的结构、标签,相当于vue中的slot
受控数据指的是组件中通过props传入的数据,受到父组件的影响
基础组件
1.react事件机制
2.react的事件和普通事件有什么不同
- React 中的事件机制分为两个阶段:事件注册、事件分发。所有的事件都会注册到 document 上,然后使用统一的回调函数
dispatchEvent
来执行分发。 **采用事件代理的模式:在根节点document上为每种事件添加唯一的Listener,然后通过事件的target找到真实的触发元素。**这样从触发元素到顶层节点之间的所有节点如果有绑定这个事件,React都会触发对应的事件处理函数。这就是所谓的React模拟事件系统。 - 在 HTML 中,事件名称使用小写,而 React 中使用驼峰命名。
- 在 HTML 中,阻止事件的默认行为使用
return false
,而 React 中必须调用preventDefault