React面试题目整理---自我的整理学习笔记(已完)


React基本应用


一、mac的创建react项目

1、安装node版本至少11以上

node -v 

2、全局安装creat-react-app

sudo npm install -g create-react-app

 3、安装项目

create-react-app XXX (XXX为你想建立的项目名)

 4、运行项目

cd XXX  (刚才起项目名的文件夹内) 
npm start     //运行

5、注意

可能会出现报错node版本太低的错误,这时用cnpm淘宝镜像来启动它就可以了

cnpm start

二、JSX语法

1、 数据,vue是data,react是this.stat

this.state = {
			name:'北京',
			image:'https://img2.baidu.com/it/u=418352367,3766713103&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=290',
			flag:true
		}

2、 变量,插值,vue是用两个{{}},react用一个{}

render(){
	const pElem = <p>{this.state.name}</p>
	return pElem
}

3、 表达式

render(){
	const exprElem = <p>{this.state.flag ? 'yes' : 'no'}</p>
	return exprElem
}

4、 子元素,vue里动态数据:,react直接绑定{} 

render(){
	const imgElem = <div>
		<p>我的头像</p>
		<img src = 'xxx.png' />
		<img src = {this.state.image} />
	</div>
	return imgElem
}

5、 class,vue是写class,react是写className

render(){
	const classElem = <p className="title">设置 css class</p>
	return classElem
}

6、  style

render(){
	const styleData = { fontSize: '30px', color: 'blue'}
	const styleElem = <p style={styleData}>设置style</p>
	return styleElem
	
	//内联写法,注意是{{和}}
	const styleElem = <p style={{fontSize: '30px', color: 'blue'}}></p>
	return styleElem
	
	//普通写法
	const styleElem = <p style="font-size:30px;color:blue;"></p>
	return styleElem
}

7、 原生html ,vue用v-html,react用dangerouslySetInnerHTM

render(){
	const rawHtml = '<span>富文本内容<i>斜体</i><b>加粗</b></span>'
	const rawHtmlData = {
		__html: rawHtml
	}
	const rawHtmlElem = <div>
		<p dangerouslySetInnerHTML={rawHtmlData}></p>
		<p>{rawHtml}</p>
	</div>
	
	return rawHtmlElem
}

8、 加载组件

import List from './List'

render(){
	const componentElem = <div>
		<p>JSX 中加载一个组件</p>
		<hr/>
		<List/>	
	</div>
	
	return componentElem
}

三、条件

1、if else

注意:vue是用v-if和v-else来进行判断,而react是直接写一个if else判断 

import React from 'react'

class leftData extends React.Component {
	constructor(props) {
		super(props)
		this.state = {}
	}
	render() {
		return <div>left</div>
	}
}

export default leftData;

2、三元表达式

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			showData: 'right'
		}
	}
	render() {
		const leftData = <button>left</button>
		const rightData = <button>right</button>
		
		return <div>
			{this.state.showData == 'left' ? leftData : rightData }
		</div>
	}
}

export default BaseUse;

3、逻辑运算符&&|| 

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			showData: 'right'
		}
	}
	render() {
		const leftData = <button>left</button>
		const rightData = <button>right</button>
		
		return <div>
			{this.state.showData == 'left' && leftData }
		</div>
	}
}

export default BaseUse;

四、渲染列表

1、map 

注意:map函数是数组的一个重组,重组的规则是return里面的返回。但是原数组的数据正常保留 ,map相当于vue里的v-for

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			list: [
				{
					id: 'id_1',
					title: '标题1'
				},{
					id: 'id_2',
					title: '标题2'
				},{
					id: 'id_3',
					title: '标题3'
				}
			]
		}
	}
	render() {
		return <ul>
			{
				this.state.list.map((item,index)=>{
					return <li key={item.id}>
						index: {index};
						title: {item.title}
					</li>
				})
			}
		</ul>
	}
}

export default BaseUse;

2、key 

注意:这里的key 和vue的key类似,必填,但是不能是index和random

五、事件(React事件为何bind this)

1、bind this

  • vue绑定事件是@加事件名称:@click,react绑定事件是on加上事件名称的首字母大写:onClick
  • react的this默认是undefined 

写法1:

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			name:'李玉'
		}
		//修改方法的 this 指向
		this.clickHandler1 = this.clickHandler1.bind(this)
	}
	render() {
		return <p onClick={this.clickHandler1}>
			{this.state.name}
		</p>
	}
	clickHandler1(){
		this.setState({
			name:'简隋英'
		})
	}
}

