安装
npx create-react-app 项目名称
JSX
JSX表示对象,Babel会把JSX转译成一个React.createElement()函数调用。
import React from "react"
import ReactDOM from "react-dom"
const name = "Jack"
const element = (
<div>Hello, {name}!</div>
)
ReactDOM.render(element, document.getElementById("root"))
React DOM 在渲染所有输入内容之前,默认会进行转译。它可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止XSS(cross-site-scripting, 跨站脚本)攻击。
元素渲染
React元素是不可变对象,一旦被创建,你就无法更改它的子元素或者属性。
组件
注意:组件名称必须大写字母开头!!!
React会将小写字母开头的组件视为原生的DOM标签。
函数组件(无状态组件)
接收唯一带有数据的 “props”(代表属性)对象与并返回一个 React 元素。
const name = "Jack"
function Element() {
return (<div>Hello, {name}!</div>)
}
ReactDOM.render(<Element />, document.getElementById("root"))
函数组件使用时给子组件传值转换为单个对象props传值。
function Element(props) {
return (<div>Hello, {props.name}!</div>)
}
const element = (<Element name={name}/>)
类组件(有状态组件)
const name = "Jack"
class Element extends React.Component {
render() {
return (<div>Hello, {name}!</div>)
}
}
ReactDOM.render(<Element />, document.getElementById("root"))
类组件通过props接收父组件传的值:
class Element extends React.Component {
render() {
return (<div>Hello, {this.props.name}!</div>)
}
}
向class组件中添加局部的state
- 方式1
class Element extends React.Component {
constructor(props) {
super(props);
this.state = {
age: 18
};
}
render() {
return (<div>Hello, {this.props.name}, 年龄:{this.state.age}!</div>)
}
}
- 方式2
class Element extends React.Component {
state = {
age: 18
};
render() {
return (<div>Hello, {this.props.name}, 年龄:{this.state.age}!</div>)
}
}
this.setState()更新组件,setState()的更新会合并。
class Element extends React.Component {
state = {
count: 0
};
componentDidMount() {
this.setState({
count: 2
})
}
render() {
return (
<div>
<div>计数器:{this.state.count}</div>
</div>
)
}
}
Props的只读性
组件声明无论是函数组件还是类组件创建的,都不能修改props。所有的React组件都必须像纯函数一样保护它们的props不被更改。
组件的声明周期
class Element extends React.Component {
/*
* 如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。
* 函数中不要调用setState方法
* 避免props的值赋值给state
*/
constructor(props) {
super(props);
this.state = {
age: 18
};
}
// 组件挂载时
componentDidMount() {}
/*
* 组件更新后立即渲染,初次加载不执行, 如果 shouldComponentUpdate() 返回值为 false,则不会调用 componentDidUpdate()。
* getSnapshotBeforeUpdate()的返回值是componentDidUpdate的第三个参数
*/
componentDidUpdate(prevProps, prevState, snapshot) {}
// 组件卸载时执行 不应调用setState,因为该组件永远不会重新渲染
componentWillUnmount() {}
// 唯一必须实现的方法
render() {
return (<div>Hello, {this.props.name}, 年龄:{this.state.age}!</div>)
}
// 不常用的生命周期
// 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()。
getSnapshotBeforeUpdate(prevProps, prevState) {}
// 判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为。
// 首次渲染或使用forceUpdate()时不会调用该方法 渲染执行之前被调用
// 仅作为性能优化的方式而存在
// 如果 shouldComponentUpdate() 返回 false,则不会调用 UNSAFE_componentWillUpdate(),render() 和 componentDidUpdate()。
shouldComponentUpdate(nextProps, nextState, nextContext) {}
// 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用
static getDerivedStateFromProps(props, state) {}
// 仅使用 Error boundaries 组件来从意外异常中恢复的情况;不要将它们用于流程控制。
/*
* React 的开发和生产构建版本在 componentDidCatch() 的方式上有轻微差别。
* 在开发模式下,错误会冒泡至 window,这意味着任何 window.onerror 或 window.addEventListener('error', callback) 会中断这些已经被 componentDidCatch() 捕获的错误。
* 相反,在生产模式下,错误不会冒泡,这意味着任何根错误处理器只会接受那些没有显式地被 componentDidCatch() 捕获的错误。
* 如果发生错误,你可以通过调用 setState 使用 componentDidCatch() 渲染降级 UI,但在未来的版本中将不推荐这样做。 可以使用静态 getDerivedStateFromError() 来处理降级渲染。
* */
static getDerivedStateFromError() {}
componentDidCatch(error, errorInfo) {}
}
事件处理
采用驼峰命名法
此语法问题在于每次渲染 LoggingButton
时都会创建不同的回调函数。在大多数情况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题。
在这两种情况下,React 的事件对象 e
会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind
的方式,事件对象以及更多的参数将会被隐式的进行传递。
class Element extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.handleClick = this.handleClick.bind(this)
}
// 方法一(推荐)
handleClick() {
this.setState(state => {
return {
count: state.count + 1
}
})
}
// 方法二
handleClick1() {
this.setState(state => ({
count: state.count + 2
}))
}
render() {
return (
<div>
<div>计数器:{this.state.count}</div>
<button onClick={this.handleClick}>+1</button>
<button onClick={() => this.handleClick1()}>+2</button>
</div>
)
}
}
组件渲染
- t条件渲染
if() {} else {}
渲染,&&
渲染,三目运算
render() {
let button;
if (this.state.flag) {
button = (<button onClick={this.handleClick}>+1</button>)
} else {
button = (<button onClick={() => this.handleClick1()}>+2</button>)
}
return (
<div>
<div>计数器:{this.state.count}</div>
{button}
</div>
)
}
class Element extends React.Component {
constructor(props) {
super(props);
this.state = {
count: true,
relCount: "a"
}
}
render() {
return (
<div>{this.state.count && this.state.relCount}</div>
)
}
}
- 列表(JSX允许嵌入任何表达式)
class Element extends React.Component {
constructor(props) {
super(props);
this.state = {
numbers: [1, 2, 3, 4, 5]
}
}
render() {
return (
<ul>
{this.state.numbers.map((item) => (
<li key={item.toString()}>{item}</li>
))}
</ul>
)
}
}
- 表单
class Element extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "Jack",
textArea: "请撰写一篇关于你喜欢的 DOM 元素的文章",
fruit: "",
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value,
})
}
handleSubmit(event) {
alert(this.state.value + this.state.textArea + this.state.fruit)
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>名字:
<input name="value" value={this.state.value} onChange={this.handleChange}/>
</label>
<label>textarea
<textarea name="textArea" value={this.state.textArea} onChange={this.handleChange}/>
</label>
<label>你喜欢的水果
<select name="fruit" value={this.state.fruit} onChange={this.handleChange}>
<option value="葡萄柚">葡萄柚</option>
<option value="酸橙">酸橙</option>
<option value="椰子">椰子</option>
<option value="芒果">芒果</option>
</select>
</label>
<input type='submit' value='提交'/>
</form>
)
}
}
状态提升(类似Vue中的子组件给父组件传值)
class Child extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.props.inputChange(event.target.value)
}
render() {
return (
<div>
<span>你好:</span>
<input value={this.props.name} onChange={this.handleChange}/>
</div>
)
}
}
class Element extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "Jack"
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(value) {
this.setState({
name: value
})
}
render() {
return (
<div>
<Child name={this.state.name} inputChange={this.handleChange}/>
</div>
)
}
}
组合和继承
组合
class Element extends React.Component {
render() {
return (
<div>{this.props.left}{this.props.right}</div>
)
}
}
const left = <span>名字:</span>
const right = <span>Jack</span>
const element = (<Element left={left} right={right}/>)
ReactDOM.render(element, document.getElementById("root"))
继承
## 组合和继承
#### 组合
```javascript
class Element extends React.Component {
render() {
return (
<div>{this.props.left}{this.props.right}</div>
)
}
}
const left = <span>名字:</span>
const right = <span>Jack</span>
const element = (<Element left={left} right={right}/>)
ReactDOM.render(element, document.getElementById("root"))
继承
不常见