react-interview

react相关知识点

事件

事件绑定

// 第一种
this.handle = this.handle.bind(this)

// <p onClick={this.handle}>aaa</p>

handle(){}

// 第二种
// <p onClick={this.handle}>aaa</p> 

handle = () => {}

event

clickHandler = (event) => {
        event.preventDefault() // 阻止默认行为
        event.stopPropagation() // 阻止冒泡
        console.log('target', event.target) // 指向当前元素,即当前元素触发
        console.log('current target', event.currentTarget) // 指向当前元素,假象!!!

        // 注意,event 其实是 React 封装的。可以看 __proto__.constructor 是 SyntheticEvent 组合事件
        console.log('event', event) // 不是原生的 Event ,原生的 MouseEvent
        console.log('event.__proto__.constructor', event.__proto__.constructor)

        // 原生 event 如下。其 __proto__.constructor 是 MouseEvent
        console.log('nativeEvent', event.nativeEvent)
        console.log('nativeEvent target', event.nativeEvent.target)  // 指向当前元素,即当前元素触发
        console.log('nativeEvent current target', event.nativeEvent.currentTarget) // 指向 document !!!

        // 1. event 是 SyntheticEvent ,模拟出来 DOM 事件所有能力
        // 2. event.nativeEvent 是原生事件对象
        // 3. 所有的事件,都被挂载到 document 上
        // 4. 和 DOM 事件不一样,和 Vue 事件也不一样
    }

合成事件

  • 为什么要合成事件机制?

1.更好的兼容性和跨平台

2.载到document,减少内存消耗,避免频繁解绑

3.方便事件的统一管理

性能优化

shouldComponentUpdate()

  • 1.默认父组件更新,子组件也会更新
  • 2.所以使用shouldComponentUpdate,来避免部分子组件不需要更新而跟着父组件更新了
  • 3.shouldComponentUpdate需要的时候才用
  • 4.shouldComponentUpdate默认返回true
shouldComponentUpdate(nextProps,nextState){
  if(nextProps.count !== this.props.count){
    return true; // 可以渲染
  }
  return false; // 不可以渲染
}

PureComponent

  • 1.PureComponent中,shouldComponentUpdate实现了浅比较
  • 2.在class组件中使用

React.memo

  • 1.相当于函数组件中的PureComponent

组件

函数组件

  • 1.纯函数,输入props,输出jsx
  • 2.没有实例,没有生命周期,没有state
  • 3.不能扩展
function List(props){
  const { list } = this.props;
  return (
      list.map(item => {
      return <div key={item.id}>{item.name}</div>
    })
  )
}

非受控组件

  • 1.不受state控制,只初始化state,通过ref方式获取改变的值
  • 2.ref ,defaultValue defaultChecked, 手动操作dom元素
constructor(){
  state = {
    name: 'aaa'
  }
  this.nameRef = React.createRef()
}

handle(){
  const ele = this.nameRef.current; // 获取 ref
  console.log(ele.value)
}

<input ref={this.nameRef} defaultValue={this.state.name} />
  • 3.非受控组件使用场景:
    • 1.必须手动操作dom元素,setstate实现不了
    • 2.文件上传
    • 3.富文本编辑器

受控组件vs非受控组件

  • 1.优先使用受控组件
  • 2.必须操作dom时,再使用非受控组件

异步组件

  • import() React.lazy React.Suspense
// React.lazy
const Demo = React.lazy(() => import('./App.js'))

// React.Suspense
<React.Suspense fallback={loading}>
    <Demo />      
</React.Suspense>

高阶组件

// 基本用法
import React from 'react'

// 高阶组件
const withMouse = (Component) => {
    class withMouseComponent extends React.Component {
        constructor(props) {
            super(props)
            this.state = { x: 0, y: 0 }
        }

        handleMouseMove = (event) => {
            this.setState({
                x: event.clientX,
                y: event.clientY
            })
        }

        render() {
            return (
                <div style={{ height: '500px' }} onMouseMove={this.handleMouseMove}>
                    {/* 1. 透传所有 props 2. 增加 mouse 属性 */}
                    <Component {...this.props} mouse={this.state}/>
                </div>
            )
        }
    }
    return withMouseComponent
}

const App = (props) => {
    const a = props.a
    const { x, y } = props.mouse // 接收 mouse 属性
    return (
        <div style={{ height: '500px' }}>
            <h1>The mouse position is ({x}, {y})</h1>
            <p>{a}</p>
        </div>
    )
}

export default withMouse(App) // 返回高阶函数

Render Props

import React from 'react'
import PropTypes from 'prop-types'

class Mouse extends React.Component {
    constructor(props) {
        super(props)
        this.state = { x: 0, y: 0 }
    }

    handleMouseMove = (event) => {
      this.setState({
        x: event.clientX,
        y: event.clientY
      })
    }

    render() {
      return (
        <div style={{ height: '500px' }} onMouseMove={this.handleMouseMove}>
            {/* 将当前 state 作为 props ,传递给 render (render 是一个函数组件) */}
            {this.props.render(this.state)}
        </div>
      )
    }
}
Mouse.propTypes = {
    render: PropTypes.func.isRequired // 必须接收一个 render 属性,而且是函数
}

const App = (props) => (
    <div style={{ height: '500px' }}>
        <p>{props.a}</p>
        <Mouse render={
            /* render 是一个函数组件 */
            ({ x, y }) => <h1>The mouse position is ({x}, {y})</h1>
        }/>

    </div>
)

