react学习笔记

前言笔记总结

1. setState

setState更新状态的2种写法

	(1). setState(stateChange, [callback])------对象式的setState
            1.stateChange为状态改变对象(该对象可以体现出状态的更改)
            2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
					
	(2). setState(updater, [callback])------函数式的setState
            1.updater为返回stateChange对象的函数。
            2.updater可以接收到state和props。
            4.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
总结:
		1.对象式的setState是函数式的setState的简写方式(语法糖)
		2.使用原则:
				(1).如果新状态不依赖于原状态 ===> 使用对象方式
				(2).如果新状态依赖于原状态 ===> 使用函数方式
				(3).如果需要在setState()执行后获取最新的状态数据, 
					要在第二个callback函数中读取

2. lazyLoad

路由组件的lazyLoad

	//1.通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包
	const Login = lazy(()=>import('@/pages/Login'))
	
	//2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面
	<Suspense fallback={<h1>loading.....</h1>}>
        <Switch>
            <Route path="/xxx" component={Xxxx}/>
            <Redirect to="/login"/>
        </Switch>
    </Suspense>

3. Hooks

1. React Hook/Hooks是什么?
(1). Hook是React 16.8.0版本增加的新特性/新语法
(2). 可以让你在函数组件中使用 state 以及其他的 React 特性
2. 三个常用的Hook
(1). State Hook: React.useState()
(2). Effect Hook: React.useEffect()
(3). Ref Hook: React.useRef()
3. State Hook
(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作
(2). 语法: const [xxx, setXxx] = React.useState(initValue)  
(3). useState()说明:
        参数: 第一次初始化指定的值在内部作缓存
        返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
(4). setXxx()2种写法:
        setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
        setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
4. Effect Hook
(1). Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
(2). React中的副作用操作:
        发ajax请求数据获取
        设置订阅 / 启动定时器
        手动更改真实DOM
(3). 语法和说明: 
        useEffect(() => { 
          // 在此可以执行任何带副作用操作
          return () => { // 在组件卸载前执行
            // 在此做一些收尾工作, 比如清除定时器/取消订阅等
          }
        }, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
    
(4). 可以把 useEffect Hook 看做如下三个函数的组合
        componentDidMount()
        componentDidUpdate()
    	componentWillUnmount() 
5. Ref Hook
(1). Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
(2). 语法: const refContainer = useRef()
(3). 作用:保存标签对象,功能与React.createRef()一样

4. Fragment

使用

<Fragment><Fragment>
<></>

作用

可以不用必须有一个真实的DOM根标签了


5. Context

理解

一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信

使用

1) 创建Context容器对象:
	const XxxContext = React.createContext()  
	
2) 渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:
	<xxxContext.Provider value={数据}>
		子组件
    </xxxContext.Provider>
    
3) 后代组件读取数据:

	//第一种方式:仅适用于类组件 
	  static contextType = xxxContext  // 声明接收context
	  this.context // 读取context中的value数据
	  
	//第二种方式: 函数组件与类组件都可以
	  <xxxContext.Consumer>
	    {
	      value => ( // value就是context中的value数据
	        要显示的内容
	      )
	    }
	  </xxxContext.Consumer>

注意

在应用开发中一般不用context, 一般都用它的封装react插件

6. 组件优化

Component的2个问题

  1. 只要执行setState(),即使不改变状态数据, 组件也会重新render() ==> 效率低

  2. 只当前组件重新render(), 就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==> 效率低

效率高的做法

只有当组件的state或props数据发生改变时才重新render()

原因

Component中的shouldComponentUpdate()总是返回true

解决

办法1: 
	重写shouldComponentUpdate()方法
	比较新旧state或props数据, 如果有变化才返回true, 如果没有返回false
办法2:  
	使用PureComponent
	PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true
	注意: 
		只是进行state和props数据的浅比较, 如果只是数据对象内部数据变了, 返回false  
		不要直接修改state数据, 而是要产生新数据
项目中一般使用PureComponent来优化

7. render props

如何向组件内部动态传入带内容的结构(标签)?

Vue中: 
	使用slot技术, 也就是通过组件标签体传入结构  <A><B/></A>
React中:
	使用children props: 通过组件标签体传入结构
	使用render props: 通过组件标签属性传入结构,而且可以携带数据,一般用render函数属性

children props

<A>
  <B>xxxx</B>
</A>
{this.props.children}
问题: 如果B组件需要A组件内的数据, ==> 做不到 

render props

<A render={(data) => <C data={data}></C>}></A>
A组件: {this.props.render(内部state数据)}
C组件: 读取A组件传入的数据显示 {this.props.data} 

8. 错误边界

理解:

错误边界(Error boundary):用来捕获后代组件错误,渲染出备用页面

特点:

只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误

使用方式:

getDerivedStateFromError配合componentDidCatch

// 生命周期函数,一旦后台组件报错,就会触发
static getDerivedStateFromError(error) {
    console.log(error);
    // 在render之前触发
    // 返回新的state
    return {
        hasError: true,
    };
}

componentDidCatch(error, info) {
    // 统计页面的错误。发送请求发送到后台去
    console.log(error, info);
}

