React 基礎(chǔ)回顧

1. React 介紹

<img src="./images/1.png" width="70%"/>

React 是一個(gè)用于構(gòu)建用戶界面的 JavaScript 庫,它只負(fù)責(zé)應(yīng)用的視圖層,幫助開發(fā)人員構(gòu)建快速且交互式的 web 應(yīng)用程序。

React 使用組件的方式構(gòu)建用戶界面。

2. JSX 語法

在 React 中使用 JSX 語法描述用戶界面,它是一種 JavaScript 語法擴(kuò)展。

在 React 代碼執(zhí)行之前,Babel 會(huì)將 JSX 語法轉(zhuǎn)換為標(biāo)準(zhǔn)的 JavaScript API。

JSX 語法就是一種語法糖,讓開發(fā)人員使用更加舒服的代碼構(gòu)建用戶界面。

2.1 在 JSX 中使用表達(dá)式

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
}
function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}
const element = <h1>Hello, {formatName(user)}!</h1>;

JSX 本身其實(shí)也是一種表達(dá)式,將它賦值給變量,當(dāng)作參數(shù)傳入,作為返回值都可以。

function getGreeting(user) {
  if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
  }
  return <h1>Hello, Stranger.</h1>;
}

2.2 屬性

如果屬性值為字符串類型,需要加引號(hào),屬性名稱推薦采用駝峰式命名法。

const element = <div greeting="hello"></div>;

如果屬性值為JavaScript表達(dá)式,屬性值外面加大括號(hào)。

const element = <img src={user.avatarUrl} />;
// 注意大括號(hào)外面不能加引號(hào),JSX 會(huì)將引號(hào)當(dāng)中的內(nèi)容識(shí)別為字符串而不是表達(dá)式

2.3 JSX 單標(biāo)記必須閉合

如果 JSX 是單標(biāo)記,必須閉合,否則報(bào)錯(cuò)。

const element = <img src={user.avatarUrl} />
const element = <input type="text"/>

2.4 className

為 JSX 標(biāo)記添加類名需要使用 className,而不是class。

const element = <img src={user.avatarUrl} className="rounded"/>;

2.5 JSX 自動(dòng)展開數(shù)組

const ary = [<p>哈哈</p>, <p>呵呵</p>, <p>嘿嘿</p>];
const element = (
    <div>{ary}</div>
);
// 解析后
/*
    <div>
        <p>哈哈</p>
        <p>呵呵</p>
        <p>嘿嘿</p>
    </div>
*/

2.6 三元運(yùn)算

{ boolean ? <div>Hello React</div> : null }
{ boolean && <div>Hello React</div> }

2.7 循環(huán)

const persons = [{
  id: 1,
  name: '張三',
  age: 20
}, {
  id: 2,
  name: '李四',
  age: 15
}, {
  id: 3,
  name: '王五',
  age: 22
}]
<ul>
  { persons.map(person => <li key={person.id}> {person.name} {person.age} </li>) }
</ul>

2.8 事件

{/* 第一個(gè)參數(shù)即是事件對象 不需傳遞 */}
<button onClick={this.eventHandler}>按鈕</button>
{/* 需要傳遞事件對象 */}
<button onClick={e=>this.eventHandler('arg',e)}>按鈕</button>
{/* 最后一個(gè)參數(shù)即是事件對象 不需傳遞 */}
<button onClick={this.eventHandler.bind(null, 'arg')}>按鈕</button>
constructor () {
  this.eventHandler = this.eventHandler.bind(this)
}
eventHandler () {}
<button onClick={this.eventHandler}>按鈕</button>

2.9 樣式

2.9.1 行內(nèi)樣式
class App extends Component {
  render() {
    const style = {width: 200, height: 200, backgroundColor: 'red'};
    return <div style={style}></div>
  }
}
2.9.2 外鏈樣式
// Button.js
import styles from './Button.module.css';
class Button extends Component {
  render() {
    return <button className={styles.error}>Error Button</button>;
  }
}
2.9.3 全局樣式
import './styles.css'

2.10 ref 屬性