export default BaseUse;

写法2: 

注意:.bind(this)都是返回一个新的函数,让当前的函数绑定到当前的this上,但是写法1比写法2要好,因为写法1 只会执行一次bind,而写法2会单击一次执行一次bind,且两种的方法都是普通的方法定义的事件

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			name:'李玉'
		}
	}
	render() {
		return <p onClick={this.clickHandler1.bind(this)}>
			{this.state.name}
		</p>
	}
	clickHandler1(){
		this.setState({
			name:'简隋英'
		})
	}
}

export default BaseUse;

 方法3:

注意:此方法是用静态方法,this指向的是当前的实例 

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			name:'李玉'
		}
	}
	render() {
		return <p onClick={this.clickHandler1}>
			{this.state.name}
		</p>
	}
	clickHandler1 = () => {
		this.setState({
			name:'简隋英'
		})
	}
}

export default BaseUse;

2、关于event参数

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

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {}
	}
	render() {
		return <a href="https://wwww.baidu.com/" onClick={this.clickHandler3}>跳转入百度</a>
	}
	clickHandler3 = (event) => {
		event.preventDefault() //阻止默认行为
		event.stopPropagation() //阻止冒泡
		console.log("targe",event.target)//指向当前元素
		console.log("current target",event.currentTarget)//指向当前元素,假象
		
		//event其实是react封装的,可以看__proto__.constructor 是 SyntheticEvent
		console.log('event',event)//不是原生event,原生的是MouseEvent ,而React的是SyntheticEvent
		
		//原生event如下,其__proto__.constructor是MouseEvent
		console.log('nativeEvent',event.nativeEvent)//这个才是原生的event
		//触发事件在绑定标签上,但是绑定事件在#document上
		
	}
}

export default BaseUse;

3、传递自定义参数

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {}
	}
	render() {
		return <div onClick={this.clickHandler3.bind(this,1,2)}>跳转入百度</div>
	}
	clickHandler3(data1,data2,event){
		console.log(data1,data2,event)
	}
}

export default BaseUse;

六、表单

1、受控组件(相当于vue的v-model)

注意:通过input的value绑定state值,通过onchange事件将$event.target.value对state的绑定值进行数据绑定 

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			name:'简隋英'
		}
	}
	render() {
		return <div>
			<p>{this.state.name}</p>
			<label htmlFor="inputName">姓名:</label>
			<input id="inputName" value={this.state.name} onChange={this.changeInput}/>
		</div>
	}
	changeInput = (e)=>{
		this.setState({
			name:e.target.value
		})
	}
}

export default BaseUse;

2、input、textarea、select用value

注意:textarea和input的写法相同 

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			name:'简隋英'
		}
	}
	render() {
		return <div>
			<p>{this.state.name}</p>
			<label htmlFor="inputName">姓名:</label>
			<textarea id="inputName" value={this.state.name} onChange={this.changeInput}></textarea>
		</div>
	}
	changeInput = (e)=>{
		this.setState({
			name:e.target.value
		})
	}
}

export default BaseUse;

3、checkbox、radio用checked 

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			name:'简隋英',
			flag:true
		}
	}
	render() {
		return <div>
			<input type="checkbox" checked={this.state.flag} onChange={this.changeCheckbox}/>
			<p>{this.state.flag.toString()}</p>
		</div>
	}
	changeCheckbox = (e)=>{
		this.setState({
			flag:!this.state.flag
		})
	}
}

export default BaseUse;

 七、组件的使用(父子组件通讯)

父组件: 

import React from 'react'
import List from './component/List/index.js'
import Input from './component/Input/index.js'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			list:[
				{
					id: 'id_1',
					title:'标题1'
				},{
					id: 'id_2',
					title:'标题2'
				},{
					id:'id_3',
					title:'标题3'
				}
			]
		}
	}
	render() {
		return <div>
			<Input submitTitle={this.onSubmitTitle}/>
			<List list={this.state.list}></List>
		</div>
	}
	onSubmitTitle = (title) =>{
		this.setState({
			list:this.state.list.concat({
				id:`id-${Date.now()}`,
				title
			})
		})
	}
}

export default BaseUse;

子组件Input:

import React from 'react'

