前段时间因工作需要,快速学习了一下React写了点代码,当时写过一篇初识React的一些感受,但限于时间,没空整理总结。最近搞完了小程序,稍微有点空闲,赶紧来复习总结一下。
参考资料:
JSX
JSZ是类似const element = <h1>Hello, world!</h1>
这样的语法,可以通过花括号{}
在其中插入变量或任意JS表达式,如const element = <h1>Hello, {name}!</h1>
或const element = <h1>Hello, {formatName(user)}!</h1>
。注意,由于JSX相比HTML更接近JavaScript,所以React DOM使用驼峰命名,例如class变为className。
React组件
我们经常用ES6的class
来定义一个组件,并且React组件名称总是使用大写字母开头,如:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
另外要注意几点:
- 可以使用props给组件传入参数,但所有的React组件都必须是纯函数,并禁止修改其自身props;
- 发
常见的React组件结构如下:
class Welcome extends React.Component {
// 构造函数,在里边使用super处理props;
// 并增加私有状态(state)
constructor(props) {
super(props);
this.state = {
data: xxx;
}
}
// 渲染函数,里边是使用jsx编写的该组件的html解构,如:
render() {
return <h1>hello, {this.props.name}--{this.state.data}</h1>
},
// 生命周期函数
// 渲染前
componentWillMount() {}
// 第一次渲染后
componentDidMount() {}
// 组件的prop变化导致组件更新后
componentWillReceiveProps() {}
// 组件接收到一个新的props或state时调用,可以在确认不需要更新组件时使用
shouldComponentUpdate() {}
// 组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用
componentWillUpdate() {}
// 在组件完成更新后立即调用。在初始化时不会被调用
componentDidUpdate() {}
// 在组件从 DOM 中移除的时候立刻被调用
componentWillUnmount() {}
}
其中, state要注意的:
1. 只能在构造函数中初始化state
2. 不能直接修改state,而是使用 this.setState({data: 'hehe'})
3. state更新可能是异步的,react为了优化性能,可能会将多个setState合并为一次更新。所以不能以来他们的值计算下一个状态,需要依赖前一次的值时,采用
this.setState((prevState, props) => {
counter: prevState.counter + props.increment
})
处理事件
通过React元素处理事件跟在DOM元素上处理事件非常相似,但有一些语法上的区别如下:
- React 事件使用驼峰命名;
- 通过JSX,传递一个函数作为事件处理程序,而不是一个字符串;
- React要阻止默认行为,必须明确使用
e.preventDefault()
; - 要额外在constructor中增加绑定;
例如:
```
class Welcome extends React.Component {
constructor(props) {
super(props);
this.state = {
data: xxx;
};
// 要对事件进行绑定,但有个autobind-decorator包,可以替你避免这些苦力活
this.clickHandler = this.clickHandler.bind(this);
}
// 没参数时:
render() {
return (
<h1 onClick={this.clickHandler}>
hello, {this.props.name}--{this.state.data}
</h1>
)
}
// 有参数时:
render() {
return (
<h1 onClick={(e) => this.clickHandler(e)}>
hello, {this.props.name}--{this.state.data}
</h1>
)
}
}
条件渲染
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
使用逻辑 && 操作符的内联 if 用法
render(){
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
使用条件操作符的内联 If-Else
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
列表渲染
列表渲染使用map()
方法,并且要在其中加上key
;
const todoItems = todos.map((todo, index) =>
// 没有id时,才使用index作为key
<li key={index}>
{todo.text}
</li>
);
表单
受控组件:
在 HTML 中,表单元素如 <input>
,<textarea>
和 <select>
表单元素通常保持自己的状态,并根据用户输入进行更新。而在 React 中,可变状态一般保存在组件的 state(状态) 属性中,并且只能通过 setState()
更新。
我们可以通过使 React 的 state 成为 “单一数据源原则” 来结合这两个形式。然后渲染表单的 React 组件也可以控制在用户输入之后的行为。这种形式,其值由 React 控制的输入表单元素称为“受控组件”。例如在render中,给value
绑定this.state.value
,然后再绑定一个onChange
事件来改变this.state.value
:
render() {
handleChange(event) {
this.setState({value: event.target.value});
}
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
状态提升
简单来说,父组件A中有子组件B和C,而B,C需要共同处理几个数据,并且处理后的结果要互相更新。例如在B中改变了数据,在C中要对应的显示出来。此时我们把需要共用的数据放到他们最近的祖先组件,也就是父组件A中。这个处理方式,就叫做状态提升。
详见官网例子: 状态提升
组合VS继承
- 混合vs继承
- 当你有一个组件a,又要弄一个跟他80%相似的组件b时:
- 混合:把那80%抽离出来做成通用组件x,剩下不同的20%分别传入通用组件,生成需要的a,b组件
- 继承:b继承自a,然后把不同的那20%在b里边重写覆盖掉。或者把那80%抽离出来写成公共组件x,让a,b分别继承x
- 由此可见,所为混合,我认为只是继承思路的子集,只是强制要求把公用的部分抽离出来。而继承则不强制要求,如果只有两处,a直接继承b自然最简单,但如果有3处或更多,写一个公共的x组件也未尝不是一个好方式。说到底组合和继承并无太大区别。