react face to face

React面试题 

创建一个react项目

1.全局安装create-react-app
npm install -g create-react-app
2.创建项目
create-react-app myapp
3.局部安装,可以直接用npx
npx create-react-app myapp
4.进入文件夹
cd myapp
5.启用项目
npm start(开发模式下运行)
npm test(测试环境运行)
npm run build(打包为生产模式)
6.显示配置文件:不可逆的,只要显示了就没有任何方法再隐藏回去
npm run eject

 这里需要等待一段时间,实际上会安装三个东西

  • react:react的顶级库
  • react-dom:因为react有很多的运行环境,比如app端的react-native,我们要在web上运行就使用react-dom
  • react-script:包含运行和打包react应用程序的所有脚本及配置 

1.React是什么?

用来构造用户界面的JS库 

2.React有什么特点?(react的主要功能有哪些?)

它用于虚拟DOM,组件化设计模式,声明式代码,单向数据流,使用jsx描述信息等特点

3.什么是组件化设计模式?

可复用的代码可以抽成组件共同使用(UI,方法等) 

4.声明式代码(编程)思想:

就是说明下你的目的,然后具体不说明怎么去做。

举例子:去酒吧告诉服务员你要一杯鸡尾酒,服务员把做好的鸡尾酒给你,并没有说做的过程是怎样的
const toLowerCase = arr = arr.map(
    value => value.toLowerCase();
)

5.还有其他的编程方式吗?

命令式编程:就是描述代码如何工作,告诉计算机一步步的执行,先做什么后做什么。

举例子:去酒吧点一杯酒,指挥服务员

从架子上取下一个玻璃杯
把杯子放在酒桶前
打开酒桶开关,直到酒杯杯满
把做好的鸡尾酒递给顾客
const toLowerCase = arr => {
    const res = [];
    for (let i = 0, len = arr.length; i < len; i++) {
        res.push(arr[i].toLowerCase());
    }
    return res;
}

6.React事件处理的几种方法(如何创建一个事件)

import React from 'react'
class Test extends React.Component{
    
    handleClick2(){
        console.log('click2')
    }

    hangleClick4 = () =>{
        console.log('click4')
    }
    render(){
        return(
            <button onClick={ console.log('click1')}>click1</button>
            <button onClick={ this.handleClick2.bind(this)}>click2</button>
            <button onClick={ () => {console.log('click3')}>click3</button>
            <button onClick={ this.hangleClick4 }>click3</button>
        )
    }
}
export default Test

 66.介绍Redux数据流的流程 (重要)

Redux如何实现多个组件之间的通信,多个组件使用相同状态如何进行管理  

redux是js状态容器

工作流程:

  • View在redux中会派发action方法
  • action通过store的dispatch方法会派发给store
  • store接收action,连同之前的state,一起传递给reducer
  • reducer返回新的数据给store
  • store去改变自己的state

Redux——详解_Mr.指尖舞者的博客-CSDN博客_redux

Redux原理及工作流程_QcoY_的博客-CSDN博客_redux工作流程

67.Hooks常用的 

useEffct使用:
如果不传参数:相当于render之后就会执行
传参数为空数组:相当于componentDidMount
如果传数组:相当于componentDidUpdate
如果里面返回:相当于componentWillUnmount
会在组件卸载的时候执行清除操作。effect 在每次渲染的时候都会执行。React 会在执行当前 effect 之前对上一个 effect 进行清除。

useLayoutEffect:
useLayoutEffect在浏览器渲染前执行
useEffect在浏览器渲染之后执行

当父组件引入子组件以及在更新某一个值的状态的时候,往往会造成一些不必要的浪费,
而useMemo和useCallback的出现就是为了减少这种浪费,提高组件的性能,
不同点是:useMemo返回的是一个缓存的值,即memoized 值,而useCallback返回的是一个memoized 回调函数。


useCallback
父组件更新子组件会渲染,针对方法不重复执行,包装函数返回函数;

useMemo:
const memoizedValue =useMemo(callback,array)
callback是一个函数用于处理逻辑
array 控制useMemo重新执⾏行的数组,array改变时才会 重新执行useMemo
不传数组,每次更新都会重新计算
空数组,只会计算一次
依赖对应的值,当对应的值发生变化时,才会重新计算(可以依赖另外一个 useMemo 返回的值)
不能在useMemo⾥面写副作⽤逻辑处理,副作用的逻辑处理放在 useEffect内进行处理

自定义hook
自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook,
自定义 Hook 是一种自然遵循 Hook 设计的约定,而并不是 React 的特性
在我看来,自定义hook就是把一块业务逻辑单独拿出去写。

 const [counter, setCounter] = useState(0);
 const counterRef = useRef(counter);  // 可以保存上一次的变量

useRef 获取节点
function App() {
    const inputRef = useRef(null);

    return <div>
        <input type="text" ref={inputRef}/>
        <button onClick={() => inputRef.current.focus()}>focus</button>
    </div>
}

7.什么是单向数据流 

数据主要从父节点传到子节点(通过props),如果父级的某个props改变了,React会重新渲染所有子节点

若子组件想要改版父子组件的值应该如果去做呢?
如下:event事件,子组件是不能够在自己的组件中去修改父组件的值,所以子组件中可以通过调用父组件的方法在父组件的方法中修改父组件的值

// 父组件
import React, {Component} from 'react'
import Child from './Child'
class Parent extends Component{   
    // 初始化
    constructor(props){
        super(props)
        this.state = {
            message: '我是从父组件传过来的'
        }
    } 
    
    handleUpdate = () =>{
        this.setState({
            message: '子组件修改父组件的值'
        })
    }
    // 渲染
    render(){
        return(
            <div>
                <Son msg={this.state.message} event={this.handleUpdate()}/>
            </div>
        )
    }
}
export default Parent


// 子组件
import React, {Component} from 'react'
class Child extends Component{  
    // 初始化
    constructor(props){
        super(props)
    } 
    // 渲染
    render(){
        return(
            <div>
               {this.props.message}
                <button onClick={() =>{this.props.event()}}>子组件调用父组件的方法</button>
            </div>
        )
    }
}
export default Child

8.什么是JSX呢?JSX代码到显示内容的转换过程

JSX就是JS的扩展语言(jsx语法= js语法+xml(html)语法)

是JS的语法扩展,本质上是JS对象。JSX可以很好的描述UI信息,但是浏览器无法直接读取,编译过程中会将JSX转换成JS的语法。

render(){
    return(        
        <div>
            <h1> Hello World from Edureka!!</h1>
        </div>
    );
}

9.react的优缺点

优点:

  • 提高了应用性能和开发效率
  • 使用JSX,代码可读性好
  • react的componentWillUnmount生命周期,能够清除相关所有事件,避免内存泄露
  • 并不直接对DOM进行操作,引入了一个虚拟DOM的概念,安插在js和真实DOM中间,性能好,速度快 

缺点:

每次 state 更改,render 函数都要生成完整的虚拟 DOM. 哪怕 state 改动很小,render函数也会完整计算一遍。如果 render 函数很复杂,这个过程就白白浪费了很多计算资源

react 缺点_不玩微博的jason2的博客-CSDN博客_react缺点

10.VUE与React两个框架的区别对比 

相似之处:

