React知识点整理

99 阅读5分钟

image.png

安装

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

  • 返回值:truefalse,表示组件是否已挂载到DOM中
  • es6废弃了,替换
componentDidMount() {
    this.mounted = true;
}
componentWillUnmount() {
    this.mounted = false;
}

React 组件生命周期

  • Mounting(挂载):已插入真实 DOM
  • Updating(更新):正在被重新渲染
  • Unmounting(卸载):已移出真实 DOM

image.png

挂载

当组件实例被创建并插入 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 />)