9. 组件通信方式总结

组件间的关系:
  • 父子组件
  • 兄弟组件(非嵌套组件)
  • 祖孙组件(跨级组件)
几种通信方式:
	1.props:
		(1).children props
		(2).render props
	2.消息订阅-发布:
		pubs-sub、event等等
	3.集中式管理:
		redux、dva等等
	4.conText:
		生产者-消费者模式
比较好的搭配方式:
	父子组件:props
	兄弟组件:消息订阅-发布、集中式管理
	祖孙组件(跨级组件):消息订阅-发布、集中式管理、conText(开发用的少,封装插件用的多)
  • XML早期用于存储和传输数据
  • js里表达jsx
//html
<div id="test></div>

//JS
	.创建虚拟DOM
const VDOM=(
	<h2>
		<span> helloword </span>
	</h2>
)
     .渲染虚拟DOM到页面
     ReactDom.react(VDOM,document,getElementById('text'))
  • JSX语法规则
    - 定义虚拟dom时,不需要写引号
    -标签中使用 JS表达式 要用花括号 { }
    -样式类名用 className
    -内联样式格式 style={{key:value}}
    写内联样式 例如:<div style={{ color:'white',fontSize:'16px' }}"></div>
    -虚拟dom必须只有一个根标签
    -标签必须闭合
    -标签首字母要小写,大写的 是组件标签

-JSX 小练习

 动态的表达
 	.hello
 	.react
 	.记笔记
//html
<div id="test></div>

//js
const VDOM =(
	<h2>
		<ul>
			<li>hello <li>
			<li>react <li>
			<li>记笔记 <li>
		</ul>
	</h2>
)
ReactDOM.render(VDOM,document.getElementById('test'))


//模拟一些数据
	const data=['hello','react','记笔记']
	
//
	const VDOM =(
	<h2>
		<ul>
			{data.map((item,index)=>{
				return <li key={index}> {item}</li>
			})
			}
		</ul>
	</h2>
)
ReactDOM.render(VDOM,document.getElementById('test'))

请添加图片cx
React面向组件编程

请添加图片描述
类 要会

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
            /***
         * constructor不是必须写的。对实例有操作的时候就可以写,例如添加属性可以写
         * super().如果A类继承了B类,且B类已经写了构造器,那么A类中的super()必须调用
         * 类中定义的方法都放在了原形对象上,供实例去使用
         * **/
        // 1,创建一个类
        class person{
            // 3,构造器
            constructor(name,hoby){
                // 构造器的this是类的实例对象
                this.name =name;
                this.hoby =hoby;
            }
            // 一般方法
            speak(){
                // speak的方法放在类的原型对象上,供实例使用
                //通过person调用speak,speak的this就是类的实例//this的指向问题
                console.log(`我的名字${this.name},我最喜欢${this.hoby}`);
            }
        }
        // 4,创建于一个Student类。继承person
        class Student extends person{
            // constructor在什么时候写?-
            constructor(name,hoby,age){
                super(name,hoby)//调用
                this.age="100"
            }
            speak(){
                console.log(`我的名字${this.name},我最喜欢${this.hoby}了,我们能活到${this.age}`);
				//原型链查找规则,查找到第一个就停止了
            }
        }
        //5,
        var s1= new Student('小乌龟','拉屎')
        console.log(s1);
        s1.speak()
        // 2,创建 person的实例对象
        const girl = new person('杜秀秀','学习');
        const dog  = new person('周锋','吃粑粑')
        console.log(girl);
        console.log(dog);
        girl.speak()
        dog.speak()
        // girl.speak().call({a:1}) //undefined call会改变this的指向,apply

    </script>
</body>
</html>
  • react的类解析
   class myComponent extends React.component{
            // render 放在myComponent的原型对象上。供实例使用
            // render 的this是  myComponent的实例对象
            render(){
                console.log('render()中的实例对象:',this);
                return  <div></div>
            }
        }
        // 渲染到页面
        ReactDOM.render(<mycomponent/>,document.getElementById('test'))
        // 做了哪些事
        // 1,react去找到组件
        // 2,发现组件是类定义的,随后new出来该类的实例,并通过该实例调用到原形render()方法。
        // 3,将rende()返回的虚拟dom转化成真实的dom,呈现在页面上

10,组件三大状态 (状态里存储着数据)

1. state

- 组件中的render() 中的this是组件的实例对象
- 组件中的this为undefined,如何解决?
	  1)强制绑定this.通过 bind()
	  2) 箭头函数
 - 状态数据不能更改或直接更新?
 	this.setState()
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
	// 练习react 点击切换
		class Foods extends React.Component{
			
			state ={banana:true}
			
			render(){
				const { banana } = this.state;
				return <h1 onClick={this.getFoods}>今晚吃{banana?'香蕉':'葡萄'}</h1>
			}
			//自定义方法 用箭头函数。箭头函数没有自身的this.
			getFoods=()=>{
				const banana = this.state.banana//this.是类 Foods的
				this.setState({ banana :!banana})
			}
		}
		
		ReactDOM.render(<Foods/>,document.getElementById('test'))
	</script>