  • 用于创建UI的js库
  • 使用起来轻快便捷
  • 都用了虚拟DOM
  • 都是基于组件的架构 

不同点 :

  • vue使用的html模板;react使用的是js
  • vue有双向绑定语法
  • vue增加了语法糖computed和watch等,react需要自己写逻辑来实现
  • react用了jsx语法
  • react整体思路是编程式,推荐组件化,数据不变,单向数据流;vue数据可变,双向绑定,声明式的写法

react使用的是js 

11.React的工作原理  

React会创建一个虚拟的DOM。当一个组件的状态改变时,React首先会通过“diffing"算法来标记虚拟DOM中的改变,第二步是调节,会用diff的结果来更新DOM.

12.阻止React的默认行为  

e.preventDefault(),e是第三方提供的一个合成事件(注意:不能用return)

class App extends React.component{
constructor(props){
super(props);
this.state = {
}
}

hander(e){
e.preventDefault()
}
render(){
return <button onClick={ this.hander.bind(this) }>阻止事件</button>
}
}

13.向事件处理程序传递参数 

例如删除当前行的ID

<button onClick={(e) => this.delete(e,id)}>Delete Row<button>
<button onClick={this.delete.bind(this,id)}>Delete Row</button>

14.React中key作用是什么? 

主要用于列表中元素被修改,删除或添加的标识。在diff算法中,key用来判断该元素节点是被删除还是创建减少不必要的元素重复渲染。

15.React中diff算法 

作用:用来计算VirtualDOM中被改变部分,针对该部分进行原生DOM操作,不用重新渲染整个页面

深入理解React虚拟DOM - 110255 - 博客园

16.props和state

  • state是数据结构,只能使用setState来改变
  • props是组件的属性,由父组件传递给子组件,props是不可以改变的 

state是局部的,除了它所在的这个组件其它组件都无法访问

  • 无状态组件:没有设置state的组件(无状态组件通过函数式声明来构建,一个函数就是一个组件)
  • 有状态组件:设置了state的组件(有状态组件通过component来构建,一个子类就是一个组件)

17.React可以用两种方法声明组件,他们的区别是什么,什么情况你会选择哪一种?

  • 函数组件:首字母大写,需要return出react元素
  • 类组件:首字母大写,需要使用render方法,return出react元素

区别:

  • 函数组件是无状态组件的思想
  • 函数组件中不能用State,不能用组件的生命周期方法,这就决定了函数组件都是展开性组件,接收props,渲染DOM,而不关注其它逻辑
  • 函数组件中没有this
  • 函数组件更容易理解。当你看到一个函数组件时,你就知道它的功能只是接收属性,渲染页面,它不执行与UI无关的逻辑处理,它只是一个纯函数
// 函数组件
function Welcome(props){
return (
<h1>hello world</h1>
)
}


// 类组件:es6的加入让js直接支持使用class来定义类,react创建组件的方式是使用继承,官网推荐这种
// 使用方式,使用es6标准语法来构建
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component{
        render(){
            return (
            <div>欢迎进入react组件</div>
        )
    }
}
ReactDOM.render(
    <App />,document.getElementById('root')
)

18.React组件生命周期的阶段是什么?

  1. 初始渲染阶段:组件将开始生命之旅并进入 DOM 阶段
  2. 更新阶段:一旦组件被添加到 DOM,它只有在 prop 或状态发生变化时才能更新和重新渲染
  3. 卸载阶段:组件生命周期最后阶段,组件被销毁并从 DOM 中删除
  • constructor:在构造函数中初始化props和state
  • componentWillMount:组件渲染之前执行,对state进行最后修改
  • render:渲染
  • componentDidMount: 组件渲染之后执行
  • componentWillReceiveProps:这个周期函数作用于特定的 prop 改变导致的 state 转换
  • shouldComponentUpdate:用来做性能优化,根据特定条件返回 true 或 false。如果你希望更新组件,请返回true 否则返回 false。默认情况下,它返回 false。
  • componentWillUpdate:数据在改变之前执行
  • componentDidUpdate:渲染发生后立即调用
  • componentWillUnmount:从 DOM 卸载组件后调用。用于清理内存空间

class Timer extends React.Component {
    constructor(props) {
        super(props)
        this.state = {seconds: 0}
    }

    tick(){
        this.setState(state =>({
            seconds: state.seconds + 1
        }))
    }

   componentDidMount() {
        this.interval = setInterval(() => this.tick(),1000)
    }
    
    componentWillMount(){
        clearInterval(this.interval);
    }

    render() {
        return (
            <div>    Seconds: {this.state.seconds}  </div>
        )
    }
}

 在react17 会删除以下三个生命周期
componentWillMount,componentWillReceiveProps , componentWillUpdate

19.什么是单向数据流和状态提升

  • 单向数据流:从上往下父组件将state数据流向子组件,子组件通过props取值
  • 状态提升:组件之间的数据交互(很多子组件想用这个状态,将这个状态提升到最上面,通过props谁用给谁)

举例子:如果两个组件都需要用到对方的状态,那么这时候就可以用到状态提升。具体做法是把两个子组件的状态写到他们的父组件中,然后父组件把状态传递给子组件的props中去,这样子组件也相当于有状态。

父组件

import React from "react"
import Child1 from "./child1"
import Child2 from "./child2"

export default class Parent extends React.Component {

    constructor() {
        super()
        this.state = {
            money: 1
        }
    }

    changeHander(e){
        this.setState({
            money: e.target.value
        })
    }
    render() {
        return (
            <div>
                <input type="text" value={ this.state.money } onChange={this.changeHander.bind(this)} />
                <p>Parent</p>
                人民比: <Child1 money={this.state.money} />
                美金: <Child2 money={this.state.money} />
            </div>
        )
    }
}

 子组件1

import React from "react"

export default class Child1 extends React.Component{

    constructor(){
        super()
        this.state = {
            input1: 0
        }
    }

    componentDidMount(){
        this.setState({
            input1: this.props.money
        })
    }

    changeHander(e) {
        this.setState({
             input1: e.target.value
        })
    }

    render() {
        return(
            <div>
                 { this.props.money }
               <input type="text" value={ this.state.input1 } onChange={ this.changeHander.bind(this) }/>
            </div>
        )
    }
}

 子组件2

import React from "react"

export default class Child2 extends React.Component{

    constructor(){
        super();
        this.state = {
            input2: 1
        }
    }

    componentDidMount(){
        this.setState({
            input2: this.props.money * 7
        })
    }

