用于构建用户界面的 JavaScript 库
声明变量 name,并包裹在大括号中
const name = 'world';
const element = <h1>Hello, {name}</h1>;
在 JSX 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式
可以使用大括号,来在属性值中插入一个 JavaScript 表达式:
const element = <img src={user.avatarUrl}></img>;
JSX 标签里能够包含很多子元素:
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
等效于:
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
页面根节点
<div id="root"></div>
将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入
const root = ReactDOM.createRoot(
document.getElementById('root')
);
const element = <h1>Hello, world</h1>;
root.render(element);
组件允许你将 UI 拆分为独立可复用的代码片段,并对每个片段进行独立构思
注意:组件名称必须以大写字母开头
接受任意的入参(即 “props”)
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”
const element = <Welcome name="Sara" />;
子组件(children)例子:
<Welcome name="react">
<span>children</span>
</Welcome>
最终props为
{name: 'react', children: {…}}
组件无论是使用 函数声明还是通过 class 声明,都决不能修改自身的 props
纯函数:函数不会尝试更改入参,且多次调用下相同的入参始终返回相同的结果。
如:
function sum(a, b) {
return a + b;
}
相反,下面这个则不是纯函数
function withdraw(account, amount) {
account.total -= amount;
}
所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
componentDidMount
:方法会在组件已经被渲染到 DOM 中后运行
componentWillUnmount
:方法会在组件卸载前调用
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
例如,此代码不会重新渲染组件:
// 错误
this.state.comment = 'Hello';
而是应该使用 setState()
:
// 正确
this.setState({comment: 'Hello'});
构造函数是唯一可以给 this.state
赋值的地方。
出于性能考虑,React 可能会把多个 setState()
调用合并成一个调用。
因为 this.props
和 this.state
可能会异步更新,所以你不要依赖他们的值来更新下一个状态。
比如:
// 错误
this.setState({
counter: this.state.counter + this.props.increment,
});
解决这个问题:
可以让 setState()
接收一个函数而不是一个对象
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
当你调用 setState()
的时候,React 会把你提供的对象合并到当前的 state。
示例:
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
先来报错案例:
说明: JSX 回调函数中的 this
,在 JavaScript 中,class 的方法默认不会绑定this
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'hello' };
}
handleClick() {
console.log(this) // 这里this为undefined
this.setState({ message: '你好' })
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.message}</h2>
<button onClick={this.handleClick}>点击事件</button>
</div>
);
}
}
为了在回调中使用 this
,对this.handleClick.bind(this);这个绑定是必不可少的
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'hello' };
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this)
this.setState({ message: '你好' })
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.message}</h2>
<button onClick={this.handleClick}>点击事件</button>
</div>
);
}
}
class LoggingButton extends React.Component {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
if
语句进行条件渲染function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
render() {
const count = 0;
return (
<div>
{count && <h1>Messages: {count}</h1>}
</div>
);
}
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
使用 map
函数
function NumberList() {
const numbers = [1, 2, 3, 4, 5];
return (
<ul>
{
numbers.map(item => {
return <li>{item}</li>
})
}
</ul>
)
}
应当给数组中的每一个元素赋予一个确定的标识
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串,最好是用id
注意,最好不要用索引index作为key,有可能会导致一些问题
function NumberList() {
const numbers = [1, 2, 3, 4, 5];
return (
<ul>
{
numbers.map(item => {
return <li key={item.toString()}>{item}</li>
})
}
</ul>
)
}
渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
class FormDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
textAreaValue: '',
selectValue: '',
}
}
handleNameChange = (e) => {
this.setState({ value: e.target.value })
}
handleTextAreaChange = (e) => {
this.setState({ textAreaValue: e.target.value })
}
handleSelectChange = (e) => {
this.setState({ selectValue: e.target.value })
}
handleSubmit = () => {
alert('提交的 input:' + this.state.value)
alert('提交的 textarea:' + this.state.textAreaValue)
alert('提交的 select:' + this.state.selectValue)
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
名字:
<input value={this.state.value} onChange={this.handleNameChange}></input>
</label>
<br />
<label>
文章:
<textarea value={this.state.textAreaValue} onChange={this.handleTextAreaChange} />
</label>
<br />
<label>
选择你喜欢的风味:
<select value={this.state.selectValue} onChange={this.handleSelectChange}>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
</label>
<br />
<input type="submit" value="提交" />
</form>
)
}
}
当需要处理多个 input
元素时,我们可以给每个元素添加 name
属性,并让处理函数根据 event.target.name
的值选择要执行的操作。
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<label>
参与:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
来宾人数:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升”
示例:
// 子组件 A
class A extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
handleClick = () => {
// 这里调用父组件传过来的方法进行修改父组件的state
this.props.onGetAName('这是a传过来的')
}
render() {
return (
<div>
<h3>这是A组件</h3>
<button onClick={this.handleClick}>a按钮</button>
</div>
)
}
}
// 子组件 B
class B extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
<h3>这是B组件,接收a的数据:{this.props.name}</h3>
</div>
)
}
}
// 父组件
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
aName: ''
};
}
getName = (val) => {
this.setState({ aName: val })
}
render() {
return (
<div className="App">
<A onGetAName={this.getName}></A>
<B name={this.state.aName}></B>
</div>
)
}
}
推荐使用组合而非继承来实现组件间的代码重用。
组件使用一个特殊的 children
prop 来将他们的子组件传递到渲染结果中:
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
这使得别的组件可以通过 JSX 嵌套,将任意组件作为子组件传递给它们。
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
{} 中绑定一个style对象
<h1 style={{ color: "red" }} onClick={this.click}>
hello
</h1>
推荐:
const style = {
fontSize: "50px",
color: 'red'
};
function App() {
return (
<div>
<h1 style={style}>这是 App</h1>
<Hello />
</div>
);
}
.title {
color: red;
}
App.js
<h1 className="title" onClick={this.click}>
hello
</h1>