class Input extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			title:''
		}
	}
	render() {
		return <div>
			<input value={this.state.title} onChange={this.onTitleChange}/>
			<button onClick={this.onSubmit}>提交</button>
		</div>
	}
	onTitleChange =(e)=>{
		this.setState({
			title:e.target.value
		})
	}
	onSubmit = () => {
		const {submitTitle} = this.props
		submitTitle(this.state.title)
		
		this.setState({
			title:''
		})
	}
}

export default Input;

子组件List:  

import React from 'react'

class List extends React.Component {
	constructor(props) {
		super(props)
		this.state = {}
	}
	render() {
		const {list} = this.props 
		return <ul>
			{
				list.map((item,index)=>{
					return <li key={item.id}>
						<span>{item.title}</span>
					</li>
				})
			}
		</ul>
	}
}

export default List;

 1、props传递数据

  • <List list={this.state.list}></List>
  • 接收:const {list} = this.props 

2、props传递函数

  • <Input submitTitle={this.onSubmitTitle}/>
  • this.onSubmitTitle是个函数
  • 接收:const {submitTitle} = this.props
  • 使用:submitTitle(this.state.title)

3、props类型检查

注意:状态提升,要把共同的数据放在最高级别的组件内对他进行管理 

八、setState 

1、不可变值(函数式编程,纯函数)

不可变值(数组): 

const list5Cpry = this.state.list5.slice()
list5Cpry.splice(2,0,'a')
this.setState({
	list1: this.state.list1.concat(100),//追加
	list2: [...this.state.list2,100],//同上追加,饿6写法
	list3: this.state.list3.slice(0,3),//截取
	list4: this.state.list4.filter(item => item > 100),//筛选
	list5: list5Cpry//其他操作
})

注意:不能直接对 this.state.list 进行push pop splice 等,这样违反不可变值的规定 

不可变值(对象):

this.setState({
	obj1: Object.assign({},this.state.obj1,{a:100}),
	obj2: {...this.state.obj2, a: 100}
})

注意:不能直接对 this.state.obj 进行修改,这样违反不可变值的规则,可以先拷贝一个出来进行修改,然后再通过setState把修改后的值赋值给原值 

2、可能是异步更新

第一种异步情况:setState完没有立刻渲染页面

this.setState({
	count: this.state.count+1
},()=>{
	//已经渲染完成,可以拿到最新的值
	//像是Vue中的 $nextTick()
	console.log('count:',this.state.count);
})
//异步的拿不到最新值
console.log('count:',this.state.count);

第二种同步情况:在setTimeout中它是同步的

setTimeout(()=>{
	this.setState({
		count: this.state.count+1
	})
	//可以打印出最新的值
	console.log('count:',this.state.count);
})

第三种同步情况:在自己定义的 DOM 事件,setState 是同步的

bodyClickHandler = () => {
	this.setState({
		count: this.state.count+1
	})
	console.log('count:',this.state.count);
}
componentDidMount() {
	document.body.addEventListener('click',this.bodyClickHandler)
}
componentWillUnmouont(){
	//销毁自定义事件
	document.body.removeEventListener('click',this.bodyClickHandler)
}

3、可能会被合并

传入对象,会被合并(类似于Object.assign),执行结果只一次 +1

//this.state.count = 0
this.setState({
	count: this.state.count + 1
})
this.setState({
	count: this.state.count + 1
})
this.setState({
	count: this.state.count + 1
})
//执行结果:1

传入函数,不会被合并,执行结果是 +3

//this.state.count = 0
this.setState((preState,props) => {
	return {
		count: this.state.count + 1
	}
})
this.setState((preState,props) => {
	return {
		count: this.state.count + 1
	}
})
this.setState((preState,props) => {
	return {
		count: this.state.count + 1
	}
})
//执行结果:3

九、组件生命周期 

shouldComponentUpdata()更新生命周期

注意:父子组件生命周期和vue是一样的 


React高级特性 


 一、函数组件

1、class组件

import React from 'react'

class List extends React.Component {
	constructor(props) {
		super(props)
		this.state = {}
	}
	render() {
		const {list} = this.props 
		return <ul>
			{
				list.map((item,index)=>{
					return <li key={item.id}>
						<span>{item.title}</span>
					</li>
				})
			}
		</ul>
	}
}

export default List;