    changeHander(e) {
        this.setState({
             input2: e.target.value
        })
    }
    render() {
        return(
            <div>
                { this.props.money * 7}
               <input type="text" value={ this.state.input2 } onChange={ this.changeHander.bind(this) }/>
            </div>
        )
    }
}

20.调用setState之后发生了什么

setState会进行状态更新

将传入的参数对象与组件当前状态合并,然后触发所谓的调和过程,经过调和过程,根据新的state,React元素会重新构建虚拟DOM,进行diff算法对比新旧虚拟DOM树的区别,进行视图更新,而不是全部渲染

setState 采用的任务队列机制,不会马上执行,而是加入队列,在下次事件循环是一次性执行

21.为什么建议传递给setState的参数是一个callback(回调函数)而不是一个对象

this.props和this.state的更新可能是异步的,不能依赖他们的值去计算下一个state

22.关于this绑定==组件绑定点击事件

// bind
// 1
<button onClick={this.handleClick.bind(this)}>hello<button/>
// 2
clicked(param,event){
    console.log(param) //hello world
    console.log(event.target.value) //按钮
}
render(){
    return (
        <React.Fragment>
            <button value="按钮" onClick={this.clicked.bind(this,"hello world")}>点击</button>
        </React.Fragment>
    )
}


// 2.在构造函数中默认绑定this(推荐)
this.handleClick = this.handleClick.bind(this)

// 3.使用箭头函数来处理,handleClick点击事件的方法
<button onClick={(e) => this.handleClick(e)}>Click me</button>

23.setState第二个参数的作用 

该函数会在setState函数调用完成并且组件开始重渲染的时候被调用,我们可以用该函数来监听渲染是否完成

24.(在构造函数中)调用 super(props) 的目的是什么

 在super() 被调用之前,子类是不能使用 this 的,在 ES5 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props

25.什么是React 路由?

Router 用于定义多个路由,当用户定义特定的 URL 时,如果此 URL 与 Router 内定义的任何 “路由” 的路径匹配,则用户将重定向到该特定路由。

路由是根据不同的url地址展示不同的内容或页面

import React from 'react';
import { Switch, Route, BrowserRouter } from 'react-router-dom';
import Home from './views/Home'

export default class App extends React.Component{
    // 初始化
    constructor(props){
        super(props);
        this.state = {}
    }
    // 渲染
    render(){
        return(
           <BrowserRouter>
               <Switch>
                   <Route component={Home} path="/" />
               </Switch>
           </BrowserRouter>
        )
    }
}

26. 区分Real DOM和Virtual DOM

Real DOM Virtual DOM
1.更新缓慢 1.更新更快
2.可以直接更新HTML 2.无法直接更新HTML
3.如果元素更新,则创建新DOM 3.如果元素更新,则更新JSX
4.DOM操作代价很高 4.DOM操作很简单
5.消耗的内存较多 5.很少消耗内存

27.为什么浏览器无法读取JSX? 

浏览器只能处理JS对象,而不能读取常规的JSX。为了使浏览器能够读取JSX,首先,需要像Babel这样的JSX转换器将JSX转换为JS对象,然后再传给浏览器

28.你理解“在React中,一切都是组件”这句话。

组件是React应用UI的构建块。这些组件将整个UI分成小的独立并可重用的部分。每个组件彼此独立,而不会影响UI的其余部分

29.解释 React 中 render() 的目的。

接收数据和返回展示的内容

class HelloMessage extends React.Component {
  render() {
    return (
      <div>
        Hello {this.props.name}
      </div>
    );
  }
}

ReactDOM.render(
  <HelloMessage name="Taylor" />,
  document.getElementById('hello-example')
);

30.什么是 Props?

只读组件,必须保持纯函数,即不可变。它们总是再整个应用中从父组件传递到子组件。子组件永远不能将prop送回到父组件。这有助于维护单向数据流,通常用于呈现动态生成的数据

31.React中的状态是什么?它是如何使用的? 

是React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props不同,它们是可变的,并创建动态和交互式组件。可以通过this.state()访问它们。

32.区分状态和 props

条件 State Props
1.从父组件中接收初始值 Y Y
2.父组件可以改变值 N Y
3.在组件中设置默认值 Y Y
4.在组件的内部变化 Y N
5.设置子组件的初始值 Y Y
6.在子组件的内部更改 N Y

33.如何更新组件的状态? 

  • 可以用 this.setState()更新组件的状态。
  • replaceState也可以改变 
class MyComponent extends React.Component {
    constructor() {
        super();
        this.state = {
            name: 'Maxx',
            id: '101'
        }
    }
    render()
        {
            setTimeout(()=>{this.setState({name:'Jaeha', id:'222'})},2000)
            return (              
				<div>
                	<h1>Hello {this.state.name}</h1>
					<h2>Your Id is {this.state.id}</h2>
                </div>
            );
        }
    }
ReactDOM.render(
    <MyComponent/>, document.getElementById('content')
);



 class App extends React.Component{

     constructor(props);
      this.state={
      count:1
          title:'数字计算'
      }
}

handleClick=()=>{
  this.replaceState({
    count:this.state.count+1
  })
}

render(){
    return(
      <button onClick={this.onClick}>点我</button>
      )
  }
}

count:1

34.React 中的箭头函数是什么?怎么用?

用于编写函数表达式的简短语法。这些函数允许正确绑定组件的上下文,因为在ES6中默认下不能使用自动绑定。使用高阶函数时,箭头函数非常有用

//General way
render() {    
    return(
        <MyInput onChange = {this.handleChange.bind(this) } />
    );
}
//With Arrow Function
render() {  
    return(
        <MyInput onChange = { (e)=>this.handleOnChange(e) } />
    );
}

35.区分有状态和无状态组件。 

有状态组件 无状态组件
1.在内存中存储有关组件状态变化的信息 1.计算组件的内部状态
2.有权改变状态 2. 无权改变状态
3. 包含过去、现在和未来可能的状态变化情况 3. 不包含过去,现在和未来可能发生的状态变化情况
4. 接受无状态组件状态变化要求的通知,然后将 props 发送给他们。 4.从有状态组件接收 props 并将其视为回调函数。

40.React中的事件是什么?

 在 React 中,事件是对鼠标悬停、鼠标单击、按键等特定操作的触发反应。处理这些事件类似于处理 DOM 元素中的事件。但是有一些语法差异,如:

  1. 用驼峰命名法对事件命名而不是仅使用小写字母
  2. 事件作为函数而不是字符串传递

事件参数重包含一组特定于事件的属性。每个事件类型都包含自己的属性和行为,只能通过其事件处理程序访问。

41.React中的合成事件是什么?

围绕浏览器原生事件充当跨浏览器对象。将不同浏览器的行为合并为一个 API。这样做是为了确保事件在不同浏览器中显示一致的属性

