React 實(shí)戰(zhàn)

一、React 視圖層

項(xiàng)目創(chuàng)建

Create React App

npx create-react-app my-app
cd my-app
npm start   /   yarn start

JSX

基于 JS 的擴(kuò)展語法


jsx.png

如何將 React 元素渲染到DOM中?

const element = <h1>Hello,world</h1>;
ReactDOM.render(element,document.getElementById('root'))

組件

React 應(yīng)用組成和復(fù)用的基本單元

component = (props) => element

React組件必須像純函數(shù)一樣運(yùn)行!


.png

函數(shù)組件

import React from 'react';

function Welcome(props) {
    return <h1>Hello, {props.name} </h1>
}

export default Welcome;

類組件

必須有一個(gè) render() 方法

import React from 'react';

class Welcome extends React.Component {
    render() {
        return <h1>Hello, {this.props.name} </h1>
    }
}

export default Welcome;

列表中的 key

只需要保證,在同一個(gè)數(shù)組中的兄弟元素之間的 key 是唯一的。而不需要在整個(gè)應(yīng)用程序甚至單個(gè)組件中保持唯一。

理想情況下,key 應(yīng)該從數(shù)據(jù)中獲取,對(duì)應(yīng)著唯一且固定的標(biāo)識(shí)符,例如 post.id。

state

只能在類組件中使用,組件內(nèi)部的可變狀態(tài)


state.png

創(chuàng)建 Clock 時(shí)鐘組件

import React, { Component } from 'react';

class Clock extends Component {
    constructor(props) {
        super(props);
        this.state = { date: new Date() };
    }

    // 組件被掛載到 DOM 節(jié)點(diǎn)時(shí)會(huì)調(diào)用
    componentDidMount() {
        // setInterval 循環(huán)任務(wù) API
        this.timerID = setInterval(() => this.tick(), 1000);
    }

    // 組件從 DOM 卸載時(shí)會(huì)調(diào)用
    componentWillUnmount() {
        // 清除 setInterval 創(chuàng)建的定時(shí)任務(wù)
        clearInterval(this.timerID);
    }

    tick() {
        this.setState({
            date: new Date()
        });
    }

    render() {
        return (
            <div>Current Time:{this.state.date.toLocaleTimeString()} </div>
        );
    }
}

export default Clock;

setState 注意事項(xiàng)

不能通過 this.state 直接賦值

// Wrong 
this.state.comment = 'Hello';

使用 this.setState 方法賦值

// Correct
this.setState({comment: 'Hello'});

如果新的狀態(tài)需要依賴當(dāng)前狀態(tài)得到

// Wrong
this.setState({
    counter: this.state.counter + this.props.increment
})

// Correct
this.setState((state, props) => ({
    counter:satae.counter + props.increment
}))

setState 對(duì) state 的修改是部分修改,而不是對(duì)整個(gè) state 全量替換

setState.png

state 總結(jié)

  • Props:父組件傳遞給子組件的屬性,在子組件內(nèi)部只讀
  • State:組件內(nèi)部自己維護(hù)的狀態(tài),可以被修改

生命周期方法

針對(duì)類組件是有意義的,而函數(shù)組件沒有這些生命周期方法

生命周期方法.png

Form

受控組件

input 的值受 react 組件控制

import React, { Component } from 'react';

class NameForm extends Component {
    constructor(props) {
        super(props);
        this.state = { value: '' };

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(event) {
        this.setState({ value: event.target.value })
    }

    handleSubmit(event) {
        alert('A name was submitted:' + this.state.value);
        event.preventDefault();
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit} >
                <label>
                    Name:
                    <input type="text" value={this.state.value} onChange={this.handleChange} />
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}

export default NameForm;

非受控組件

import React, { Component } from 'react';

class NameForm extends Component {
    constructor(props) {
        super(props);

        this.handleSubmit = this.handleSubmit.bind(this);
        this.input = React.createRef();
    }