2、函数组件   

    function List(props) {
	const { list } = this.props
	
	return <ul>
		{list.map((item,index) => {
			return <li key={item.id}>
				<span>{item.title}</span>
			</li>
		})}
	</ul>
}
  • 纯函数,输入props,输出JSX
  • 没有实例,没有生命周期,没有state
  • 不能扩展其他的方法 

二、非受控组件 

1、 ref

组件上绑定:

<input defaultValue={this.state.name} ref={this.nameInputRef}/>

 constructor上注册:

this.nameInputRef = React.createRef()

绑定事件的访问:

alertName = () => {
		const elem = this.nameInputRef.current;//通过 ref 获取 DOM 节点
		alert(elem.value)
	}

2、defaultValue、defaultChecked

<input defaultValue={this.state.name} ref={this.nameInputRef}/>
<input defaultChecked={this.state.flag} type="checkbox"/>

3、手动操作DOM原数​​​​​

上传文件: 

import React from 'react'

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {}
		this.fileInputRef = React.createRef()
	}
	render() {
		return <div>
			<input type="file" ref={this.fileInputRef}/>
			<button onClick={this.alertFileName}>alert name</button>
		</div>
	}
	alertFileName = () => {
		const elem = this.fileInputRef.current
		alert(elem.files[0].name)
	}
}

export default BaseUse;

非受控组件-使用场景:

  •  必须手动操作DOM元素,setState实现不了
  • 文件上传<input type='file'/>
  • 某些富文本编辑器,需要传入DOM元素

三、Portals

  • 组件默认会按照既定层次嵌套渲染
  • 如何让组件渲染到父组件以外? 

1、this.props.children 

render() {
		return <div className="modal">
			{this.props.children}
		</div>
	}

this.props.children类似于Vue的slot 

2、protals写法

普通写法:

return <div className="modal">
			{this.props.childrem}
		</div>

protals写法: 

import ReactDom from 'react-dom'
//render()函数内
return  ReactDom.createPortal(
			<div className="modal">
				{this.props.childrem}
			</div>,
			document.body
		)

3、protals应用场景 

  •  overfilow:hidden
  • 父组件z-index值太小
  • fixed需要放在body第一层级

四、context

  • 公共信息(语言,主题)如何传递给每个组件?
  • 用props太繁琐
  • 用redux小题大做 

context官网实例icon-default.png?t=N7T8https://react.docschina.org/learn/passing-data-deeply-with-context

import React from 'react'
const ThemeContext = React.createContext('light')