/**
 * 即,定义了 Mouse 组件,只有获取 x y 的能力。
 * 至于 Mouse 组件如何渲染,App 说了算,通过 render prop 的方式告诉 Mouse 。
 */

export default App

介绍一下虚拟DOM

React组件如何通讯

jsx本质是什么

Context是什么,有何用途

多层组件传递属性,用context

import React from 'react'

// 创建 Context 填入默认值(任何一个 js 变量)
const ThemeContext = React.createContext('light')

// 底层组件 - 函数是组件
function ThemeLink (props) {
    // const theme = this.context // 会报错。函数式组件没有实例,即没有 this

    // 函数式组件可以使用 Consumer
    return <ThemeContext.Consumer>
        { value => <p>link's theme is {value}</p> }
    </ThemeContext.Consumer>
}

// 底层组件 - class 组件
class ThemedButton extends React.Component {
    // 指定 contextType 读取当前的 theme context。
    // static contextType = ThemeContext // 也可以用 ThemedButton.contextType = ThemeContext
    render() {
        const theme = this.context // React 会往上找到最近的 theme Provider,然后使用它的值。
        return <div>
            <p>button's theme is {theme}</p>
        </div>
    }
}
ThemedButton.contextType = ThemeContext // 指定 contextType 读取当前的 theme context。

// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar(props) {
    return (
        <div>
            <ThemedButton />
            <ThemeLink />
        </div>
    )
}

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            theme: 'light'
        }
    }
    render() {
        return <ThemeContext.Provider value={this.state.theme}>
            <Toolbar />
            <hr/>
            <button onClick={this.changeTheme}>change theme</button>
        </ThemeContext.Provider>
    }
    changeTheme = () => {
        this.setState({
            theme: this.state.theme === 'light' ? 'dark' : 'light'
        })
    }
}

export default App

渲染列表为何用key

  • 必须用key,且不能是index和random
  • diff算法中通过tag和key来判断,是否是sameNode
  • 减少渲染次数,提升渲染性能

jsx本质

1.React.createElement 即h函数,返回vnode

2.第一个参数,可能是组件,也可能是html tag

3.组件名,首字母必须大写

Portals

  • 例如做一个Modal组件,需要把modal节点放在body第一层,使用createPortal
// index.js
<Modal>MODAL</Modal>

// Modal.js
import React from 'react'
import ReactDom from 'react-dom';


class Demo React.Component {
  render(){
    return ReactDom.createPortal(
        <div className="modal">this.props.childen</div>,
      document.body // dom 节点
    )
  }
}
  • Portal使用场景:

1.overflow:hidden

2.父组件:z-index太小

3.fixed需要放在body第一层

什么是纯函数

什么是受控组件

何时使用异步组件

多个组件有公共逻辑,如何抽离

redux如何进行异步请求

react-router如何配置懒加载

PureComponent有何区别

react和vue区别

react事件和dom事件区别

生命周期

描述redux单项数据流

setState是同步还是异步

不可变值

  • 1.不能直接修改state,使用setState
    // 数组
    this.setState({
    count: this.state.count.concat(100)
    })
    

// 对象
this.setState({
obj:{…this.state.obj,{a:10}}
})


+ 2.可能是异步更新:
```js
state = {
  count: 0
}
// 第一种 ,同步
this.setState({
  count: this.state.count+1
})
console.log(this.state.count) // 0

// 第二种,异步,回调函数
this.setState({
  count: this.state.count+1
},() => {
  console.log(this.state.count) // 1
})

// 第三种,在setTimeout中是,同步,不需要回调函数
setTimeout(() => {
  this.setState({
  count: this.state.count+1
})
console.log(this.state.count) // 1
},0)

// 第四种,自定义的dom事件,setState是同步
componentDidMount(){
  document.body.addEventListener('click',() => {
    this.setState({
      count: this.state.count+1
    })
    console.log(this.state.count) // 1
  })
}
  • 3.可能会被合并:
    // 传入对象,会被合并。执行3次,结果还是1
    this.setState({
    count:this.state.count+1
    })
    this.setState({
    count:this.state.count+1
    })
    this.setState({
    count:this.state.count+1
    })
    

// 传入函数,不会被合并。执行结果是3
this.setState((prevState,props) => {
return {
count:prevState + 1
}
})
this.setState((prevState,props) => {
return {
count:prevState + 1
}
})
this.setState((prevState,props) => {
return {
count:prevState + 1
}
})
```

setstate到底是异步还是同步

1.setstate无所谓是同步还是异步

2.看是否能命中batchUpdate机制

3.判断isBatchingUpdates

哪些不能名字batchupdate机制

1.setTimeout

2.自定义的dom事件

vdom和diff

只比较同一层级,不跨级比较

tag不相同,则直接删除重建,不再深度比较

tag和key相同,则一样

基于react设计一个todolist(组件结构,redux state 数据结构)

jsx如何渲染页面

setstate之后如何更新页面

react源码解析

react源码解析

react 里如何做动态加载

  • React.lazy ,另外通过 webpack 的动态加载:import() 和 ensure.require

虚拟 DOM 的理解

redux 的原理

redux 做状态管理和发布订阅模式有什么区别

react-redux 的原理,是怎么跟 react 关联起来的


   转载规则


《react-interview》 朝飞 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录