    handleSubmit(event) {
        alert('A name was submitted:' + this.input.current.value);
        event.preventDefault();
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit} >
                <label>
                    Name:
                    <input type="text" ref={this.input} />
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}

export default NameForm;

組件的組合用法

一般用法

import React from 'react';

function FanctBorder(props) {
    return (
        <div className={'FancyBorder FancyBorder-' + props.color}>
            {props.children}
        </div>
    )
}

function WelcomeDialog() {
    return (
        <FanctBorder color="blue">
            <h1 className="Dialog-title"> Welcome </h1>
            <p> Thank you for visiting our spacecraft! </p>
        </FanctBorder>
    )
}

export default WelcomeDialog;

更加靈活的組合方式

import React from 'react';

function FanctBorder(props) {
    return (
        <div>
            <div>{props.left}</div>
            <div><h3> this is line! </h3></div>
            <div>{props.right}</div>
        </div>
    )
}

function Left(props) {
    return (
        <div>
            <p> this is a Left! </p>
        </div>
    )
}

function Right(props) {
    return (
        <div>
            <p> this is a Right! </p>
        </div>
    )
}

function WelcomeDialog() {
    return (
        <FanctBorder left={<Left />} right={<Right />} />
    )
}

export default WelcomeDialog;
組合組件.png

React Hooks

React 16.8 以后,新的組件開發(fā)方法

React Hooks 編寫形式對(duì)比

先來寫一個(gè)最簡(jiǎn)單的組件,點(diǎn)我們點(diǎn)擊按鈕時(shí),點(diǎn)擊數(shù)量不斷增加。

有狀態(tài)組件寫法:

import React, { Component } from 'react';

class Example extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
        this.addCount = this.addCount.bind(this)
    }
    render() {
        return (
            <div>
                <button type="button" onClick={this.addCount}>
                    count is: {this.state.count}
                </button>
            </div>
        );
    }

    addCount() {
        this.setState({
            count: this.state.count + 1
        })
    }
}

export default Example;

React Hooks 寫法

import React, { useState, useEffect } from 'react';

function Example() {
    const [count, setCount] = useState(0)

    useEffect(() => {
        console.log(`useEffect=> You clicked ${count}`);
        return () => {
            console.log('解綁生命周期函數(shù)!')
        }
    }, [count]) // count 發(fā)生變化,就會(huì)執(zhí)行解綁


    return (
        <div>
            <button type="button" onClick={() => setCount((count) => count + 1)}>
                count is: {count}
            </button>
        </div>
    )
}

export default Example;

State Hook

StateHook.png
const [state, setState] = useState(initialState);

Effect Hook

EffectHook.png

useEffect(() =>{ effectFn(); return clearFn},[...dependencies])

一般用法

useEffect(() => {
        const getUserInfo = async () => {
            try {
                const userInfo = await fetch('https://api.github.com/users/hzjsj');
                console.log(userInfo)
            } catch (err) {
                console.error(err)
            }
        }
        getUserInfo();
    }, [])

其它 Hooks API

其它 HooksAPI.png

二、React Router 路由層

路由分類

1.服務(wù)端路由

請(qǐng)求發(fā)送到服務(wù)端,服務(wù)端返回對(duì)應(yīng)的頁面內(nèi)容

2.客戶端路由

請(qǐng)求不發(fā)送到服務(wù)端,有客戶端代碼更新頁面內(nèi)容

MPA 和 SPA

路由分類.png

React Router是什么

React 應(yīng)用中的客戶端路由解決方案

基礎(chǔ)示例

import React from "react";
import {
    BrowserRouter as Router,
    // HashRouter as Router,
    Switch,
    Route,
    Link,
    useHistory,
    useParams
} from "react-router-dom";

export default function BasicExample() {
    return (
        <Router>
            <div>
                <ul>
                    <li>
                        <Link to="/">Home</Link>
                    </li>
                    <li>
                        <Link to="/about">About</Link>
                    </li>
                    <li>
                        <Link to="/dashboard">Dashboard</Link>
                    </li>
                </ul>

                <hr />

                <Switch>
                    <Route exact path="/">
                        <Home />
                    </Route>
                    <Route path="/about">
                        <About />
                    </Route>
                    <Route path="/dashboard">
                        <Dashboard />
                    </Route>
                    <Route path="/user/:username">
                        <User />
                    </Route>
                </Switch>
            </div>
        </Router>
    );
}

// You can think of these components as "pages"
// in your app.

function Home() {
    const history = useHistory();
    return (
        <div>
            <h2>Home</h2>
            <button
                onClick={() => {
                    history.push("/user/jason");
                }}
            >
                Go User{" "}
            </button>
        </div>
    );
}

function About() {
    return (
        <div>
            <h2>About</h2>
        </div>
    );
}

function Dashboard() {
    return (
        <div>
            <h2>Dashboard</h2>
        </div>
    );
}

function User() {
    const params = useParams();
    const username = params.username;
    return <div>Welcome: {username}</div>;
}

Router

browserrouter:根據(jù) URL 中的 path 做路由跳轉(zhuǎn)

HashRouter:根據(jù) URL 中的 hash 部分做路由

Route

當(dāng) url 和 Route 中定義的 path 匹配時(shí),渲染對(duì)應(yīng)的組件

重要 props:path、exact

Switch

當(dāng)找到Switch組件內(nèi)的第一個(gè)路由規(guī)則匹配的Route組件后,立即停止后續(xù)的查找

路由跳轉(zhuǎn)

聲明式的組件方式:Link

命令式的 API 調(diào)用方式:history.push

Hooks

useHistory:獲取 history 對(duì)象

useParams:獲取路由中的參數(shù)

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

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

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