function ThemedLink(props){
	return <ThemeContext.Consumer>
			{value => <p>link's theme is {value}</p>}
	</ThemeContext.Consumer>
}

class ThemedButton extends React.Component {
	 render() {
		 const theme = this.context
		 return <div>
			<p>button's theme is {theme}</p>
		 </div>
	 }
}

ThemedButton.contextType = ThemeContext

function Toolbar(props) {
	return (
		<div>
			<ThemedButton/>
			<ThemedLink/>
		</div>
	)
}


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

export default BaseUse;

五、异步组件

  •  import()
  • React.lazy
  • React.Suspense
import React from 'react'
const ContextDemo = React.lazy(() => import('./component/ContextDemo/index.js'))

class BaseUse extends React.Component {
	constructor(props) {
		super(props)
		this.state = {}
	}
	render() {
		return <div>
			<p>引入一个动态组件</p>
			<hr/>
			<React.Suspense fallback={<div>Loading...</div>}>
				<ContextDemo/>
			</React.Suspense>
		</div>
	}
}

// 1、强制刷新,可看见Loading (看不见就限制一下 chrome的网速)
// 2、看 network 的js 加载

export default BaseUse;

六、性能优化 

  • 性能优化对于React更加重要
  • setState中重点强调不可变值 

1、SCU基本用法

shouldComponentUpdate(nextProps, nextState){
	if(nextState.count !== this.state.count){
		return true //可以渲染
	}
	return false // 不重复渲染
}
  • React 默认:父组件有更新,子组件则无条件更新!!!
  • 性能优化对于 React 更加重要 
  • SCU不是需要每次都用,根据需求去用它。 

错误写法: 

let ran = parseInt(Math.random()*10000)
this.state.list.push({
	id:ran,
	name:ran
})
this.setState({
	list:this.state.list
})

 正确写法:

let ran = parseInt(Math.random()*10000)
this.setState({
	list:this.state.list.concat({
		id:ran,
		name:ran
	})
})

scu深度监听: 

shouldComponentUpdate(nextProps, nextState){
	//_isEqual深度监听
	if(_isEqual(nextProps.list, this.props.list)){
		return false
	}
	return true
}
  1. SCU里对数据进行深度监听是错误写法会出现不更新的bug状态,bug出现原因为 那样的写法会导致对比会完全相同,所以不会返回true。

2、SCU使用总结

  •  SCU默认返回true,即React默认重新渲染所有子组件
  • 必须配合“不可变值”一起使用
  • 可先不用SCU,有性能问题时在考虑使用

3、PureComponent和memo

  • PureComponent,SCU中实现了浅比较
  • memo,函数组件中的PureComponent
  • 浅比较已使用大部分情况(尽量不要做深度比较) 

PureComponent 

class BaseUse extends React.PureComponent {
	constructor(props) {
		super(props)
		this.state = {
		}
	}
	shouldComponentUpdate(){/*浅比较*/}
}

 memo

function MyComponent(props) {
	/* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
	/*
	如果把 nextProps 传入 render 方法的返回结果与将
	prevProps 传入 render方法的返回结果一致则返回 true
	否则返回 false
	*/
}
export default React.memo(MyComponent, areEqual)

4、immutable.js

  • 彻底拥抱“不可变值”
  • 最快的方式用不可变值的方式就是深拷贝,但是深拷贝有缺点,缺点会导致性能非常烂
  • immutable基于共享数据(不是深拷贝),速度好
  • 有一定的学习和迁移成本,按需使用 
const map1 = Immutable.Map({a:1, b:2 c:3})
const map2 = map1.set('b', 50)
map1.get('b')//2
map2.get('b')//50

 七、组件的公共逻辑抽离

  • mixin,已被React弃用了
  • 高阶组件HOC
  • Render Props 

 1、高阶组件HOC

一张图说明

高阶组件 基本用法 

//高阶组件不是一种功能,而是一种模式
const HOCFactory = (Component) => {
	class HOC extends React.Component {
		//在此定义多个组件公共逻辑
		render(){
			return <Component {...this.props} /> //返回拼装的结果
		}
	}
	return HOC
}

const EnHancedComponent1 = HOCFactory(WrappedComponent1)
const EnHancedComponent2 = HOCFactory(WrappedComponent2)
  • 接收一个组件,返回一个组件(返回的组件用了我们传入的组件)
  • 它类似一个组装厂 

例子: 

import React, { Component } from 'react'

//高阶组件
const withMouse = (Component) => {
	class withMouseComponent extends React.Component{
		constructor(props) {
			super(props)
			this.state = {x:1 ,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}></Component>
				</div>
			)
		}
	}
	return withMouseComponent
}

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

export default withMouse(APP)//返回高阶函数
  •  HOC通过mouse的属性传递值给子组件
<Component {...this.props} mouse={this.state}></Component>
  •  子组件接收传递的值直接用props接收
const {x, y} = props.mouse //接收 mouse 属性
  • 透传所有props (避免上一个父组件有传值,且高阶组件内包含的子组件有对传值的数据处理,所以需要将所有的props传入子组件内)

{...this.props}

<Component {...this.props} mouse={this.state}></Component>
  • vue的透传所有props通过:$props 和v-bind

2、Render Props

基本用法: 

const App () => (
	<Factory render={
		/* render 是一个函数组件*/
		(props))=> <p>{props.a} {props.b} ...</p>
	}/>
)

//Render Props 的核心思想
//通过一个函数将 class 组件的 state 做为 props 传递给函数组件
class Factory extends React.Component{
	constructor(){
		this.state = {
			/*state 即多个组件的公共逻辑的数据*/
		}
	}
	/*修改 state*/
	render(){
		return <div>{this.props.render(this.state)}</div>
	}
}

例子: 

import React, { Component } from 'react'

class Mouse extends React.Component{
	constructor(props) {
		super(props)
		this.state = {x:1 ,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>
		)
	}
}

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

export default APP

3、 高阶组件HOC和Render Props的区别

  • HOC:模式简单,但是会增加组件层级(可能会出现透传少值的情况)
  • Render Props:代码简洁,学习成本较高 

Redux

  • 和Vuex作用相同,但比Vuex学习成本高
  • 不可变值,纯函数
  • 面试常考

一、安装使用

  • 安装 
npm install --save redux
  •  使用react时安装
npm install --save react-redux
npm install --save-dev redux-devtools

二、三大原则 

 