42.如何创建refs? 
import React from 'react'
class test extends React.Component{
    state = {
        myTest: 'jjj'
    }
    testRef = React.createRef()   // 创建的是一个对象
    render(){
    
        return(
            <div>
                <input ref={this.testRef}/>
                <button onClick={() =>{
                console.log("获取输入框中的值",this.testRefs.current.value)
                console.log(this.testRefs.current, '是一个对象,可以获取到DOM')
                }}>点我</button>
            </div>
            )
    }
}
export default test
43.列出一些应该使用 Refs 的情况。

通过ref来获取DOM元

  • 需要管理焦点、选择文本或媒体播放时(请看React-60)
  • 触发式动画
  • 与第三方 DOM 库集成
//标签中设置ref,值为字符串
<input type="text" ref="name"/>

//函数中通过ref获取DOM中的值
getInputValue(){
    cnosole.log(this.refs.name.value) //打印出input中输入的内容
}


class ReferenceDemo extends React.Component{
     display() {
         const name = this.inputDemo.value;
         document.getElementById('disp').innerHTML = name;
     }
render() {
    return(        
          <div>
            Name: <input type="text" ref={input => this.inputDemo = input} />
            <button name="Click" onClick={this.display}>Click</button>            
            <h2>Hello <span id="disp"></span> !!!</h2>
          </div>
    );
   }
 }

43.如何模块化 React 中的代码?

可以使用 export 和 import 属性来模块化代码。它们有助于在不同的文件中单独编写组件。

//ChildComponent.jsx
export default class ChildComponent extends React.Component {
    render() {
        return(           
              <div>
              	<h1>This is a child component</h1>
              </div>
        );
    }
}
 
//ParentComponent.jsx
import ChildComponent from './childcomponent.js';
class ParentComponent extends React.Component {    
    render() {        
        return(           
             <div>               
                <App />          
             </div>       
        );  
    }
}

44.解释react中render()的目的

每个React组件强制要求必须有一个render().它返回一个React元素,是原生DOM组件的表示。如果需要渲染多个HTML元素,则必须将它们组合在一个封闭标记内,例如<form>,<group>,<div>等。此函数必须保持纯净,即必须每次调用时都返回相同的结果。

45.如何将两个或多个组件嵌入到一个组件中?

// 可以通过以下方式
class MyComponent extends React.Component{
    render(){
        return(          
			<div>
            	<h1>Hello</h1>
                <Header/>
            </div>
        );
    }
}
class Header extends React.Component{
    render(){
        return
			<h1>Header Component</h1>   
   };
}
ReactDOM.render(
    <MyComponent/>, document.getElementById('content')
);

46.React事件机制 

<div onClick={this.handleClick.bind(this)}>点我</div>

React并不是将click事件绑定到了div的真实DOM上,而是在document处监听了所有的事件,当事件发生并且冒泡到document处的时候,React将事件内容封装并交由真正的处理函数运行。这样的方式不仅仅减少了内存的消耗,还能在组件挂在销毁时统一订阅和移除事件。

除此之外,冒泡到document上的事件也不是原生的浏览器事件,而是由react自己实现的合成事件。.因此如果不想要是事件冒泡的话应该调用event.preventDefault()方法,而不是调用event.stopProppagation()方法。

是怎么较少内存消耗的???

渲染组件 

 当react元素

function Welcome(props) {
    return <h1>Hello, {props.name}</h1>
}

const element = <Welcome name="Sara" />
ReactDOM.render(
    element,
    document.geteElementById('root')
)

47.事件处理

// 传统的
<button οnclick="activateLasers()">Active Lasers</button>
// react
<button onClick={activateLaser}>
    Activate Lasers
</button>

// 开关按钮
class Toggle extends React.Component{
    constructor(props){
        super(props)
        this.state = {isToggleOn: true}
        
        // 为了在回调中使用this,这个绑定是必不可少的
        this.handleClick = this.handleClick.bind(this)
    }

    handleClick() {
        this.setState(state =>({
            isToggleOn: !state.isToggleOn
        }))
    }

    render() {
        return (<button onClick={this.handleClick}>
                    {this.state.isToggleOn ? 'ON' : 'OFF'
                </button>)
    }
}

ReactDOM.render(
    <Toggle />,
    document.getElementById('root')
)


class LoggingButton extends React.Component{
    handleClick = () =>{
        console.log(this)
    }
    render(){
        <button onClick={this.handleClick}>
            Click me
        </button>
    }

}

48.受控组件和非受控组件

受控组件:通过setState的形式控制输入的值及更新

非受控组件:通过dom的形式更新值,获取值通过ref的形式去获取

// 受控
class NameForm extends React.Component{
    constructor(props){
        super(props)
        this.state = {value: ''}
        this.handleChange = this.handleChange.bind(this)
        this.handleSubmit = this.handleSubmit.bind(this)
    }


    handleChange(event){
        this.setState({}value: event.target.value)
    }
    
    handleSubmit(event){
        alert('提交的名字:' + this.state.value)
        event.preventDefault()
    }

    render(){
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    名字:
                    <input type="text" value={this.state.value} onChange={this.handleChange}/>
                </label>
                    <input type="submit" value="提交"/>
            </form>
        )
    }
}

// 非受控
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class Demo1 extends Component {
    render() {
        return (
            <input />
        )
    }
}

ReactDOM.render(<Demo1/>, document.getElementById('content'))
 在这个最简单的输入框组件里,我们并没有干涉input中的value展示,即用户输入的内容都会展示在上面。如果我们通过props给组件设置一个初始默认值,defaultValue属性是React内部实现的一个属性,目的类似于input的placeholder属性。

49.为什么在src创建子目录?

webpack只处理src的中文件。如果不把css和html放在src文件夹下,webpack发现不了。

50.react是单页面应用程序

单页面不需要加载整个页面,单页面就是一个页面,用路由来切换组件显示,页面只有一个index.html,不管什么组件都是在这个页面里的,最后都放在这里面了

非单页面:原来那种网站 每点个链接 都是整个页面刷新 有的登录都是刷新,原来网站会有很多html文件

优点:

1.良好的交互体验
  单页应用的内容的改变不需要重新加载整个页面,获取数据也是通过Ajax异步获取,没有页面之间的切换,就不会出现“白屏现象”,也不会出现假死并有“闪烁”现象,页面显示流畅,web应用更具响应性和更令人着迷。

2.良好的前后端工作分离模式
  后端不再负责模板渲染、输出页面工作,后端API通用化,即同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端。

3.减轻服务器压力
  单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍。

缺点:

  • 首屏加载慢

解决方案:

  • Vue-router懒加载:对首屏加载的速度提升得越明显。
  • 使用CDN加速

单页面应用程序的优缺点 - 浩荡九天 - 博客园

React如何优雅地写单页面应用? - 知乎

用React实现移动端单页应用 - 一扬 - 博客园

简单单页面的实现

https://blog.csdn.net/u013558749/article/details/68068519?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

52.React-router单页面应用--路由管理;路由和组件;重定向;路由生命周期;懒加载   

53.render函数中return如果没有使用()会有什么问题?

render进行return时,对于单行的内容,没必要加括号,但对于多行的内容要加括号

