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') );
代码解析:
- 使用map方法遍历numbers数组,利用map的回调函数将数组中的每一个元素都变成li标签
- 将调用map方法后,的得到的新数组赋给listItems
- 将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也提供了以下几种方式:
- 通过事件对象获取DOM
- React的特殊属性
refs - ReactDOM提供的方法
findDOMNode
事件对象获取DOM
可以通过访问事件对象的currentTarget与target属性获取相关的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> ) } }
要注意的是:
- 当组件渲染内容为null或false时,此API也会返回null
- 此API不能用于函数组件
- React推荐将此API作为底层DOM节点的应急方案,优先使用refs