第八节:React里的常规操作

96 阅读5分钟

React里的常规操作

条件渲染

条件渲染的方式

在React中,可以创建不同的组件封装需要的各种行为,然后根据应用的不同状态,只渲染对应状态的部分内容

条件渲染和JS中一样,可使用JS的if运算符或条件运算符去创建元素来表现当前的状态,然后让React根据它们来更新UI

if运算符

示例,创建一个Greeting函数组件,根据樱花的登陆状态来显示不同问候语

function Greeting (props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {    
return <h1>欢迎回来~</h1>    
} else { 
return <h1>请先登录</h1>     
} }

根据props传值的不同进行不同的渲染

元素变量

可以使用变量存储元素,帮助我们实现条件的渲染组件的一部分,二其他部分不会改变

render(){ 
let button;    
const {isLoggedIn} = this.state;   
if (isLoggedIn) { 
button = <button onClick={this.handleLogout}>注销</button>  
} else {   
button = <button onClick={this.handleLogin}>登录</button>      
}       
return ( 
<div>     
<Greeting isLoggedIn={isLoggedIn} />      
{ button }         
</div>         )     }

除此之外还可以用三目运算符和&&符号进行一些条件渲染

列表渲染

列表渲染的方式

React中,把一个数组数据转换为一组元素列表进行渲染,是采用JS提供的map方法,能这样做的原因是:React可以自动扁平化数组,对数组的每一个React元素进行渲染

示例:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map(number => 
<li>{number}</li> );
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('app') );

代码解析:

  1. 使用map方法遍历numbers数组,利用map的回调函数将数组中的每一个元素都变成li标签
  2. 将调用map方法后,的得到的新数组赋给listItems
  3. 将listItems元素插入到ul元素中,利用React对数组的处理方式,即可在页面渲染出1到5的项目符号列表。

React的特殊属性:Key

在进行列表渲染时,未给元素列表的每一项提供Key属性,React就会给出警告,需要给每一个元素列表一个独一无二的Key属性。

return ( 
<ul> {
numbers.map(
number => (
<li key={number}>{number}</li> ))
}
</ul> 
)

通常来说,可以使用数据id来作为元素key:

todos.map(item =>
<li key={item.id}> 
{item.text}
</li> 
)

如果元素没有id,也可以使用index作为key

todos.map((item, index) =>
<li key={index}>
{item.text}
</li> 
)

注意:

  • 如果列表项目的顺序可能会变化,那就不建议使用索引作为key,因为这样做会导致性能变差,还可能引起组件状态的问题。
  • 如果已知列表是静态的,或者不必关注顺序,可以选择索引index,甚至可以忽略key属性

这是因为数据改变触发React重新渲染时,React会校正带有key的元素,确保它们被重新排序,而不是重新创建,以确保元素可以保持自身的状态,并提高列表渲染的效率。

key在兄弟节点之间必须唯一

只需要保证在兄弟节点之间是独一无二的即可,不需要全局唯一的。当我们生产两个不同的数组元素时,可以使用相同的key值。

我们可以通过一个数组渲染成一个组件列表,此时key属性需要保持在组件元素上。

DOM操作

React操作DOM的方式

使用React开发应用时,大部分情况不需要查询DOM来更新组件的UI层,只需要关注、设置组件的状态即可。

如果确实需要直接操作DOM,React也提供了以下几种方式:

  1. 通过事件对象获取DOM
  2. React的特殊属性refs
  3. ReactDOM提供的方法findDOMNode

事件对象获取DOM

可以通过访问事件对象的currentTargettarget属性获取相关的DOM元素:

  • event.currentTarget:返回绑定事件处理器的DOM元素的引用
  • event.target:返回触发事件处理函数的DOM元素的引用

示例

class BtnGroup extends React.Component {
handleClick = (e) => {
if (e.target.tagName !== "BUTTON")
return;
e.currentTarget.style.backgroundColor = "skyblue"; 
e.target.innerText = "你点到我了";
}
render() {
return (
<div className="btn-group" onClick={this.handleClick}> 
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
</div> )
}
}

注:也可以利用event.nativeEvent属性访问到浏览器的底层事件,利用熟悉的原生事件对象获取相关的DOM元素。

特殊属性ref

Refs提供了一种方式。允许我们访问DOM节点,或者是在render方法中创建React元素

Refs是使用React.creatRef()创建的,并通过ref属性附加到React元素上。在构造组件时,通常将Refs分配给实例属性,以便可以在整个组件中引用它们。

class App extends React.Component {
constructor(props){
super(props);    
this.myRef = React.createRef();   
}    
render() {  
return ( 
<div className="btn-group" ref={this.myRef}>   
<button>戳我</button>  
</div>    
)    
} }

当ref被传递给render中的元素时,对该节点的引用可以通过ref的current属性访问:

class BtnGroup extends React.Component { 
constructor(props){ 
super(props); 
this.myRef = React.createRef(); 
}
handleClick = () => {   
const wrapEle = this.myRef.current;     
wrapEle.style.backgroundColor = "skyblue"; 
}  
render() {  
return (  
<div className="btn-group" ref={this.myRef}> 
<button onClick={this.handleClick}>戳我</button> 
</div>     
) 
} }

ref的属性也可以附加到React组件上,需要注意的是根据节点类型的不同ref的值也有差异:

  • 当ref属性用于HTML元素时,ref对象接收底层DOM元素作为其current属性
  • 当ref属性用于自定义class组件时,ref对象接收组件的挂载实例作为其current属性

注意:不能在函数组件上用ref属性,因为他们没有实例

findDOMNode方法

如果React组件已经被渲染,使用ReactDOM.findDOMNode可访问浏览器上的原生DOM元素

class App extends React.Component {
handleClick = () => { 
// 返回浏览器中与 App 组件相对应的 DOM 元素 const appDOM = ReactDOM.findDOMNode(this); 
appDOM.style.backgroundColor = "skyblue";
} 
render() { 
return (
<div>
<BtnGroup /> <button onClick={this.handleClick}>点我下试试</button>
</div> ) } }

要注意的是:

  1. 当组件渲染内容为null或false时,此API也会返回null
  2. 此API不能用于函数组件
  3. React推荐将此API作为底层DOM节点的应急方案,优先使用refs