1、单一数据源

         整个应用的state被存储在一棵object tree 中,并且这个 object tree 只存在于唯一一个store中。

2、使用纯函数来修改执行

        如何改变 state tree 需要编写reducers 。它接收先前的 state 和 action ,并且返回新的state。如果这个 action 超出 reducers 的权限, 要返回老的state 。(注意:里面不能用异步,如定时器网络请求)

3、state是只读的

        唯一改变 state 的方法就是触发 action , action是一个用于描述已发生事件的普通对象。执行上面纯函数

三、核心

1、Action 

function gaiTel(){
	return {
		type:'GAITL',//要办理业务类型
		data:1234567//新数据
	}
}

 2、Reducer

function todoAPP(state = initialState,action) {
	switch (action.type){
		case SET_VISIBILITY_FILTER:
			return Object.assign({},state,{
				visibiliFill:action.filter
			})
		default:
			return state
	}
}

 3、Store

//调用业务流程,执行
store.dispatch(Action)
//创建出来唯一的仓库
let store = createStore(Reducer)

 四、语法

1、创建仓库

import { createStore } from 'redux'
const store = createStore(reducer,initState,middleware)
  • 返回值是一个store对象,这个对象上有3个常用的方法
  • dispatch:store对象提供给用户,告诉管理员有哪些操作
  • getState:获取store中存储的数据
  • subscribe:是一个监听方法,当store中的数据发生改变时就会触发

 2、添加管理员 reducer

function admi(){
	switch(action.type){
		case A:
			return state;
		case B:
			return state;
		default:
			return state
	}
}

3、整体代码

首页引入:

import './component/redux1.js'

 redux1.js:

//引入createStore,创建store方法
import {createStore} from 'redux'

const init = {
	color:'red',
	height:'80cm'
}

const store = createStore(admin,init)

//管理员
function admin(state,action){
	switch(action.type){
		case 'ChangeColor':
			state.color = action.data
			return {...state}
		case 'ChangeHeight':
			state.height = action.data
			return {...state}
		default:
			return state
	}
}

//getState()方法:获取storre中存储的方法
console.log(store.getState())
//dispatch()方法,让用户提交需求
store.dispatch({
	type:'ChangeColor',
	data:'黄色'
})

//subscribe()方法是监听store中的数据变化,变化后会自动触发函数
store.subscribe(function(){
	console.log(store.getState())
})

五、react-redux关联

1、<Provider>

2、connect

​​​​​​​react-redux关联icon-default.png?t=N7T8https://blog.csdn.net/weixin_49866029/article/details/122900437?spm=1001.2014.3001.5506

3、mapStateToProps、mapDispatchToProps 

react-redux关联icon-default.png?t=N7T8https://www.jianshu.com/p/77bd43527a0e

 六、异步Action

1、同步Action

//同步Action
export const addTodo = text =>{
	//返回action对象
	return {
		type:'ChangeColor',
		id:Idoe++,
		text
	}
}

//异步Action
export const addTodoAsync = text =>{
	return (dispatch) => {
		//ajax 异步获取数据
		fetch(url).then(res=>{
			//执行异步action
			dispatch(addTodo(res.text))
		})
	}
}
  • 异步的情况下,要return一个函数
  •  函数里面会接收一个dispatch
  • 异步请求完成后再去调用同步action函数
  • 异步action就是在异步里面再去做了一次同步的action
  • 直接像上面是那么写不行

2、引入thunk完成异步action的完整 


