React 属性, 函数式组件以及Hook
Posted ZZZ --- jh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React 属性, 函数式组件以及Hook相关的知识,希望对你有一定的参考价值。
属性以及函数式组件,Hook
五个属性: PureComponent、ref、children、dangerouslySetInnerhtml、key
React的五个属性
PureComponent
个人理解是PureComponent 是类组件的情况下,它是用来继承的
pureComponent 提供了一个具有浅比较,的shouldComponrentUpdate方法其他和component完全一致
是react中创建组件的一种方式,可以减少不必要的更新,易于实施,进而提升性能,每次更新会自动帮你对更新前后的props和state进行一个简单对比, 来决定是否进行更新.只要把继承类从 Component
换成 PureComponent
即可,可以减少不必要的 render
操作的次数,从而提高性能,而且可以少写 shouldComponentUpdate
函数,节省了点代码。
import React, {PureComponent, Component} from 'react';
class App extends PureComponent {
state = {
name:'张三',
list:["张三01","张三02","张三03"]
}
render(){
let {name, list} = this.state;
return (
<div>
<h1>{name}</h1>
<ul>
{
list.map((item,index)=>{
return <li key={index}>{item}</li>
})
}
</ul>
<button onClick={()=>{
this.setState({name:'yyqx'})
}}>升级</button>
<button onClick={()=>{
list.push('新人');
this.setState({list:[...list]})
}}>扩大</button>
</div>
)
}
}
export default App;
以上这个案例当继承PureComponent时,list:[...list]
必须写成这样扩大的这个按钮才会新增数据的; 当继承Component时, list:[...list]
也可以写成list
ref
-
注意: 再组件挂载完成之后及更新之后使用
-
旧版 ref —> 字符串类型绑定
先安装
npm i better-scroll
再引入
import BScroll from "better-scroll";
import React, {PureComponent, Component} from 'react'; import BScroll from "better-scroll"; // new BScroll() let list = [...('.'.repeat(100))]; // console.log(list); class App extends PureComponent { // 组件挂载完成之后 componentDidMount(){ // 通过this.refs绑定ref的名字来获取dom节点 // console.log(this.refs.box); new BScroll(this.refs.box); } render(){ return ( <div style={{ height:'300px', border:'1px solid red', overflow:'hidden' }} ref='box' > <ul style={ {margin:0,padding:0,listStyle:'none'} }> { list.map((item,index)=>{ return <li key={index}>这是第{index}个li</li> }) } </ul> </div> ) } } export default App;
这个案例中滚动效果是可以实现的,但是控制台会给一个提示
Warning: A string ref, "box", has been found within a strict mode tree. String refs are a source of potential bugs and should be avoided. We recommend using useRef() or createRef() instead. Learn more about using refs safely here
(字符串ref, “box”,在严格模式树中被发现。字符串引用是潜在错误的来源,应该避免); 可以把index.js中的<React.StrictMode></React.StrictMode>
这个标签删除掉就不会警告了; 此时就要用到下面的这个方法了. -
新版 ref —> createRef()
通过在class中使用createRef()方法创建一些变量,可以将这些变量绑定到标签的ref中,那么该变量的current则指向绑定的标签dom
import React, {PureComponent, Component, createRef} from 'react'; import BScroll from "better-scroll"; // new BScroll() let list = [...('.'.repeat(100))]; // console.log(list); class App extends PureComponent { box = createRef(); componentDidMount(){ // console.log(this); // console.log(this.box.current); new BScroll(this.box.current) } render(){ return ( <div style={{ height:'300px', border:'1px solid red', overflow:'hidden' }} ref = {this.box} > <ul style={ {margin:0,padding:0,listStyle:'none'} }> { list.map((item,index)=>{ return <li key={index}>这是第{index}个li</li> }) } </ul> </div> ) } } export default App;
children
-
组件标签对之间的内容会被当做一个特殊的属性props.children传入组件内容
import React, {PureComponent} from 'react'; class Child extends PureComponent{ render(){ console.log(this); let {children} = this.props; return <div>{children}</div> } } class App extends PureComponent { render(){ return ( <div> <Child > {/* <h1>今天的天气很不错</h1> <p>明天的天气也还行</p> */} { ['哈哈','拉拉'] } </Child> </div> ) } } export default App;
-
可以自定义结构的组件的常用形式
- children
- 传递函数
- 传递子组件
import React, {PureComponent} from 'react'; class Popwindow extends PureComponent{ state = { close:false } render(){ // console.log(this); let {close} = this.state; let {children} = this.props; return ( <div style={{ border:'3px solid #ccc', display: close ? "none" : 'block' }}> {children} <button onClick={()=>{ this.setState({ close:true }) }}>关闭</button> </div> ) } } class App extends PureComponent { state = { show:false, man:false } render(){ let {show, man} = this.state; return ( <div> {show?(<Popwindow > <h1>yyqx</h1> <p>qzh</p> </Popwindow>):''} {man?(<Popwindow > <h1>qxx</h1> <p>byg</p> </Popwindow>):''} <button onClick={()=>{ this.setState({show:true}) }}>显示弹框1</button> <button onClick={()=>{ this.setState({man:true}) }}>显示弹框2</button> </div> ) } } export default App;
dangerouslySetInnerHTML
-
直接设置标签的innerHTML
-
要接收的插值只能是一个对象
-
有个固定的属性:
__html
-
可以用来接收数据,但是接收的只能是后端的数据,后端服务器发送过来的数据是校检过的,是安全的;不要接收前端自己写的数据
-
import React, {PureComponent} from 'react'; let message = `<h1>yyqx</h1> <p>qzh</p>` class App extends PureComponent { render(){ return ( <div dangerouslySetInnerHTML={{ __html:message }}> </div> ) } } export default App;
key的问题
-
在react,组件每次更新时,会生成一个虚拟DOM, 和原油的虚拟DOM进行对比; 如果在批量生成一组元素,那么react就会根据key值去做对比
-
一个列表中的每一项key是惟一的, 如果列表中发生顺序等操作变化,key一定要用数据的id
-
import React, {PureComponent} from 'react'; class App extends PureComponent { state = { data:[ { id:0, content:'第1条数据' }, { id:1, content:'第2条数据' }, { id:2, content:'第3条数据' }, { id:3, content:'第4条数据' }, { id:4, content:'第5条数据' } ] } render(){ let {data} = this.state; return ( <div > { data.map((item,index)=>{ return <p key={item.id}> {item.content} <a onClick={()=>{ data = data.filter(itemData=>itemData!==item) this.setState({ data:[...data] }) }}>删除</a> </p> }) } </div> ) } } export default App;
函数式组件
16.7版本之后新增的
函数式组件中, 没有state和生命周期; 所以又称为无状态组件; 在早期16.7(react)版本中,被当前纯渲染组件来用
函数名就是组件名;
组件的第0个参数是 props - 接收父级传过来的信息
没有this; 没有state和生命周期;
必须要有return, return里面定义的是该组件渲染的内容
在16.7之前函数组件一直当做渲染组件来使用
<!-- app.js -->
import React from 'react';
function Child(props){
return <h1>{props.info} </h1>
}
function App(){
// console.log(this); // undefined
// return <div>哈哈哈</div>
return <Child info='呵呵' />
}
export default App;
React hooks
react hooks 是react16.8中的新增功能. 无需编写class类的情况下使用state状态和其他react功能.
英文文档参考: https://reactjs.org/docs/hooks-intro.html
中文文档参考: https://reactjs.bootcss.com/docs/hooks-intro.html
什么是Hook
Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React.
React Hooks的优势
- 简化组件逻辑
- 复用状态逻辑
- 无需使用类组件编写
- 完全可选的
- 100%向后兼容. 不包含任何破坏性改动
- 现在可用
常用Hook
-
useState – 让函数式组件拥有状态
let [状态的值,修改状态的方法] = useState(状态的初始值);
let [state, setState] = useState(initialState);
useState 唯一的采纳数就是初始state.
<!-- app.js --> import React, {useState} from 'react'; import Child from './Child' // let [状态的值,修改状态的方法] = useState(状态的初始值); function App(){ let [data,setData] = useState({ name:"yyqx", age:20 }); return <div> <Child data={data} /> <button onClick={()=>{ setData({ name:'Jackson', age:data.age }); }}> 变身 </button> </div> } export default App;
<!-- Child.js --> import React from 'react'; function Child(props){ console.log(props); let {data} = props; return <div> <h1>name:{data.name} </h1> <h1>age:{data.age} </h1> </div> } export default Child;
-
useEffect – 副作用,取代生命周期
相当于类组件中的 componentDidMount(挂载完成); componentDidUpdate(数据更新完成); componentWillUnmount(即将卸载) 这三个的集合体.
可以在组件中多次使用useEffect;
useEffect
做了什么? 通过使用这个 Hook,可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数并且在执行 DOM 更新之后调用它。为什么在组件内部调用
useEffect
? 将useEffect
放在组件内部让我们可以在 effect 中直接访问count
state 变量(或其他 props)。不需要特殊的 API 来读取它 —— 它已经保存在函数作用域中。Hook 使用了 javascript 的闭包机制,而不用在 JavaScript 已经提供了解决方案的情况下,还引入特定的 React API.useEffect
会在每次渲染后都执行吗? 是的,默认情况下,它在第一次渲染之后和每次更新之后都会执行。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。<!-- Child.js --> import React,{ useState, useEffect } from 'react'; function Child(props){ let {data} = props; let [age,setAge] = useState(8); // 第二个参数数组中放的是监测的内容 useEffect(()=>{ console.log('挂载了'); },[]) // 卸载的时候记得卸载return里面 useEffect(()=>{ return ()=>{ console.log('卸载了'); } },[]) useEffect(()=>{ console.log('更新了'); },[age]) return <div> <h1>name:{data.name} </h1> <h1>age:{age} </h1> <button onClick={()=>{ setAge(++age) }}>涨一岁</button> </div> } export default Child;
<!-- app.js --> import React, {useState} from 'react'; import Child from './Child' function App(){ let [data,setData] = useState({ name:"yyqx", age:20 }); let [show,setShow] = useState(true); return <div> {show ? <Child data={data} /> : ""} <button onClick={()=>{ setData({ name:'Jackson', age:data.age }); }}> 变身 </button> <button onClick={()=>{ setShow(<
以上是关于React 属性, 函数式组件以及Hook的主要内容,如果未能解决你的问题,请参考以下文章