2.10.1 createRef
class Input extends Component {
  constructor() {
    super()
    this.inputRef = React.createRef()
  }
  render() {
    return (
      <div>
        <input type="text" ref={this.inputRef} />
        <button onClick={() => console.log(this.inputRef.current)}> button </button>
      </div>
    )
  }
}
2.10.2 函數(shù)參數(shù)
class Input extends Component {
  render() {
    return (
      <div>
        <input type="text" ref={input => (this.input = input)} />
        <button onClick={() => console.log(this.input)}>button</button>
      </div>
    )
  }
}
2.10.3 ref 字符串

不推薦使用,在嚴(yán)格模式下報(bào)錯(cuò)。

class Input extends Component {
  render() {
    return (
      <div>
        <input type="text" ref="username" />
        <button onClick={() => console.log(this.refs.username)}>button</button>
      </div>
    )
  }
}
2.10.4 獲取組件實(shí)例

點(diǎn)擊按鈕讓 input 文本框獲取焦點(diǎn)。

input 文本框以及讓文本框獲取焦點(diǎn)的方法定義在 Input 組件中,在 App 組件中引入 Input 組件,按鈕定義在 App 組件中。

// Input.js
class Input extends Component {
  constructor() {
    super()
    this.inputRef = React.createRef()
    this.focusInput = this.focusInput.bind(this)
  }
  focusInput() {
    this.inputRef.current.focus()
  }
  render() {
    return (
      <div>
        <input type="text" ref={this.inputRef} />
      </div>
    )
  }
}
// App.js
class App extends Component {
  constructor() {
    super()
    this.InputComponentRef = React.createRef()
  }
  render() {
    return (
      <div className="App">
        <Input ref={this.InputComponentRef} />
        <button onClick={() => this.InputComponentRef.current.focusInput()}>button</button>
      </div>
    )
}

<img src="./images/5.gif" />

3. 組件

3.1 什么是組件

React 是基于組件的方式進(jìn)行用戶界面開發(fā)的. 組件可以理解為對頁面中某一塊區(qū)域的封裝。

<img src="./images/2.png" width="70%"/>

3.2 創(chuàng)建組件

3.2.1 創(chuàng)建類組件
import React, { Component } from 'react';
class App extends Component {
    render () {
        return <div>Hello, 我是類組件</div>
    }
}
3.2.2 創(chuàng)建函數(shù)組件
const Person = () => {
     return <div>Hello, 我是函數(shù)型組件</div>;
}

注意事項(xiàng)

  1. 組件名稱首字母必須大寫,用以區(qū)分組件和普通標(biāo)簽。
  2. jsx語法外層必須有一個(gè)根元素

3.3 組件 props

3.3.1 props 傳遞數(shù)據(jù)

在調(diào)用組件時(shí)可以向組件內(nèi)部傳遞數(shù)據(jù),在組件中可以通過 props 對象獲取外部傳遞進(jìn)來的數(shù)據(jù)。

<Person name="喬治" age="20"/>
<Person name="瑪麗" age="10"/>
// 類組件
class Person extends Component {
  render() {
    return (
      <div>
        <h3>姓名:{this.props.name}</h3>
        <h4>年齡:{this.props.age}</h4>
      </div>
    );
  }
}
// 函數(shù)組件
const Person = props => {
  return (
    <div>
      <h3>姓名:{props.name}</h3>
      <h4>年齡:{props.age}</h4>
    </div>
  );
}

注意:

  1. props 對象中存儲(chǔ)的數(shù)據(jù)是只讀的,不能在組件內(nèi)部被修改。
  2. 當(dāng) props 數(shù)據(jù)源中的數(shù)據(jù)被修改后,組件中的接收到的 props 數(shù)據(jù)會(huì)被同步更新。( 數(shù)據(jù)驅(qū)動(dòng)DOM )
3.3.2 設(shè)置 props 默認(rèn)值
class App extends Component {
    static defaultProps = {}
}
function ThemedButton(props) {
}
ThemedButton.defaultProps = {
  theme: "secondary",
  label: "Button Text"
};
3.3.3 組件 children

通過 props.children 屬性可以獲取到在調(diào)用組件時(shí)填充到組件標(biāo)簽內(nèi)部的內(nèi)容。

<Person>組件內(nèi)部的內(nèi)容</Person>
const Person = (props) => {
    return (
        <div>{props.children}</div>
    );
}
3.3.4 單向數(shù)據(jù)流
  1. 在React中, 關(guān)于數(shù)據(jù)流動(dòng)有一條原則, 就是單向數(shù)據(jù)流動(dòng), 自頂向下, 從父組件到子組件.