import {createStore,applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import rootReducer from '../rootReducer'

//创建store时,作为中间件引入redux-thunk
const store = createStore(rootReducer,applyMiddleware(thunk))

七、redux中间件

 

  • 上面的redux-thunk就是中间件
  •  图一是一般的操作redux的图
  • action是一个对象,我们的中间件只能在dispatch函数处理action里面去加入中间件

八、redux单项数据流

react-router

  •  hash模式(默认),如http://abc.com/#/user/10
  • H5 history模式,如http://abc.com/user/10

注意:后者需要server端支持,因此无特殊要求可以选择前者 toC用后者,toB用前者

 一、react-router路由模式

二、react-router动态路由的配置 

 

三、跳转路由 

 四、懒加载

React原理

一、函数式编程

  • 一种编程范式,概念比较多
  • 纯函数
  • 不可变值 

二、vdom和diff

 注意:第一个提出虚拟dom和diff是React

vdom 

  • h函数
  • vnode数据结构
  • patch函数

diff 

  • 只比较同一层级,不跨级比较 
  • tag不相同,则直接删除重建,不再深度比较
  • tag和key,两者都相同,则认为是同一节点,不再深度比较

补充 

  • Vue2.0、vue3.0、React三者实现vdom细节口不同
  • 核心概念和实现思路,都一样

三、JSX本质

  •  JSX等同于Vue模板
  • Vue模板不是html
  • JSX也不是JS

 JSX实例

//JSX写法
const imgRlem = <div>
        <p>some text</p>
        <img src={imgUrl}/>
        </div>

//编译后写法
var imgRlem = React.createElement(
        "div",
        null,
        React.createElement(
                "p",
                null,
                "some text"
        ),
        React.createElement("img", { src: imgUrl })
);

h函数编译本质:

 React.createElement('tag',null,child1,child2,child3)

  • 第一个参数为标签
  • 第二个参数为属性
  • 第三个参数为子元素,且第三个参数可以为数组也可以不是数组

返回vnode

//JSX基本用法
const styleData = {
	fontSize:'30px',
	color:'blue'
}
const styleElem = <p style={styleData}>设置style</p>

//h函数转换
var styleData = {
	fontSize: '30px',
	color: 'blue'
};
var styleElem = React.createElement(
	'p',
	{ style: styleData },
	'\u8BBE\u7F6Estyle'
);

//JSX
const app = <div>
	<Input submitTitle={onSubmitTitle}/>
	<List list={list}/>
</div>
//h函数
var app = React.createElement(
	"div",
	null,
	React.createElement(Input, { submitTitle: onSubmitTitle }),
	React.createElement(List, { list: list })
);

 注意:React.createElement第一个参数不一定是元素的名称,还有可能是组件的变量名。

//JSX
const listElem = <ul>
	{this.state.list.map((item,index)=>{
		return <li key={item.id}>index{index},title{item.title}</li>
	})}
</ul>
//h函数
var listElem = React.createElement(
	"ul",
	null,
	undefined.state.list.map(function (item, index) {
		return React.createElement(
			"li",
			{ key: item.id },
			"index",
			index,
			",title",
			item.title
		);
	})
);

 总结​​​​​​​

  • React.createElement即h函数,返回vnode
  • 第一个参数可能是组件,也可能是html tag
  • 组件名,首字母必须大写(React规定) 

四、合成事件 

  •  所有事件挂载到document上
  • event不是原生的,是SyntheicEvent合成事件对象
  • 和Vue事件不同,和Dom事件不同

 为何要合成事件机制?

  • 更好的兼容性和跨平台
  • 挂载到docoment,较少内存消耗,避免频繁解绑
  • 方便事件的同一管理(如事务机制)

五、setState、 batchUpdata

  • 有时是异步(普通使用),有时是同步的(setTimeout、DOM事件)
  • 有时合并(对象形式),有时不合并(函数形式)
  • 后者比较好理解(像Object.assign),主要是前者

 setState主流程

 

注意:普通异步就会处于batch updata之中,同步不会处于batch updata之中

 ​​​​​​​

 

setState是异步还是同步

  • setState无所谓是异步还是同步
  • 看是否能够命中batchUpdata机制
  • 判断isBatchingUpdates 

能够命中batchUpdata机制 

  • 生命周期(和它调用的函数) 
  • React中注册的事件(和它调用的函数)
  • React可以“管理”的入口

不能命中batchUpdata机制

  • setTimeout、setInterval等(和它调用的函数)
  • 自定义的DOM事件(和它调用的函数)
  • React “管不到”的入口  

transaction(事务)机制 

实例:

 

六、总结(组件渲染和更新的过程) 

 

 

更新的两个阶段

  •  上述的patch被拆分成两个阶段
  • reconciliation阶段-执行diff算法,纯JS阶段
  • commit阶段-将diff结果渲染DOM

 如果不分可能会有性能问题

  • JS是单线程,且和DOM渲染共用一个线程
  • 当组件足够复杂,组件更新时计算和渲染都压力过大
  • 同时再有DOM操作需求(动画、拖拽等)、将会卡顿

解决方案fiber

  • 将reconciliation阶段进行任务拆分(commit无法拆分) 
  • DOM需要渲染时暂停,空闲时恢复
  • 如何知道DOM需要渲染,window。requestIdleCallback
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值