JSX转为js后,js会在每行自动加';',如果return后换行了,那么就会变成return;

54.componentWillUpdate可以直接修改state的值吗

  • 不可以,会导致无限循环报错
  • 在react中直接修改state,render函数不会重新执行渲染,应使用setState方法进行修改

55.React的事件和普通的HTML事件有什么不同? 

  • 事件名称命名方式,原生事件为全小写,react 事件采用小驼峰
  • 事件函数处理语法,原生事件为字符串,react 事件为函数
  • react 事件不能采用 return false 的方式来阻止浏览器的默认行为,必须明确调用preventDefault来阻止默认行为

合成事件是 react 模拟原生 DOM 事件所有能力的一个事件对象,其优点如下:

  • 兼容所有浏览器,更好的跨平台
  • 将事件统一存放在一个数组,避免频繁的新增与删除(垃圾回收)
  • 方便 react 统一管理和事务机制

事件的执行顺序为原生事件先执行,合成事件后执行,合成事件会冒泡绑定到 document 上,所以尽量避免原生事件与合成事件混用,如果原生事件阻止冒泡,可能会导致合成事件不执行,因为需要冒泡到document 上合成事件才会执行

56.React 组件中怎么做事件代理?它的原理是什么?

React基于Virtual DOM实现了一个SyntheticEvent层(合成事件层),定义的事件处理器会接收到一个合成事件对象的实例,它符合W3C标准,且与原生的浏览器事件拥有同样的接口,支持冒泡机制,所有的事件都自动绑定在最外层上。

在React底层,主要对合成事件做了:事件委派和自动绑定。

  • 事件委派: React会把所有的事件绑定到结构的最外层,使用统一的事件监听器,这个事件监听器上维持了一个映射来保存所有组件内部事件监听和处理函数。
  • 自动绑定: React组件中,每个方法的上下文都会指向该组件的实例,即自动绑定this为当前组件。

57.条件渲染 

场景:返回按钮是否显示

import React,{component} from 'react'
export default class App extends Component{
    state = {
        list:[
            {
                id: 1,
                isShow: false
            },
             {
                id: 2,
                isShow: true
            }
        ]
    }
    render(){
        return(
            <div>
                    <ul>
                        {this.state.list.map(item =>{
                            <li key={item.id}>
                                {item.isShow}
                            {item.isShow && <button>返回</button>}
                            </li>
                        })}
                    </ul>
            </div>
        )
    }
}
import React,{Component} from 'react'
class User extends Component{
    render(){
        return(<div>Weclome back!</div>)
    }
}

class Guest extends Component{
     render(){
        return(<div>Weclome back!</div>)
     }
}
export default class App extends Component{
     state = {
        isLogin: false
     }
     render(){
        const isLogin = this.state
        let button
        if(isLogin){
               button = <User /> 
        }else{
                button = <Guest />
        }
        return(<div>
            {button}
        </div>)
     }
}
58.模仿vue中v-model指令,react实现类似双向绑定

通过onChange事件监听input的value值,在通过this.setState改变显示出来 

59.react无状态组件和class类组件的区别 

  • 函数组件是一个返回react元素的函数,体现的是无状态组件思想,函数组件中没有this,没有state,没有生命周期,决定了函数组件都是展示性组件,接收props,渲染dom
  • 函数组件不需要考虑组件状态和组件生命周期方法,有很大的性能提升空间

60.React中什么是纯函数

即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。

let friend = {
    firstName: 'zhang',
    lastName: 'san',
    age: 18
}
// 非纯函数:会修改函数外变量 friend 的值
function appendMessage() {
    friend.message = {
        time: '2021年',
        info: '学习React'
    }
}
// 纯函数:返回一个新对象,且不会修改参数
function appendMessage(friend) {
    let copyFriend = Object.assign({}, friend)
    copyFriend.message = {
        time: '2021年',
        info: '学习React'
    }
    return copyFriend
}

61.shouldComponentUpdate默认会有的吗 

是的,每个组件都会有 

62.React组件传值有哪些方式 

父传子:props  

子传父:通过在父组件引入的子组件中传递一个函数并传参数,子组件去触发这个函数更改参数完成数据更新

跨多层组件传值:通过context api完成

63.React中要实现一键换ui样式有哪些方案

  • 准备不同主题色的样式文件
  • 将用户的选择记录在本地缓存中
  • 每次进入应用时,读取缓存,根据缓存的信息判断要加载哪个样式文件即可 

64.路由的动态加载模块 

webpack在打包react应用时会将整个应用打包成一个js文件,当用户首次访问时,会加载整个js文件,当应用规模越来越大时,这个js文件所包含的数据量也越来越大,网站首屏渲染的速度也就会变慢

优化方法

  • 多入口:利用webpack的entry配置多入口,将应用打包分割成多个js文件。适用于多页面应用。
  • 路由动态加载:利用import()方法细颗粒度的分割代码,将每一个路由到的组件从主bundle.js文件分离出来。

65.什么时候使用状态管理器?

  • 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  • 某个组件的状态需要共享
  • 某个状态需要在任何地方都可以拿到

===============下面不用背 

52.什么是高阶组件 

高阶组件是参数为组件,返回值为新组件的函数 

React高阶组件_小小白学计算机的博客-CSDN博客_高阶组件

55.什么是渲染劫持 

渲染指的是组件中的render函数return的JSX语法部分。劫持是在渲染之前进行数据等操作的处理,修改了原来组件的渲染

控制组件从另一个组件输出的能力

在高阶组件中,组合渲染和条件渲染都是渲染劫持的一种,通过反向继承,不仅可以实现以上两点,还可以增强由原组件render函数产生的React元素。

实际的操作中 通过 操作 state、props 都可以实现渲染劫持

 77.如何配置React-Router 

1.安装

npm install react-router-dom --save

npm install react-router-config --save

2.HashRouter与BrowserRouter区别

 BrowserRouter:
  原理是H5的history API,IE9及以下不兼容,需要由web server支持,在web client这边window.location.pathname被react router解析

HashRouter:
  原理是URL的hash,不需要由web server支持,因为它的只有‘/’path需要由web server支持,而#/react/route URL不能被web server读取,在web client这边window,location.hash被react router解析

3.index.js

 import { HashRouter as Router } from 'react-router-dom'
 
ReactDOM.render(
  <Router>
    <App />
  </Router>,
 
  document.getElementById('root')
);

4.app.js

// import logo from './logo.svg';
import './App.css';
import React, { Component } from 'react';
import { Link } from "react-router-dom"
import { renderRoutes } from "react-router-config"
import routes from "./routes"
 
class App extends Component {
  render() {
    return (
      <div className="App" >
        <Link to="/">首页</Link>
        <Link to="/communication">通讯</Link>
        <Link to="/find">发现</Link>
        <Link to="/about">我的</Link>
 
 
 
        <div>
          {renderRoutes(routes)}
        </div>
      </div>
 
    );
  }
 
}
 