  2. 單向數(shù)據(jù)流特性要求我們共享數(shù)據(jù)要放置在上層組件中.

  3. 子組件通過調(diào)用父組件傳遞過來的方法更改數(shù)據(jù).

  4. 當(dāng)數(shù)據(jù)發(fā)生更改時(shí), React會(huì)重新渲染組件樹.

  5. 單向數(shù)據(jù)流使組件之間的數(shù)據(jù)流動(dòng)變得可預(yù)測. 使得定位程序錯(cuò)誤變得簡單.

<img src="./images/3.png" />

3.4 類組件狀態(tài) state

3.4.1 定義組件狀態(tài)

類組件除了能夠從外部 (props) 接收狀態(tài)數(shù)據(jù)以外還可以擁有自己的狀態(tài) (state),此狀態(tài)在組件內(nèi)部可以被更新,狀態(tài)更新 DOM 更新。

組件內(nèi)部的狀態(tài)數(shù)據(jù)被存儲(chǔ)在組件類中的 state 屬性中,state 屬性值為對象類型,屬性名稱固定不可更改。

class App extends Component {
  constructor () {
    super()
    this.state = {
      person: { name: '張三', age: 20 },
    }
  }
  render () {
    return (
      <div>
        {this.state.person.name}
        {this.state.person.age}
      </div>
    );
  }
}
3.4.2 更改組件狀態(tài)

state 狀態(tài)對象中的數(shù)據(jù)不可直接更改,如果直接更改 DOM 不會(huì)被更新,要更改 state 狀態(tài)數(shù)據(jù)需要使用 setState方法。

class App extends Component {
  constructor () {
    this.state = {
      person: { name: '張三', age: 20 },
    }
    this.changePerson = this.changePerson.bind(this)
  }
    changePerson () {
    this.setState({
      person: {
        name: '李四',
        age: 15
      }
    })
  }
  render() {
    return (
      <div>
        {this.state.person.name}
        {this.state.person.age}
        <button onClick={this.changePerson}>按鈕</button>
      </div>
    );
  }
}
3.4.3 雙向數(shù)據(jù)綁定

雙向數(shù)據(jù)綁定是指,組件類中更新了狀態(tài),DOM 狀態(tài)同步更新,DOM 更改了狀態(tài),組件類中同步更新。組件 <=> 視圖。

要實(shí)現(xiàn)雙向數(shù)據(jù)綁定需要用到表單元素和 state 狀態(tài)對象。

class App extends Component {
  constructor () {
    this.state = {
      name: "張三"
    }
    this.nameChanged = this.nameChanged.bind(this)
  }
  nameChanged (event) {
    this.setState({name: event.target.value});
  }
  render() {
    return (
      <div>
        <div>{this.state.name}</div>
        <Person name={this.state.name} changed={this.nameChanged}/>
      </div>
    )
  }
}
const Person = props => {
    return <input type="text" value={props.name} onChange={props.changed}/>;
}

3.5 類組件生命周期函數(shù)

<img src="./images/4.jpg"/>

在組件完成更新之前需要做某種邏輯或者計(jì)算,就需要用到快照

componentDidUpdate(prevProps, prevState, snapshot) {}

getSnapshotBeforeUpdate 方法會(huì)在組件完成更新之前執(zhí)行,用于執(zhí)行某種邏輯或計(jì)算,返回值可以在 componentDidUpdate 方法中的第三個(gè)參數(shù)中獲取,就是說在組件更新之后可以拿到這個(gè)值再去做其他事情。

getSnapshotBeforeUpdate(prevProps, prevState) {
  return 'snapshot'
}

3.6 Context

通過 Context 可以跨層級傳遞數(shù)據(jù)

<img src="./images/6.png" width="70%"/>

// userContext.js
import React from "react"

const userContext = React.createContext("default value")
const UserProvider = userContext.Provider
const UserConsumer = userContext.Consumer

export { UserProvider, UserConsumer }
// App.js
import { UserProvider } from "./userContext"
class App extends Component {
  render() {
    return (
      <UserProvider value="Hello React Context">
        <A />
      </UserProvider>
    )
  }
}
// C.js
import { UserConsumer } from "./userContext"

export class C extends Component {
  render() {
    return (
      <div>
        <UserConsumer>
          {username => {
            return <div>{username}</div>
          }}
        </UserConsumer>
      </div>
    )
  }
}

context 的另一種用法

// userContext.js
export default userContext
// C.js
import userContext from "./userContext"

export class C extends Component {
  static contextType = userContext
  render() {
    return (
      <div>
        {this.context}
      </div>
    )
  }
}

4. 表單

4.1 受控表單

表單控件中的值由組件的 state 對象來管理,state對象中存儲(chǔ)的值和表單控件中的值時(shí)同步狀態(tài)的

class App extends Component {
  constructor () {
    this.state = { username: "" }
    this.nameChanged = this.nameChanged.bind(this)
  }
  
