1. Hello World
最简易的React实例如下:
ReactDOM.render(
<h1>Hello World!</h1>,
document.getElementById('root')
);
2. JSX
JSX直观印象:<h1>ello, {name} !</h1> 或者 <Welcome name="vivian" />
- JSX表示对象(React 元素),JSX等价于
React.createElement() 函数调用
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
- JSX是一个表达式:可以将JSX赋值给变量、可以作为入参出参。
- 可以在JSX中嵌入表达式,通过大括号{}的形式
const element = <img src={user.avatarUrl} />;
const element = <div tabIndex="1">hhh</div>;
function fun() {
return <h1>hhh</h1>;
}
3. 元素渲染
按照自己的理解,React元素相当于JSX,直观理解:<h1>ello, {name} !</h1> 或者 <Welcome name="vivian" />
<div id="root"></div> 是根节点,该节点内的内容将由React DOM管理,将React元素渲染到根节点中:
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
React 元素是不可变的,一旦被创建,你就无法更改它的子元素或者属性。因此,想要更新UI只能重新渲染,即再次执行ReactDOM.render() (当然不止这种方式,class组件中的render也是)。注意每一次执行ReactDOM.render() ,React DOM会只更新变化的部分(只进行必要的更新)。
4. 组件 & Props
组件:传入props,传出React元素
函数组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
- 组件名称必须以大写字母开头
- 纯函数定义:不会更改入参,且多次调用下相同入参始终返回相同的结果。
- 所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
5. State & 生命周期
- state:class组件私有属性,可以通过
setState() 来进行变更 - 生命周期函数:
componentDidMount ,componentWillUnmount
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
使用setState注意点
- state的更新是合并的。
- state的更新可能是异步的,不要依赖this.state和this.props来更新下一个状态
this.setState({
counter: this.state.counter + this.props.increment,
});
this.setState((state, props) = ({
counter: state.counter + props.increment
}));
6. 事件处理
React元素事件处理与传统HTML的区别
<button onclick="activateLasers()">
Activate Lasers
</button>
<button onClick={activateLasers}>
Activate Lasers
</button>
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
如何正确绑定事件
法一:直接在constructor上绑定这个事件
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
法二:使用 class fields 正确的绑定回调函数
class LoggingButton extends React.Component {
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
法三(在公司里最常用):在回调中使用箭头函数。 此语法问题在于每次渲染 LoggingButton 时都会创建不同的回调函数。在大多数情况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题。
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
向事件传递参数
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
7. 条件渲染
if && - 三目运算符:
condition ? true : false 。
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
render() {
return (
{unreadMessages.length > 0 && <h1>hhh</h1>}
)
}
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
8. 列表 & Key
- key帮助React识别哪些元素改变了,比如被添加或删除。不是作为属性传递。
- key值需要在该数组中独一无二,一般选用元素的id,不建议使用索引来作为key值,因为项目的顺序可能发生变化,导致一些问题。
- 一个好的经验法则是:在
map() 方法中的元素需要设置 key 属性。
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
9. 表单
受控组件
- 受控组件:state是表单输入元素的唯一数据源,控制着用户输入过程中表单发生的操作。
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('提交的名字: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
名字:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="提交" />
</form>
);
}
}
<input type="text" value={this.state.value} onChange={this.handleChange} />
当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作。
<textarea value={this.state.value} onChange={this.handleChange} />
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
<select multiple={true} value={['B', 'C']}>
有时候使用受控组件会很麻烦,因为需要为数据变化的每种方式都编写事件处理函数,并通过一个React组件传递所有的输入state,也可以使用非受控组件,这是实现输入表单的另一种方式。
10. 状态提升
通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
11. 组合 vs 继承
React 有十分强大的组合模式。我们推荐使用组合而非继承来实现组件间的代码重用。
- React当中没有
槽(slot) 的概念限制,你可以将任何东西作为props进行传递,包括基本数据类型、React元素以及函数。
组合的常见使用方式:包含和特例
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!" />
);
}
12. React 哲学
略
|