export default App;

 5.在创建一个routes文件夹 index.js

import Home from "../components/home"
import Communication from "../components/communication"
import Find from "../components/find"
import About from "../components/about"
 
const routes = [
    {
        path: "/",
        exact: true,
        component: Home
    },
    {
        path: "/communication",
        component: Communication,
        // routes: [
        //     {
        //         path: '/communication/:id',
        //         component: Course
        //     }
        // ]
 
    },
    {
        path: "/find",
        exact: true,
        component: Find
    },
    {
        path: "/about",
        exact: true,
        component: About
    },
]
 
export default routes

6.在建components 文件夹 里面对应的页面 

React-Router 路由配置_初夏七鹿的博客-CSDN博客_react-router 路由配置

高阶组件用法及作用 

react中高阶组件用了什么设计模式 

使用了装饰模式,高阶组件的运用:

function withWindowWidth(BaseComponent) {
  class DerivedClass extends React.Component {
    state = {
      windowWidth: window.innerWidth,
    }
    onResize = () => {
      this.setState({
        windowWidth: window.innerWidth,
      })
    }
    componentDidMount() {
      window.addEventListener('resize', this.onResize)
    }
    componentWillUnmount() {
      window.removeEventListener('resize', this.onResize);
    }
    render() {
      return <BaseComponent {...this.props} {...this.state}/>
    }
  }
  return DerivedClass;
}
const MyComponent = (props) => {
  return <div>Window width is: {props.windowWidth}</div>
};
export default withWindowWidth(MyComponent);
复制代码

 装饰模式的特点是不需要改变 被装饰对象 本身,而只是在外面套一个外壳接口。JavaScript 目前已经有了原生装饰器的提案,其用法如下:

@testable
   class MyTestableClass {
}
react hooks中的 userLayouteffect 和 userEffect 有啥区别 

useEffect 是异步执行的,而 useLayoutEffect 是同步执行的。
useEffect 的执行时机是浏览器完成渲染之后,而 useLayoutEffect 的执行时机是浏览器把内容真正渲染到界面之前,和 componentDidMount 等价。 

 react hooks 为什么不能在循环和条件判断语句中调用 

这是因为React通过单链表来管理Hooks。update阶段,每次调用 useState,链表就会执行 next 向后移动一步。如果将 useState 写在条件判断中,假设条件判断不成立,没有执行里面的 useState 方法,会导致接下来所有的 useState 的取值出现偏移,从而导致异常发生。 

 react hook中userCallback的用途? 

优化子组件渲染次数 

react hooks 中的 useCallback 和 useMemo 

useMemo和useCallback接收的参数都是一样,第一个参数为回调,第二个参数为要依赖的数据

共同作用:依赖数据发生变化, 才会调用,也就是起到缓存的作用。useCallback缓存函数,useMemo缓存返回值。

react hooks 函数组件实现 shouldcompensUpdate? 

使用 userMemo 实现。

父组件调用子组件,父组件中的任何一个state发生变化,子组件中的方法代码都会重新进行渲染使用 userMemo 可解决重复渲染和多余渲染问题

 react 中的 hooks 解决了什么问题?为啥要出现 hooks ? 

① 从组件中提取状态逻辑,解决了在组件之间复用状态逻辑很难的问题;
② 将组件中相互关联的部分拆分成更小的函数,解决了复杂组件的问题;
③ 在非class的情况下使用更多的React特性,解决了class组件与函数组件有差异的问题。 

82.hooks父子传值

父传子
在父组件中用useState声明数据
 const [ data, setData ] = useState(false)

把数据传递给子组件
<Child data={data} />

子组件接收
export default function (props) {
	const { data } = props
	console.log(data)
}
子传父
子传父可以通过事件方法传值,和父传子有点类似。
在父组件中用useState声明数据
 const [ data, setData ] = useState(false)

把更新数据的函数传递给子组件
<Child setData={setData} />

子组件中触发函数更新数据,就会直接传递给父组件
export default function (props) {
	const { setData } = props
	setData(true)
}
如果存在多个层级的数据传递,也可依照此方法依次传递

// 多层级用useContext
const User = () => {
 // 直接获取,不用回调
 const { user, setUser } = useContext(UserContext);
 return <Avatar user={user} setUser={setUser} />;
};

使用过的Redux中间件 

83.介绍redux,主要解决什么问题 

redux是为了解决react组件间通信和组件间状态共享而提出的一种解决方案,主要包括3个部分,(store + action + reducer)。

store:用来存储当前react状态机(state)的对象。connect后,store的改变就会驱动react的生命周期循环,从而驱动页面状态的改变

action: 用于接受state的改变命令,是改变state的唯一途径和入口。一般使用时在当前组件里面调用相关的action方法,通常把和后端的通信(ajax)函数放在这里

reducer: action的处理器,用于修改store中state的值,返回一个新的state值

主要解决什么问题:

1、组件间通信

由于connect后,各connect组件是共享store的,所以各组件可以通过store来进行数据通信,当然这里必须遵守redux的一些规范,比如遵守 view -> aciton -> reducer的改变state的路径

2、通过对象驱动组件进入生命周期

对于一个react组件来说,只能对自己的state改变驱动自己的生命周期,或者通过外部传入的props进行驱动。通过redux,可以通过store中改变的state,来驱动组件进行update

3、方便进行数据管理和切片

redux通过对store的管理和控制,可以很方便的实现页面状态的管理和切片。通过切片的操作,可以轻松的实现redo之类的操作

在React中页面重新加载时怎样保留数据? 

这个问题就设计到了数据持久化, 主要的实现方式有以下几种:

Redux: 将页面的数据存储在redux中,在重新加载页面时,获取Redux中的数据;
data.js: 使用webpack构建的项目,可以建一个文件,data.js,将数据保存data.js中,跳转页面后获取;
sessionStorge: 在进入选择地址页面之前,componentWillUnMount的时候,将数据存储到sessionStorage中,每次进入页面判断sessionStorage中有没有存储的那个值,有,则读取渲染数据;没有,则说明数据是初始化的状态。返回或进入除了选择地址以外的页面,清掉存储的sessionStorage,保证下次进入是初始化的数据
history API: History API 的 pushState 函数可以给历史记录关联一个任意的可序列化 state,所以可以在路由 push 的时候将当前页面的一些信息存到 state 中,下次返回到这个页面的时候就能从 state 里面取出离开前的数据重新渲染。react-router 直接可以支持。这个方法适合一些需要临时存储的场景。

在React中怎么使用sync/await?

async/await是ES7标准中的新特性。如果是使用React官方的脚手架创建的项目,就可以直接使用。如果是在自己搭建的webpack配置的项目中使用,可能会遇到 regeneratorRuntime is not defined 的异常错误。那么我们就需要引入babel,并在babel中配置使用async/await。可以利用babel的 transform-async-to-module-method 插件来转换其成为浏览器支持的语法,虽然没有性能的提升,但对于代码编写体验要更好。

