安装
React CDN库
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
使用 create-react-app 快速构建
$ cnpm install -g create-react-app
$ create-react-app my-app
$ cd my-app/
$ npm start
基本使用
hello world示例
import React from 'react';
import { createRoot } from 'react-dom/client';
const element = (
<div>
<h1 data-myattribute = "somevalue">Hello, world!</h1>
</div>
)
const root = createRoot(document.querySelector('#root'));
root.render(element)
注: data-myattribute自定义属性
- class Clock extends React.Component
- this.props传值
- 更新元素渲染: React当元素被创建之后,你是无法改变其内容或属性的。 目前更新界面的唯一办法是创建一个新的元素 使用setInterval
class Clock extends React.Component {
render () {
return (
<div>
<h1>Hello, world!</h1>
<h2>现在是 {this.props.date}.</h2>
</div>
)
}
}
const root = createRoot(document.querySelector('root'));
function tick() {
root.render(<Clock date={new Date().toLocaleTimeString()} />)
}
setInterval(tick, 1000)
JSX
const i = 1
var myStyle = {
fontSize: 40,
color: 'red'
}
var arr = [
<h1>菜鸟教程</h1>,
<h2>学的不仅是技术,更是梦想!</h2>,
];
class Clock extends React.Component {
render () {
return (
<div>
{ /* 注释 */}
<h1>{1+1}</h1>
{ /*在 JSX 中不能使用 if else 语句,可以使用三元运算*/}
<h2>{i === 1 ? 'True!' : 'False'}</h2>
<p style={myStyle}>style样式</p>
{/* JSX 允许在模板中插入数组,数组会自动展开所有成员 */}
<div>{arr}</div>
</div>
)
}
}
const root = createRoot(document.getElementById('root'));
root.render(<Clock />)
组件
- 自定义的 React 类名以大写字母开头
- class 属性需要写成 className
- for 属性需要写成 htmlFor
复合组件
function App() {
return (
<div>
<Name name="菜鸟教程" />
<Nickname nickname="Runoob" />
</div>
)
}
function Name(props) {
return (
<h2>网站名称: {props.name}</h2>
)
}
function Nickname(props) {
return (
<h2>网站小名: {props.nickname}</h2>
)
}
const root = createRoot(document.getElementById('root'));
root.render(<App />)
React State(状态)
- 插入到 DOM,调用
componentDidMount()生命周期钩子 - 从 DOM 中移除,React 会调用
componentWillUnmount()这个钩子函数 - 数据自顶向下流动, state状态除了拥有并设置它的组件外,其它组件不可访问,组件间是隔离的
function FormattedDate(props) {
return <h2>现在是:{props.date.toLocaleTimeString()}.</h2>
}
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = { date: new Date() }
}
componentDidMount() {
this.timer = setInterval(() => {
this.tick()
})
}
componentWillUnmount() {
clearInterval(this.timer)
}
tick() {
this.setState({
date: new Date()
})
}
render() {
return (
<div>
<h1>hello world</h1>
<h2>现在是: {this.state.date.toLocaleTimeString()}.</h2>
<FormattedDate date={this.state.date} />
</div>
)
}
}
function App() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
)
}
const root = createRoot(document.getElementById('root'));
root.render(<App />)
React Props
默认props
class Clock extends React.Component {
render() {
return (
<div>{this.props.name}</div>
)
}
}
Clock.defaultProps = {
name: 'Runoob'
}
const root = createRoot(document.getElementById('root'));
root.render(<Clock />)
// root.render(<Clock name='jason' />)
示例
class Person extends React.Component {
constructor(props) {
super(props)
this.state = {
name: 'Amy',
age: 18
}
}
render() {
return (
<div>
<Name name={this.state.name} />
<Age age={this.state.age} />
</div>
)
}
}
class Name extends React.Component {
render() {
return (
<div>姓名是:{this.props.name}</div>
)
}
}
function Age(props) {
return (
<div>年龄是:{props.age}</div>
)
}
Name.defaultProps = {
name: 'Runoob'
}
const root = createRoot(document.getElementById('root'));
root.render(<Person />)
Props 验证
import PropTypes from 'prop-types'
var title = '菜鸟教程'
// var title = 123 // 报错 Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`
class MyTitle extends React.Component {
render() {
return (
<div>Hello, {this.props.title}</div>
)
}
}
MyTitle.propTypes = {
title: PropTypes.string
}
const root = createRoot(document.getElementById('root'));
root.render(<MyTitle title={title} />)
React 事件处理
// 1 2 3 4 绑定this 四选一
class Toggle extends React.Component {
constructor(props) {
super(props)
this.state = {
isToggle: true
}
// this.handleClick = this.handleClick.bind(this) >1
}
handleClick = () => { // >3
console.log('this', this)
this.setState(prevState => ({
isToggle: !prevState.isToggle
}))
}
render() {
return (
// <button onClick={(e) => this.handleClick(e)}> >2
<button onClick={this.handleClick.bind(this}> // >4
{this.state.isToggle ? 'ON' : 'OFF'}
</button>
)
}
}
const root = createRoot(document.getElementById('root'));
root.render(<Toggle />)
向事件处理程序传递参数
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
- 参数 e 作为 React 事件对象将会被作为
第二个参数进行传递
class Proper extends React.Component {
constructor(props) {
super(props)
this.state = {
name: 'jason'
}
}
preventPop(name, e) {
e.preventDefault();
alert(name)
}
render() {
// 两种方式二选一
return (
// <a href="https://reactjs.org" onClick={(e) => this.preventPop(this.state.name, e)}>点我</a>
<a href='https://reactjs.org' onClick={this.preventPop.bind(this, this.state.name)}>点我</a>
)
}
}
const root = createRoot(document.getElementById('root'));
root.render(<Proper />)
React 条件渲染
function MailBox(props) {
const messages = props.messages
return (
<div>
<h1>Hello</h1>
{messages.length > 0 &&
<h2>您有{messages.length}条未读消息!</h2>}
</div>
)
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
let root = createRoot(document.querySelector('#root'))
root.render(<MailBox messages={messages} />)
三目运算符
render() {
let isLoginIn = this.state.isLoginIn
return (
<div>
<Greeting isLoginIn={isLoginIn} />
{isLoginIn ? <LogOutButton onClick={this.handleLogOut} /> : <LoginButton onClick={this.handleLogin} />}
</div>
)
}
React 列表 & Keys
class Blog extends Component {
render() {
let posts = this.props.posts
// 在 jsx 中嵌入 map()
const sidebar = (
<ul>
{posts.map(item =>
<li key={item.id}>item</li>
)}
</ul>
)
const content = posts.map(item =>
<Post key={item.id} title={item.title} content={item.content} />
)
return (
<div>
{sidebar}
<hr />
{content}
</div>
)
}
}
class Post extends Component {
render() {
return (
<div key={this.props.id}>
<h3>{this.props.title}</h3>
<p>{this.props.content}</p>
</div>
)
}
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
let root = createRoot(document.querySelector('#root'))
root.render(<Blog posts={posts} />)
React 组件 API
设置状态:setState
- nextState 将要设置的新状态,该状态会和当前的state合并
this.setState(prevState => ({
isToggle: !prevState.isToggle
}))
替换状态:replaceState
- nextState,将要设置的新状态,该状态会替换当前的state
设置属性:setProps
- nextProps,将要设置的新属性,该状态会和当前的props合并
替换属性:replaceProps
- nextProps,将要设置的新属性,该属性会替换当前的props。
- replaceProps() 方法与setProps类似,但它会删除原有 props
强制更新:forceUpdate
- callback,可选参数,回调函数。该函数会在组件render() 方法调用后调用
获取DOM节点:findDOMNode
- 返回值:DOM元素DOMElement
判断组件挂载状态:isMounted
- 返回值:true或false,表示组件是否已挂载到DOM中
- es6废弃了,替换
componentDidMount() {
this.mounted = true;
}
componentWillUnmount() {
this.mounted = false;
}
React 组件生命周期
- Mounting(挂载):已插入真实 DOM
- Updating(更新):正在被重新渲染
- Unmounting(卸载):已移出真实 DOM
挂载
当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:
constructor(): 在 React 组件挂载之前,会调用它的构造函数。getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。render(): render() 方法是 class 组件中唯一必须实现的方法。componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用。
render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。
更新
每当组件的 state 或 props 发生变化时,组件就会更新。
当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:
getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。shouldComponentUpdate():当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。render(): render() 方法是 class 组件中唯一必须实现的方法。getSnapshotBeforeUpdate(): 在最近一次渲染输出(提交到 DOM 节点)之前调用。componentDidUpdate(): 在更新后会被立即调用。
render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。
卸载
当组件从 DOM 中移除时会调用如下方法:
componentWillUnmount(): 在组件卸载及销毁之前直接调用。
class Button extends Component {
constructor(props) {
super(props)
this.state = {
data: 0
}
this.setNewNumber = this.setNewNumber.bind(this)
}
setNewNumber() {
this.setState({
data: this.state.data + 1
})
}
render() {
return (
<div>
<button onClick={this.setNewNumber}>INCREMENT</button>
<Content myNumber={this.state.data}/>
</div>
)
}
}
class Content extends Component {
componentWillMount() {
console.log('component WILL Mount');
}
componentDidMount() {
console.log('component DID Mount');
}
componentWillReceiveProps(newProps) {
console.log('componentWillReceiveProps');
}
shouldComponentUpdate(newProps, newState) {
return true
}
componentWillUpdate() {
console.log('componentWillUpdate');
}
componentDidUpdate() {
console.log('componentDidUpdate');
}
componentWillUnmount() {
console.log('componentWillUnmount');
}
render() {
return (
<div>
<h3>{this.props.myNumber}</h3>
</div>
)
}
}
let root = createRoot(document.querySelector('#root'))
root.render(<Button />)
React AJAX
class UserGits extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
lastGitsUrl: '',
created_at: ''
}
}
componentDidMount() {
this.serverRequest = $.get(this.props.source, result => {
var lastGits = result[0]
this.setState({
username: lastGits.owner.login,
lastGitsUrl: lastGits.html_url,
created_at: lastGits.created_at
})
})
}
componentWillUnmount() {
this.serverRequest.abort()
}
render() {
return (
<div>
{this.state.username} 用户最新的Gist共享地址:
<a href={this.state.lastGitsUrl}>{this.state.lastGitsUrl}</a>
<p>创建时间为:{this.state.created_at}</p>
</div>
)
}
}
let root = createRoot(document.querySelector('#root'))
root.render(<UserGits source="https://api.github.com/users/octocat/gists" />)
React表单
class Content extends Component {
render() {
return (
<div>
<input type="text" value={this.props.myDataProp} onChange={this.props.updateStateProp} />
<h4>{this.props.myDataProp}</h4>
</div>
)
}
}
class HelloMessage extends Component {
constructor(props) {
super(props)
this.state = {
value: 'hello Jason'
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
value: event.target.value
})
}
render() {
var value = this.state.value
return (
<div>
<Content myDataProp={value} updateStateProp = {this.handleChange} />
</div>
)
}
}
let root = createRoot(document.querySelector('#root'))
root.render(<HelloMessage />)
React Refs
class MyComponent extends Component {
constructor(props) {
super(props)
this.inputRef = React.createRef()
}
handleClick = () => {
console.log('this.inputRef', this.inputRef);
this.inputRef.current.focus()
}
render() {
return (
<div>
<input type='text' ref={this.inputRef} />
<input type='button' value='点我输入框获取焦点' onClick={this.handleClick} />
</div>
)
}
}
let root = createRoot(document.querySelector('#root'))
root.render(<MyComponent />)