  nameChanged (e) {
    this.setState({username: e.target.value})
  }
  render() {
    return (
      <form>
        <p>{this.state.username}</p>
        <input type="text" value={this.state.username} onChange={this.nameChanged}/>
      </form>
    )
  }
}

4.2 非受控表單

表單元素的值由 DOM 元素本身管理。

class App extends Component {
  constructor () {
    this.onSubmit = this.onSubmit.bind(this)
  }
  onSubmit(e) {
    console.log(this.username.value)
    e.preventDefault();
  }
  render(
    <form onSubmit={this.onSubmit}>
      <input type="text" ref={username => this.username = username}/>
    </form>
  )
}

5. 路由

url地址與組件之間的對應(yīng)關(guān)系,訪問不同的url地址顯示不同的組件。

下載:npm install react-router-dom

5.1.1 路由基本使用

// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
function Index() {
    return <div>首頁</div>;
}
function News() {
    return <div>新聞</div>;
}
function App() {
  return (
    <Router>
      <div>
        <Link to="/index">首頁</Link>
        <Link to="/news">新聞</Link>
      </div>
      <div>
        <Route path="/index" component={Index}/>
        <Route path="/news" component={News}/>
      </div>
    </Router>
  );
}

5.1.2 路由嵌套

function News(props) {
  return (
    <div>
      <div>
        <Link to={`${props.match.url}/company`}>公司新聞</Link>
        <Link to={`${props.match.url}/industry`}>行業(yè)新聞</Link>
      </div>
      <div>
        <Route path={`${props.match.path}/company`} component={CompanyNews} />
        <Route path={`${props.match.path}/industry`} component={IndustryNews}/>  
      </div>    
    </div>
  );
}

function CompanyNews() {
    return <div>公司新聞</div>
}
function IndustryNews() {
    return <div>行業(yè)新聞</div>
}

5.1.3 路由傳參

import url from 'url';
class News extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [{
        id: 1,
        title: '新聞1'
      }, {
        id: 2,
        title: '新聞2'
      }]
    }
  }
    
  render() {
    return (
      <div>
        <div>新聞列表組件</div>
        <ul>
          this.state.list.map((item, index) => {
            return (
              <li key={index}>
                <Link to={`/detail?id=${item.id}`}>{item.title}</Link>
              </li>
            );
          })
        </ul>
      </div>
    );
  }
}
class Detail extends Component {
  constructor(props) {
    super(props);
  }
    const { query } = url.parse(this.props.location.search, true);
    console.log(query); // {id: 1}
  render() {
    return <div>新聞詳情</div>
  }
}

5.1.4 路由重定向

import { Redirect } from 'react-router-dom';

class Login extends Component {
  render() {
    if (this.state.isLogin) {
      return <Redirect to="/"/>
    }
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容