84.React层面的性能优化 

对于类组件和函数式组件来看,都可以从以下几个方面去思考能够进行性能优化

  • 减少重新render的次数

举例子:

React更新流程如下,我们可以有两种优化角度

1.props/state变化 --->render函数变化这个阶段,减少render的执行次数

2.新旧DOM树进行diff--->计算出差异进行更新,减少差异内容

类组件:

(1)shouldComponentUpdate

当props和state更新时,render函数就会执行,

此时我们可以通过生命周期 shouldComponentUpdate来控制是否需要render重新执行,当不写这个生命周期时,React内部决定render是否变化的函数就会返回true,即默认每次都更新。

state = { count: 0 }   
shouldComponentUpdate(nextProps, nextState){
     if(nextProps.count === this.state.count){
          return false
     }
     return true 
} 
  • 减少渲染的节点 

(2)减少差异

 虚拟DOM的diff算法中为了提高性能,只对每一层进行比较,不会跨层比较,有key的时候会比对相同的key,没有key时内容不同就直接替换,当我们进行逆序增加数据时,没有唯一的key,会导致相同的数据每次都会重新渲染 。每个元素的唯一id,因为索引值会根据遍历的数据变化。

<ul>
    <li key="1">千与千寻的神隐</li>
    <li key="2">龙猫</li>
    <li key="3">侧耳倾听</li>
<ul>
 
<ul>
    <li key="1">起风了</li>    
    <li key="2">千与千寻的神隐</li>
    <li key="3">龙猫</li>
    <li key="4">侧耳倾听</li>
<ul>
  • 降低渲染计算量
  • 合理设计组件

高耦合低内聚(减少无必要的重复渲染;减小重复渲染时影响得范围)

在react里时间耗时最多的一个地方是reconciliation,如果不执行render,也就不需要 reconciliation,所以可以看出减少render在性能优化过程中的重要程度了

85.react-router里的<Link>标签和<a>标签有什么区别 

Link组件最终会渲染为HTML标签<a>,它的to,query,hash属性会被组合在一起并渲染为href属性。虽然Link被渲染为超链接,但在内部实现上使用脚本拦截了浏览器的默认行为,然后调用了history.pushState方法

Link 只负责触发 url 变更,Route 只负责根据 url 渲染组件

相比于 <a> 标签,<Link> 避免了不必要的渲染

  react 项目中使用 class 组件和 函数组件要怎么通信?

用 ref 通信

具体实例参考:react 类组件(父组件)与函数组件(子组件) ref 通信_yang423712的博客-CSDN博客_react父子组件通信ref

 如何在React中使用innerHTML

增加dangerouslySetInnerHTML属性,并且传入对象的属性名叫_html

function Component(props){
	return <div dangerouslySetInnerHTML={
  
  {_html:'<span>你好</span>'}}>
	</div>
}

redux请求中间件如何处理并发 

使用redux-Saga redux-saga是一个管理redux应用异步操作的中间件,用于代替 redux-thunk 的。它通过创建 Sagas 将所有异步操作逻辑存放在一个地方进行集中处理,以此将react中的同步操作与异步操作区分开来,以便于后期的管理与维护。 redux-saga如何处理并发:

React组件中怎么做事件代理 

React组件事件代理的原理 

深入理解React:事件机制原理 - OneForCheng - 博客园

React怎么做数据的检查和变化 

  • props组件属性,专门用来连接父子组件间通信,父组件传输父类成员,子组件可以利用但不能编辑父类成员
  • state:专门负责保存和改变组价内部的状态

数据传递:在React中,父组件给子组件传递数据时,通过子组价设置props的方式,子组件取得props中的值,即可完成数据传递,被传递数据的格式可以是任何js可识别的数据结构props一般只作为父组件给子组件传递数据用,不要试图去修改自己的props

数据改变:props不能被自身修改,如果组件内部的属性发生变化使用state

this.setState({})

React会实时监听每个组件的props和state的值,一旦有变化,会立刻更新组件,将结果重新渲染到页面上,state,props

react-router怎么实现路由切换 

使用import时,webpacknode_modules里的依赖会做什么 

ReactDom结构发生变化后内部经历了哪些变化 

React挂载的时候有3个组件,textComponent、composeComponent、domComponent,区别和关系,Dom结构发生变化时怎么区分data的变化,怎么更新,更新怎么调度,如果更新的时候还有其他任务存在怎么处理 

Redux中异步的请求怎么处理 

redux的设计思想 

接入redux的过程 

绑定connect的过程 

Redux在状态管理方面解决了React本身不能解决的问题 

遇到性能问题一般在哪个生命周期里解决 

写react有哪些细节可以优化 

React的事件机制(绑定一个事件到一个组件上) 

React子父组件之间如何传值 

介绍下React高阶组件,和普通组件有什么区别 

页面上有1万个button如何绑定事件 

循环绑定时的index是多少,为什么,怎么解决 

页面上有一个input,还有一个p标签,改变input后p标签就跟着变化,如何处理 

监听input的哪个事件,在什么时候触发 

Redux怎么实现属性传递,介绍下原理 

React-Router版本号 

Redux状态管理器和变量挂载到window中有什么区别 

React中setState后发生了什么 

seetState()将总会触发一次重绘,除非在shouldComponentUpdate()中实现了条件渲染逻辑。如果可变对象被使用了,但又不能在shouldComponentUpdate() 中实现这种逻辑,仅在新state和之前的state存在差异的时候调用setState()可以避免不必要的重新渲染。通常state中只来管理和渲染有关的状态,从而保证setState改变状态和渲染有关的状态。这样子就可以避免不必要的重复渲染。其他和渲染无关的状态,可以直接以属性的形式保存在组件中,在需要的时候调用和改变,不会造成渲染。同时需要避免不必要的修改,当 state 的值没有发生改变的时候,尽量不要使用 setState 。虽然 shouldComponentUpdate 和PureComponent 可以避免不必要的重复渲染,但是还是增加了一层 shallowEqual 的调用,造成多余的浪费。

setState为什么默认是异步;setState什么时候是同步的 

react设计思路 

react常见的通信方式 

  • 父子组件通信:父组件可以向子组件通过传 props 的方式,向子组件进行通讯
  • 跨级组件通信:Context设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言,对于跨越多层的全局数据通过Context通信再适合不过
  • 非嵌套组件通信 

父子通信

  • 父传子 --> props
  • 子传父--->props+回调函数 

跨级组件通信

  • props逐层传递(不考虑)
  • context传递 

非嵌套组件通信(如兄弟组件等) 

使用机制:消息订阅与发布

react组件通信的几种方式_卡布达。的博客-CSDN博客_react组件通信

React中组件通信的几种方式 - 简书

redux整体的工作流程 

首先,我们看下几个核心理念:

