react
- 说说react中onClick绑定后的工作原理
- react中的性能优化
- react里面bind与箭头函数
- 高阶组件和高阶函数是什么
- 类组件setState是同步还是异步
- setState和replaceState的区别
- redux三大核心
- 什么是受控组件
- hooks+context和redux你是怎么选择的,都在上面场景下使用
- useffect模拟生命周期
- setState更新之后和useState的区别
- react父组件props变化的时候子组件怎么监听
- usememo在react中怎么使用
- Hooks
- Component和Purecomponent区别
- hooks相对于class的优化
- hooks父组件怎么调用子组件的方法
- react通过什么方法修改参数
- react native
- redux的实现原理
- react的render什么时候渲染
- useEffect的依赖为引用类型如何处理
- Hooks需要注意的
- 原生JS
- Vue
说说react中onClick绑定后的工作原理
- 首先react有自己的事件系统,也是遵循w3c的,这个事件系统的名称叫做合成事件(SyntheticEvent),而其自定义事件系统的动机主要包含以下几个方面
抹平不同浏览器之间的兼容性差异。最主要的冬季
既可以处理兼容性问题
提供一个抽象的跨平台事件机制
可以做更多优化
可以干预事件的分发
- 当给组件(元素)绑定onClick事件之后
react会对事件先进行注册,将事件统一注册到document上
根据组件唯一的标识key来对事件函数进行存储
统一的指定dispatchEvent回调函数
储存事件回调:react会将click这个事件统一存到一个对象中,回调函数的存储采用键值对(key/value)的方式存储在对象中,key是组件的唯一标识id,value对应的就是事件的回调函数,通过组件的key就能回调到相应的函数了
react中的性能优化
- 使用shouldComponentUpdate来对state和props进行对比,如果两次的结果一致,那么就return false
- 使用纯净组件pureComponent
react里面bind与箭头函数
- bind由于在类中采用的是严格模式,所以事件回调的时候会丢失this指向,指向undefined,需要使用bind来给函数绑定上当前实例的this指向
- 箭头函数的this指向上下文,所以永久能拿到当前组件实例的this指向,我们可以完美的使用箭头函数来替代传统事件处理函数的回调
高阶组件和高阶函数是什么
- 高阶函数:函数接收一个函数函数作为参数,或者将函数作为返回值的函数就是高阶函数 map some every filter reduce find forEach等都属于高阶函数
- 高阶组件:接受一个组件,返回一个新组建的组件就是高阶组件,本质上和高阶函数一样
- 高阶组件是用来复用react代码的一种方式
类组件setState是同步还是异步
- 使用合成事件setState是异步的,想要拿到最新数据需要去回调
- 使用原生事件setState是同步的
setState和replaceState的区别
setState是修改其中的部分状态,相当于Object.assign,只是覆盖,不会减少原来的状态;replaceState是完全替换原来的状态,相当于赋值,将原来的state替换成另一个对象,如果新状态属性减少,那么state中就没有这个状态了
redux三大核心
action
action理解为动作,action的值一般为一个对象,格式如{ type:“”, data:“” },type是必须要的,因为reducer处理数据的时候要根据不同的type来进行不同操作
reducer
reducer是初始化以及处理派发的action的纯函数,作用是接收旧的state和action,返回新的state
store
store是一个仓库,用来存储数据,它可以获取数据,也可以派发数据,还能监听到数据的变化
什么是受控组件
受控组件就是可以被react状态控制的组件
在react中,Input textarea等组件默认是非受控组件(输入框内部的值是用户控制,和React无关)。但是也可以转换成受控组件,就是通过onChange事件获取当前输入内容,将当前输入内容作为value传入,此时就称为受控组件
hooks+context和redux你是怎么选择的,都在上面场景下使用
如果项目体量较小,只是需要一个公共的store存储state,而不讲究使用action来管理state,那context完全可以胜任。反之,则是redux的优点。
使用场景:
组件间传递的数据逻辑比较复杂,可以使用redux
组件层级不多,可以使用props
层级较深,数据逻辑简单,可以使用context
useffect模拟生命周期
- 模拟componentDidMount
第二个参数为一个空数组,可以模拟componentDidMount
componentDidMount:useEffect(()=>{console.log(‘第一次渲染时调用’)},[ ])
- 模拟componentDidUpdate
没有第二个参数代表监听所有的属性更新
useEffect(()=>{console.log(‘任意状态改变’)})
监听多个属性的变化需要将属性作为数组传入第二个参数
useEffect(()=>{console.log(‘指定状态改变’)},[状态1,状态2…])
-模拟componentWillUNmount
useEffect(()=>{ … return()=>{ //组件卸载前} })
setState更新之后和useState的区别
- setState( updater [,callback])
updater:object/function 用于更新数据
callback:function 用于获取更新后最新的state值
构造函数是唯一建议给this.state赋值的地方
不建议直接修改state的值,因为这样不会重新渲染组件
自动进行浅合并(只会合并第一层)
由于setState()异步更新的缘故,依赖state旧值更新state的时候建议采用传入函数的方式
- useState(initState)
const [ state , setState ] = useState(initState)
state:状态
setState(updater):修改状态的方法
updater:object/function 用于更新数据
initState:状态的初始值
react父组件props变化的时候子组件怎么监听
当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用
//props发生变化时触发
componentWillReceiveProps(props) {
console.log(props)
this.setState({show: props.checked})
}
usememo在react中怎么使用
返回一个memoized值
把“创建”函数和依赖项数作为参数传入useMemo,它仅会在某个依赖项改变时才重新计算memoized值。这种优化有助于避免在每次渲染时都进行高开销的计算
传入useMemo的函数会在渲染期间执行。请不要再这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于useEffect的使用范畴,而不是useMemo
如果没有提供依赖项数组,useMemo在每次渲染时都会计算新的值
可以把useMemo作为性能优化的手段,但不要把它当成语义上的保证。将来React可能会选择“遗忘”以前的一些memoized值,并在下次渲染时重新计算它们,比如为离屏组件释放內存。先编写在没有useMemo的情况下也可以执行的代码 —— 之后再在你的代码中添加useMemo,以达到优化性能的目的。
Hooks
- useState
useState是用于声明一个状态变量的,用于为函数组件引入状态
useState只接收一个参数,这个参数可以是数字、字符串、对象等任意值,用于初始化声明的状态变量。也可以是一个返回初始值的函数,最好是函数,可以在渲染时减少不必要的计算
返回一个长度为2的读写数组,数组的第一项是定义的状态变量本身,第二项是一个用来更新该状态变量的函数,约定是set前缀加上状态的变量名
useState Hook中返回的setState并不会帮我们自动合并对象状态的属性
useState中接收的对象参数如果地址没变的话会被React认为没有改变,因此不会引起视图的更新
- useReduser
useReducer是useState的升级版。在useState中返回的接口中,我们只能传递最终的结果,在setN的内部也只是简单的赋值操作
创建初始状态值initialState
创建包含所有操作的reducer(state,action)函数,每种操作类型均返回新的state值
根据initialState和reducer使用const [ state, dispatch ] = useReducer(reducer,initialState)得到读写API
调用接口,传递的参数均挂在action对象上
- useContext
context是上下文,上下文是局部的全局变量,这个局部的范围由开发者自己定义
- useEffect
effect是副作用的意思,对环境的改变就是副作用。副作用是函数式编程里的一个概念
在React中,useEffect就是在每次render后执行的操作,相当于afterRender,接收的第一个参数是回调函数,第二个参数是回调时机。可用在函数组件中模拟生命周期。
如果同时出现多个useEffect,会按出现顺序依次执行
- useLayoutEffect
useEffect总是在浏览器渲染完视图过后才执行,如果useEffect里面的回调函数有对DOM视图的操作,则会出现一开始是初始化的视图,后来执行了useEffect里的回调后立马改变了视图的某一部分,会出现一个闪烁的状态。
为了避免这种闪烁,可以将副作用的回调函数提前到浏览器渲染视图的前面执行,当还没有将DOM挂载到页面显示前执行Effect中对DOM进行操作的回调函数,则在浏览器渲染到页面后不会出现闪烁的状态。
layout是视图的意思,useLayoutEffect就是在视图显示处理前执行的副作用
useEffect和useLayoutEffect就是执行的时间点不同,useLayoutEffect是在浏览器渲染前执行,useEffect是在浏览器渲染后执行。但二者都是在render函数执行过程中运行,useEffect是在render完毕后执行,useLayoutEffect是在render完毕前(视图还没渲染到浏览器页面上)执行。因此useLayoutEffect总是在useEffect前执行
一般情况下,如果Effect中的回调函数中涉及到DOM视图的改变,就应该用useLayoutEffect,如果没有,则用useEffect
- useRef
useRef Hook是用来定义一个组件在不断render时保持不变的变量
组件每次render后都会返回一个虚拟DOM,组件内对应的变量都只属于那个时刻的虚拟DOM。
useRef Hook提供了创建贯穿整个虚拟DOM更新历史的属于这个组件的局部的全局变量
为了确保每次render后使用useRef获得的变量都能是之前的同一个变量,只能使用引用做到,因此,useRef就将这个局部的全局变量的值存储到了一个对象中,属性名为current
useRef的current变化时不会自动render
useRef可以将创建的Refs对象通过ref属性的方式引用到DOM节点或者React实例
- useCallback
将某个函数“放入到react底层原型链上,并返回该函数的索引”,而useMemo是将某个函数返回值“放入到react底层原型链上,并返回该返回值的索引”。一个是针对函数,一个是针对函数返回值
- uselmperativeHandle
uselmperativeHandle可以让父组件获取并执行子组件内某些自定义函数(方法)。本质上其实是子组件将自己内部的函数(方法)通过uselmperaativeHandle添加到父组件中useRef定义的对象中
- useMemo
useMemo可以将某些函数的计算结果(返回值)挂载到react底层原型链上,并返回该函数返回值的索引。当组件重新渲染时,如果useMemo依赖的数据变量未发生变化,那么直接使用原型链上保存的该函数计算结果,跳过本次无异议的重新计算,达到提高组件性能的目的
Component和Purecomponent区别
Component没有直接实现shouldComponentUpdate这个方法;但是PureComponent通过浅层的Porps和state的对比,内部实现了这个生命周期函数
PureComponent会跳过整个组件子树的props更新,要确保全部的子组件也是pure形式
Component中需要手动执行的shouldComponentUpdate函数,在PureComponent中已经自动完成了(自动浅对比)
PureComponent不仅会影响本身,而且会影响子组件,所以PureComponent最好用在数据展示组件中
PureComponent如果是复杂数据类型,这里会造成错误的提示(setState浅复制更新,但是界面不会重新渲染)
hooks相对于class的优化
- 类组件缺点一:复杂且不容易理解的“this”
Hooks解决方式:函数组件和普通JS函数非常相似,在普通JS函数中定义的变量、方法都可以不适用“this”,而直接适用该变量或函数,因为不需要去关心“this”了
- 类组件缺点二:组件数据状态逻辑不能重用
Hooks解决方式:通过自定义Hook,可以将数据状态逻辑从组件中抽离出去,这样同一个Hook可以被多个组件使用,解决组件数据状态逻辑并不能重用的问题
- 类组件缺点三:组件之间传值过程复杂,复杂场景下代码难以阻止在一起
Hooks解决方式:通过React内置的useState()函数,可以将不同数据分别从“this.state”中独立拆分出去。降低数据复杂度和可维护性,同时解决类组件缺点中“内部state数据只能是整体,无法被拆分更细”的问题
通过React内置的useEffect()函数,将componentDidMount、componentDidUpdate、componentWillUncount三个生命周期函数通过Hook(钩子)关联成1个处理函数,解决事件订阅分散在多个生命周期函数的问题
hooks父组件怎么调用子组件的方法
父组件使用useRef创建一个ref传入子组件
子组件需要使用useImperativeHandle暴露ref自定义的实例值给父组件。这个需要用forwardRef包裹着。
react通过什么方法修改参数
类组件修改数据的方法是通过setState
setState的修改方法有两种,而且它是异步的
函数组件修改方式通过自定义方法。需要通过useState,hooks
react native
React native基于JavaScript开发的一个可以开发原生app的集成框架,它兼容开发IOS和Android,能够实现一套代码,两个系统都能使用,方便维护,相比web前端的react,react-native更好的提供了一些调用手机硬件的API,可以更好的开发移动端,现在react-native它的生态环境也是越来越好,基本上可以完全实现原生开发
但是现在很多的应用还是用它来套壳(原生+web前端),用它来做有些路由,和框架的搭建,然后里面内容来使用前端的react来实现,这样一来让维护更方便,开发更便捷
redux的实现原理
redux它是一个单独的状态管理工具,它是一个数据集中管理的方案,简单的说,就是将公用的数据,放在redux里面进行存储,修改的时候也是利用redux提供的方法来修改,让框架使用的数据的时候更方便,维护起来更容易,redux提供了以下核心内容
- store
store是redux的核心内容,整个redux的仓库,所有的应用方法都是由store提供
- createStore
createStore用于创建store,方法里面有三哥参数,有reducer,有中间件,还有初始值,最重要的就是reducer函数,它提供了整个数据管理的逻辑
- reducer(state,action)
reducer函数相当于数据加工厂,初始的数据,修改数据的逻辑都统统的在这里完成,它让我们整个的数据走向更完整,维护更方便
- action
action本质是一个对象,它来告诉redux要执行什么任务
- state
state它就是我们需要存储的redux数据,所有的数据都将要在这里面存储
- store.getState()
它就是用来获取数据的,每次修改前后的数据都可以用store.getState()来修改
- store.dispatch(action)
用户通过dispatch触发要执行的任务,这个就是触发动作,然后reducer函数会执行,然后进行数据加工
- store.subscribe(callback)
会自动的监听state,一旦有state发生改变,store.subscribe就回执行,利用它可以用来更新视图
react的render什么时候渲染
react生命周期有三个阶段,两个阶段都会执行render
主要从更新和挂载两个阶段来讲,挂载阶段的顺序,更新阶段一定要说shouldComponentUpdate,true和false分别对应后边是否执行render
1) 挂载阶段
constructor(){}
static getDerivedStateFromProps(){
return {}
}
render(){}. 挂载阶段会执行一次
componentDidMount(){}
2 ) 更新阶段
static getDerivedStateFromProps(props, state){rerturn {}}
shouldComponentUpdate(nextProps, nextState).{ return Boolean. 注意如果 false 则
不向下执行 ,true的时候会执行render}
return。true
render() …
useEffect的依赖为引用类型如何处理
useEffect的依赖为引用类型的时候,可能会导致监听不触发,原因就是监听的同一个地址的时候,对象本身地址没变,所以监听的结果就是任务数据并没有改变从而不直接调用
解决方案
1.如果是数据是对象的话,可以监听对象里面的值,值是基本类型,如果值改变了,那么可以监听执行
2.在去修改对象和数据的时候,使用深拷贝或者浅拷贝,这样地址发送改变可以监听执行
3.可以转成字符串,通过JSON.stringify(),监听字符串,这样改变也会执行
Hooks需要注意的
- 首先要注意的就是useState里面方法是异步的,所以不要在后面连续调用,由于react方法是批量异步调用,并不是每次调用修改方法都执行,所以需要用到callback写法
const [count, setCount] = useState(0)
const add = () => {
setCount(count + 1)
setCount(count + 1)
setCount(count + 1)
setCount(count + 1) //就算执行多次,其实还是只会执行一次
//clas组件是一样的
}
// 修改后
const add = () => {
setCount(count => count + 1); //这种回调函数的写法
setCount(count => count + 1);
setCount(count => count + 1);
setCount(count => count + 1);
// class组件
this.setState(prev => ({ count: prev.count }))
};
- 由于useState是异步的,不要在修改后直接使用数据,可以先修改数据,判断数据,也可以利用useEffect,useMemo等等通过监听数据执行
const [count, setCount] = useState(0);
const add = () => {
setCount(count + 1);
if (count >= 10) { // 一个逻辑 这样的写的话 会执行上一次的结果}
};
// 正确使用 1
const add = () => {
let n = count + 1
if (n) {
//逻辑
}
setCount(n)
};
// 正确2 :
const add = () => [
setCount(count + 1)
]
useEffect(() => {
// 这里是逻辑
}, [count])
- useEffect这个hook的使用,每一个消耗性能的内容都可以通过return来消除
useEffect(() => {
// 逻辑1
return () => {
// 清楚逻辑1的副作用
}
}, [/* 监听的值 */])
- useRef可以获取组件的数据,也可当常量的值来使用,注意获取数据使用的时候函数组件特别需要注意,如果子组件是函数组件需要利用useImperativeHandle,forWard