</body>
</html>

2,props

对标签进行限制

	Person.propTypes = {
			name:PropTypes.string.isRequired, //限制name必传,且为字符串
			sex:PropTypes.string,//限制sex为字符串
			age:PropTypes.number,//限制age为数值
			speak:PropTypes.func,//限制speak为函数
		}
		//指定默认标签属性值
		Person.defaultProps = {
			sex:'男',//sex默认值为男
			age:18 //age默认值为18
		}

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>对props进行限制</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test1"></div>
	<div id="test2"></div>
	<div id="test3"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>
	<!-- 引入prop-types,用于对组件标签属性进行限制 -->
	<script type="text/javascript" src="../js/prop-types.js"></script>

	<script type="text/babel">
		//创建组件
		class Person extends React.Component{

			constructor(props){
				//构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
				// console.log(props);
				super(props)
				console.log('constructor',this.props);
			}

			//对标签属性进行类型、必要性的限制
			static propTypes = {
				name:PropTypes.string.isRequired, //限制name必传,且为字符串
				sex:PropTypes.string,//限制sex为字符串
				age:PropTypes.number,//限制age为数值
			}

			//指定默认标签属性值
			static defaultProps = {
				sex:'男',//sex默认值为男
				age:18 //age默认值为18
			}
			
			render(){
				// console.log(this);
				const {name,age,sex} = this.props
				//props是只读的
				//this.props.name = 'jack' //此行代码会报错,因为props是只读的
				return (
					<ul>
						<li>姓名:{name}</li>
						<li>性别:{sex}</li>
						<li>年龄:{age+1}</li>
					</ul>
				)
			}
		}

		//渲染组件到页面
		ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
	</script>
</body>
</html>

关键词
propTypes

defaultProps

3,refs

1,字符串形式的ref 不推荐使用
2,createRef() 创建的 ref 属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> createRef() 创建的 ref 属性</title>
</head>
<body>
    	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>
	<script type="text/javascript" src="../js/prop-types.js"></script>
    <script type="text/babel">
        class Demo extends React.Component{
            render() {
                return (
                    <div>
                        <input ref={this.myRef} type="text" placeholder="点我左侧提示" />
                        <button ref='btn1' onClick={this.showbtn}>按钮</button>
                        <input ref={this.myOnblur} type="text" placeholder="点我失去焦点提示"  onBlur={this.blurBtn}/>
                        <button ref='btn2'>按钮</button>
                    </div>
                )   
            }
             // /****/ 把ref理解成打标识
            //  React.createRef调用后可以返回一个容器,该容器存储被ref所标识的节点,该容器是“专人专用"
             myRef = React.createRef() 
             myOnblur = React.createRef()
            showbtn = ()=>{
                console.log('showbtn:',this);
                alert(this.myRef.current.value)
             }
            blurBtn=()=>{
                console.log(this)
                alert(this.myOnblur.current.value)
            }
        }
      
        ReactDOM.render(<Demo/>,document.getElementById('test'))
    </script>
    <style>
        .mr{
            margin-right: 10px;
        }
    </style>
</body>
</html>

官方文档:
ref 回调以内联函数的方式定义,在更新期间会被调用两次,第一次参数是 null ,之后参数是 DOM 元素。这是因为在每次渲染中都会创建一个新的函数实例。因此,React 需要清理旧的 ref 并且设置新的。

-ref不推荐频繁使用
通过event.target得到发生dom的元素对象-不用使用ref

在这里插入代码片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> createRef() 创建的 ref 属性</title>
</head>
<body>
    	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>
	<script type="text/javascript" src="../js/prop-types.js"></script>
    <script type="text/babel">
        class Demo extends React.Component{
            render() {
                return (
                    <div>
                        <input ref={this.myRef} type="text" placeholder="点我左侧提示" />
                        <button ref='btn1' onClick={this.showbtn}>按钮</button>
                        <input type="text" placeholder="点我失去焦点提示"  onBlur={this.blurBtn}/>
                        <button ref='btn2'>按钮</button>
                    </div>
                )   
            }
             // /****/ 把ref理解成打标识
            //  React.createRef调用后可以返回一个容器,该容器存储被ref所标识的节点,该容器是“专人专用"
             myRef = React.createRef() 
             myOnblur = React.createRef()
            showbtn = ()=>{
                console.log('showbtn:',this);
                alert(this.myRef.current.value)
             }
            blurBtn=(event)=>{
                console.log(event.target)
                alert(event.target.value)
            }
        }
      
        ReactDOM.render(<Demo/>,document.getElementById('test'))
    </script>
    <style>
        .mr{
            margin-right: 10px;
        }
    </style>
</body>
</html>

11,生命周期

1,生命周期旧



			1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
								1.	constructor()
								2.	componentWillMount()
								3.	render()
								4.	componentDidMount() =====> 常用
												一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
			2. 更新阶段: 由组件内部this.setSate()或父组件render触发
								1.	shouldComponentUpdate()
								2.	componentWillUpdate()
								3.	render() =====> 必须使用的一个
								4.	componentDidUpdate()
			3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
								1.	componentWillUnmount()  =====> 常用
												一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值