Store:保存数据的地方,

  • 你可以把它看成一个容器,整个应用只能有一个Store。
  • State:Store对象包含所有数据,如果想得到某个时点的数据,就要对Store生成快照,这种时点的数据集合,就叫做State。
  • Action:State的变化,会导致View的变化。但是,用户接触不到State,只能接触到View。所以,State的变化必须是View导致的。Action就是View发出的通知,表示State应该要发生变化了。
  • Action Creator:View要发送多少种消息,就会有多少种Action。如果都手写,会很麻烦,所以我们定义一个函数来生成Action,这个函数就叫Action Creator。
  • Reducer:Store收到Action以后,必须给出一个新的State,这样View才会发生变化。这种State的计算过程就叫做Reducer。Reducer是一个函数,它接受Action和当前State作为参数,返回一个新的State。
  • dispatch:是View发出Action的唯一方法。

然后我们过下整个工作流程:

  1. 首先,用户(通过View)发出Action,发出方式就用到了dispatch方法。
  2. 然后,Store自动调用Reducer,并且传入两个参数:当前State和收到的Action,Reducer会返回新的State
  3. State一旦有变化,Store就会调用监听函数,来更新View。

React数据流 

哪些方法会触发React重新渲染?

setState()方法被调用

父组件重新渲染 

 重新渲染render会做些什么?

会对新旧VNode进行对比,也就是我们所说的Diff算法

对新旧两棵树进行一个深度优先遍历,这样每一个节点都会一个标记,在到深度遍历的时候,没遍历到一个节点,就把该节点和新的节点树进行对比,如果有差异就到放到一个对象里面

说说React有什么坑点

 JSX做表达式判断的时候需要转为boolean类型

如果不使用!!b进行强转数据类型会在页面里面输出0

render() {
  const b = 0;
  return <div>
    {
      !!b && <div>这是一段文本</div>
    }
  </div>
}

react的理念是什么(拿函数式编程来做页面渲染) 

为什么使用Hooks? 

使用hooks理由

  • 高阶组件为了复用,导致代码层级复杂
  • 生命周期复杂
  • 写成functional组件,无状态组件,因为需要状态,又改成了class,成本高 

useState(保存组件状态)

const [state,setState] = useState(initialState) 

常用hooks有哪些? 

useState:保存组件内部状态的函数,提供了setState改变组件状态(初始化的时候只执行一次)

useEffect:在函数组件中执行副作用操作,componentDidMount,componentDidUpdate和componentWillUnmount(内部不能修改state)

负责对某些值进行实时监控。如果第二个可选参数为空,表明在第一次渲染时进行。
如果是需要清除的副作用,一个return一键清除。【数据请求】 

useContext:跨组件传值

useReducer: useState的加强版,在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。

useCallback:和useEffect类似,把函数做为第一个参数,把函数的依赖项作为第二个参数传入,改回调函数只有在函数的依赖项发生改变时才会调用,返回的是一个回调函数。

useMemo和uesCallback类似... ...返回的是一个值。

useRef const refContainer = useRef(initialValue);

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。
本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。
你应该熟悉 ref 这一种访问 DOM 的主要方式。如果你将 ref 对象以 <div ref={myRef} /> 形式传入组件,则无论该节点如何改变,React 都会将 ref 对象的 .current 属性设置为相应的 DOM 节点。
然而,useRef() 比 ref 属性更有用。它可以<a href="https://知乎 - 有问题,就会有答案">很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。
这是因为它创建的是一个普通 Javascript 对象。而 useRef() 和自建一个 {current: ...} 对象的唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象。
请记住,当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。

useEffect的回调函数为什么无法使用async?

react本身并不支持这么做,理由effect function 应该返回一个销毁函数(effect:是指return返回的cleanup函数),如果useEffect第一个参数传入async,返回值则变成了Promise,会导致react在调用销毁函数的时候报错:function.apply is undefined

useCallback和useMemo的区别?他们是如何进行缓存的? 

useCallback返回的是函数,useMemo 返回的是值。 

 useCallback在什么情况下不适用? 

使用 useCallback 避免频繁调用,但当一个 useCallback 的依赖项变化后,这个 useEffect 会被执行。

· 记忆效果差,依赖变化时,函数也被重新生成

· 想要记忆效果好(也就是依赖为[])又拿不到最新的state

· useCallback返回的函数也是具有闭包效应,即我们在其他hooks中使用的时候useCallback返回的函数也是那次闭包环境下产生的函数。

 useState是同步还是异步?如果是异步,如何变为同步?

什么场景下是异步的?

只要在react的管控下的setState都是异步的:

一是提高效率,每次修改state的值都会造成render的重新渲染,将多次修改state的值合并统一更新可以提高性能;

二是render的更新会晚一些,如果render中有子组件,子组件的props依赖于父组件的state,props和state就不能保持一致 

如何获取异步时的state的值

1.在setState的回调函数中

this.setState({ 
 count: this.state.count + 1}}, 
 ()=>{ console.log(this.state.count)})

2.在componentDidUpdate中获取

componentDidUpdate(){
 console.log(this.state.count)}

是同步的

通过 this.setState 修改状态之后,在它的下一行输出 state 是新的值

什么场景下同步的?

Reduce 方法里的 setState 是同步更新的。

setTimeout帮助了setState逃脱了react的管控,所以是同步的。

① 原生js获取dom元素,并绑定事件

<button id="addBtn">点我+1</button>componentDidMount(){
 const addBtn = document.getElementById('addBtn')
 changeBtn.addEventListener('click',()=>{
 this.setState({ count: this.state.count + 1})
 console.log(this.state.message)
 })}

② 计时器 setTimeout

<button onClick={ e => this.addOne() }>点我+1</button>addOne(){setTimeout(()=>{ this.setState({ count: this.state.count + 1 })
 console.log(this.state.count ) },0)}

 想同步获取最新的值的代码写入到回调函数中,通过这种方式进行处理;

hook原理 

 如何在React中使用innerHTML

 增加dangerouslySetInnerHTML属性,并且传入对象的属性名叫_html

function Component(props){
    return <div dnagerouslySetInnerHTML={
  
  {_html:'<span>你好</span>'}}></div>
}

66.说说你对react的渲染原理的理解

【第1386期】React从渲染原理到性能优化(一)

67.说说Context有哪些属性

68.怎么使用Context开发组件 

69.React中在哪捕获错误?

百度安全验证

[react] React中在哪捕获错误?_「违规用户」的博客-CSDN博客_react 捕获错误

错误边界 – React

70.react组件的构造函数有什么用 

提供了一个无需为每层组件手动添加props,就能在组件树间进行数据传递的方法  

React 高阶组件、Render props、hooks 有什么区别,为什么要不断迭代 

高频react面试题20道(附详解)_程序员成长指北-CSDN博客

虚拟DOM原理剖析

react动画特效 

这么高质量React面试题(含答案),看到就是赚到了! - 知乎

https://www.aliyue.net/11776.html

react组件化思想 

猜你喜欢

转载自blog.csdn.net/weixin_51225684/article/details/130202647