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.lazy ,另外通过 webpack 的动态加载:import() 和 ensure.require