React研究ノート(2つ):Reactスキャフォールディング、Reactルーティング

3. Reactアプリケーション(Reactスキャフォールディングに基づく)

1)、create-react-appを使用してreactアプリケーションを作成します

1)足場を反応させる

reactは、reactプロジェクトを作成するためのスキャフォールディングライブラリを提供します:create-react-app

プロジェクトの全体的な技術アーキテクチャは次のとおりです。react+ webpack + es6 + eslint

2)プロジェクトを作成して開始します

最初のステップ、グローバルインストール:npm i -g create-react-app

2番目のステップは、作成するプロジェクトのディレクトリに切り替えて、次のコマンドを使用することです:create-react-app hello-react

3番目のステップは、プロジェクトフォルダーに入る方法です:cd hello-react

4番目のステップはプロジェクトを開始することです:npm start

3)足場プロジェクトの構造を反応させる

public-staticリソースフォルダー

favicon.icon-ウェブサイトタブアイコン

index.html-メインページ

Logo192.png-ロゴ画像

Logo512.png-ロゴ画像

マニフェスト.json-アプリケーションパッカー構成ファイル

robots.txt-クローラープロトコルファイル

src-sourceフォルダー

App.css-アプリコンポーネントスタイル

App.js-アプリコンポーネント

App.test.js-アプリのテストに使用

index.css-style

index.js-エントリファイル

​ logo.svg——logo图

reportWebVitals.js-ページパフォーマンス分析ファイル(Web-vitalsライブラリのサポートが必要)

setupTests.js-コンポーネントユニットテストファイル(jest-domライブラリのサポートが必要)

2)、todoListケース関連の知識ポイント

1)コンポーネントを分割し、静的コンポーネントを実装します。注:classNameとstyleの記述

2)動的初期化リスト、データを配置するコンポーネントの状態を決定する方法は?

  • コンポーネントの使用:独自の状態にする
  • 一部のコンポーネントは次を使用します:共通の親コンポーネントの状態にします(正式にはこの操作を呼び出します:状態の昇格)

3)父と息子のコミュニケーションについて:

  • [親コンポーネント] [子コンポーネント]にデータを渡す:小道具を渡す
  • [子コンポーネント] [親コンポーネント]にデータを渡す:小道具を通過し、親が事前に子に関数を渡す必要があります

親コンポーネント

import React, { Component } from 'react'
import Header from './components/Header/index'
import List from './components/List/index'
import Footer from './components/Footer/index'
import './App.css'

//创建并暴露App组件
export default class App extends Component {
    //初始化状态
    state = {
        todos: [
            { id: '001', name: '吃饭', done: true },
            { id: '002', name: '睡觉', done: true },
            { id: '003', name: '打代码', done: false }
        ]
    }

    addTodo = (todoObj) => {
        const { todos } = this.state
        const newTodos = [todoObj, ...todos]
        this.setState({ todos: newTodos })
    }

    updateTodo = (id, done) => {
        const { todos } = this.state
        const newTodos = todos.map(todoObj => {
            if (todoObj.id === id) {
                return { ...todoObj, done: done }
            } else {
                return todoObj
            }
        })
        this.setState({ todos: newTodos })
    }

    deleteTodo = (id) => {
        const { todos } = this.state
        const newTodos = todos.filter((todoObj) => {
            return todoObj.id !== id
        })
        this.setState({ todos: newTodos })
    }

    checkAllTodo = (done) => {
        const { todos } = this.state
        const newTodos = todos.map((todoObj) => {
            return { ...todoObj, done: done }
        })
        this.setState({ todos: newTodos })
    }

    clearAllDone = () => {
        const { todos } = this.state
        const newTodos = todos.filter((todoObj) => {
            return !todoObj.done
        })
        this.setState({ todos: newTodos })
    }

    render() {
        const { todos } = this.state
        return (
            <div className="todo-container">
                <div className="todo-wrap">
                    <Header addTodo={this.addTodo} />
                    <List todos={todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo} />
                    <Footer todos={todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone} />
                </div>
            </div>
        );
    }
}

ヘッダーサブコンポーネント

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { nanoid } from 'nanoid'
import './index.css'

export default class Header extends Component {
    static propTypes = {
        addTodo: PropTypes.func.isRequired
    }

    handleKeyUp = (event) => {
        const { target, keyCode } = event
        const { addTodo } = this.props
        if (keyCode !== 13) {
            return
        }
        if (target.value.trim() === '') {
            alert('输入不能为空')
            return
        }
        const todoObj = { id: nanoid(), name: target.value, done: false }
        addTodo(todoObj)
        target.value = ''
    }

    render() {
        return (
            <div className="todo-header">
                <input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认" />
            </div>
        )
    }
}

サブコンポーネントの一覧表示

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Item from '../Item/index'
import './index.css'

export default class List extends Component {
    static propTypes = {
        todos: PropTypes.array.isRequired,
        updateTodo: PropTypes.func.isRequired,
        deleteTodo: PropTypes.func.isRequired
    }

    render() {
        const { todos, updateTodo, deleteTodo } = this.props

        return (
            <ul className="todo-main">
                {
                    todos.map(todo => {
                        return <Item key={todo.id} {...todo} updateTodo={updateTodo} deleteTodo={deleteTodo} />
                    })
                }
            </ul>
        )
    }
}

アイテムサブコンポーネント

import React, { Component } from 'react'
import './index.css'

export default class Item extends Component {
    state = {
        mouse: false
    }

    handleMouse = (flag) => {
        return () => {
            this.setState({ mouse: flag })
        }
    }

    handleCheck = (id) => {
        const { updateTodo } = this.props
        return (event) => {
            updateTodo(id, event.target.checked)
        }
    }

    handleDelete = (id) => {
        const { deleteTodo } = this.props
        if (window.confirm('确定删除吗?')) {
            deleteTodo(id)
        }
    }

    render() {
        const { id, name, done } = this.props
        const { mouse } = this.state

        return (
            <li style={
   
   { backgroundColor: mouse ? '#ddd' : 'white' }} onMouseLeave={this.handleMouse(false)} onMouseEnter={this.handleMouse(true)}>
                <label>
                    <input type="checkbox" checked={done} onChange={this.handleCheck(id)} />
                    <span>{name}</span>
                </label>
                <button onClick={() => this.handleDelete(id)} className="btn btn-danger" style={
   
   { display: mouse ? 'block' : 'none' }}>删除</button>
            </li>
        )
    }
}

フッターサブコンポーネント

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import './index.css'

export default class Footer extends Component {
    static propTypes = {
        todos: PropTypes.array.isRequired,
        checkAllTodo: PropTypes.func.isRequired,
        clearAllDone: PropTypes.func.isRequired
    }

    handleCheckAll = (event) => {
        const { checkAllTodo } = this.props
        checkAllTodo(event.target.checked)
    }

    handleClearAllDone = () => {
        const { clearAllDone } = this.props
        clearAllDone()
    }

    render() {
        const { todos } = this.props
        const doneCount = todos.reduce((pre, todo) => { return pre + (todo.done ? 1 : 0) }, 0)
        const total = todos.length

        return (
            <div className="todo-footer">
                <label>
                    <input type="checkbox" onChange={this.handleCheckAll} checked={total !== 0 && doneCount === total} />
                </label>
                <span>
                    <span>已完成{doneCount}</span> / 全部{total}
                </span>
                <button onClick={this.handleClearAllDone} className="btn btn-danger">清除已完成任务</button>
            </div>
        )
    }
}

4)defaultCheckedとcheckedの違いに注意してください。類似点があります:defaultValueとvalue

5)状態はどこですか、状態の操作方法はどこですか

4.Reactルーティング

1)、関連する理解

1)SPAの理解
  • シングルページWebアプリケーション(シングルページWebアプリケーション、SPA)
  • アプリケーション全体には、完全なページが1つだけあります
  • ページ内のリンクをクリックしてもページは更新されず、ページが部分的に更新されるだけです。
  • すべてのデータはajaxリクエストを介して取得し、フロントエンドに非同期で表示する必要があります
2)ルーティングの理解

ルーティングとは何ですか?

  • ルートはマッピング関係です(キー:値)
  • キーはパスであり、値は関数またはコンポーネントである可能性があります

ルート分類

a。バックエンドルーティング

理解:値は関数であり、クライアントから送信された要求を処理するために使用されます

ルートの登録:router.get(path, function(req, res))

作業プロセス:ノードはリクエストを受信すると、リクエストパスに従って一致するルートを見つけ、ルート内の関数を呼び出してリクエストを処理し、レスポンスデータを返します。

b。フロントエンドルーティング

ブラウザ側のルーティング、値はコンポーネントであり、ページコンテンツの表示に使用されます

ルートの登録:<Route path="/test" component={Test}>

作業プロセス:ブラウザのパスが/ testになると、現在のルーティングコンポーネントがテストコンポーネントになります

2)、基本的なルーティングの使用

1)react-router-domを導入する

ヤーンはreact-router-domを追加します

2)ルーティングの基本的な使用法
  1. インターフェイスのナビゲーション領域と表示領域を明確にする
  2. ナビゲーション領域のタグがリンクタグに変更されます<Link to="/xxxxx">Demo</Link>
  3. パスに一致するように表示領域にルートタグを書き込みます<Route path='/xxxx' component={Demo}/>
  4. <App>1つ<BrowserRouter>または<HashRouter>
3)コードの実装

App.jsx

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Home from './pages/Home/index'
import About from './pages/About/index'

export default class App extends Component {
    render() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-offset-2 col-xs-8">
                        <div className="page-header"><h2>React Router Demo</h2></div>
                    </div>
                </div>

                <div className="row">
                    <div className="col-xs-2 col-xs-offset-2">
                        <div className="list-group">
                            {/* 编写路由链接 */}
                            <Link className="list-group-item" to="/about">About</Link>
                            <Link className="list-group-item" to="/home">Home</Link>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                <Route path="/home" component={Home} />
                                <Route path="/about" component={About} />
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from './App'

ReactDOM.render(
    <BrowserRouter><App /></BrowserRouter>,
    document.getElementById('root')
)

3)、ルーティングコンポーネントと一般コンポーネント

1)別の文章

一般的なコンポーネント:<Demo/>

ルーティングコンポーネント:<Route path="/demo" component={Demo}/>

2)異なる保管場所

一般的なコンポーネント:コンポーネント

ルーティングコンポーネント:ページ

受け取った小道具は異なります:

一般的なコンポーネント:コンポーネントラベルを書き込むときに渡されるもの、受信できるもの

ルーティングコンポーネント:3つの固定属性を受け取りました

history:
	go: ƒ go(n)
	goBack: ƒ goBack()
	goForward: ƒ goForward()
	push: ƒ push(path, state)
	replace: ƒ replace(path, state)
location:
	pathname: "/about"
	search: ""
	state: undefined
match:
	params: {}
	path: "/about"
	url: "/about"

4)NavLinkとパッケージNavLink

  1. NavLinkは、ルーティングリンクの強調表示を実現し、activeClassNameを介してスタイル名を指定できます。
  2. タグ本体の内容は特別なタグ属性です
  3. this.props.childrenを介して、タグ本体のコンテンツを取得できます
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { NavLink } from 'react-router-dom'
import './index.css'

export default class MyNavLink extends Component {
    static propTypes = {
        to: PropTypes.string.isRequired,
        children: PropTypes.string.isRequired
    }

    render() {
        return (
            <NavLink activeClassName="demo" className="list-group-item" {...this.props} />
        )
    }
}

App.jsx

import React, { Component } from 'react'
import { Route } from 'react-router-dom'
import MyNavLink from './components/MyNavLink/index'
import Home from './pages/Home/index'
import About from './pages/About/index'

export default class App extends Component {
    render() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-offset-2 col-xs-8">
                        <div className="page-header"><h2>React Router Demo</h2></div>
                    </div>
                </div>

                <div className="row">
                    <div className="col-xs-2 col-xs-offset-2">
                        <div className="list-group">
                            {/* 编写路由链接 */}
                            <MyNavLink to="/home">Home</MyNavLink>
                            <MyNavLink to="/about">About</MyNavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                <Route path="/home" component={Home} />
                                <Route path="/about" component={About} />
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

5)スイッチの使用

  1. 通常の状況では、パスとコンポーネントは1対1で対応しています。
  2. スイッチはルーティングマッチング効率を向上させることができます(シングルマッチング)

App.jsx

import React, { Component } from 'react'
import { Route, Switch } from 'react-router-dom'
import MyNavLink from './components/MyNavLink/index'
import Home from './pages/Home/index'
import About from './pages/About/index'

export default class App extends Component {
    render() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-offset-2 col-xs-8">
                        <div className="page-header"><h2>React Router Demo</h2></div>
                    </div>
                </div>

                <div className="row">
                    <div className="col-xs-2 col-xs-offset-2">
                        <div className="list-group">
                            {/* 编写路由链接 */}
                            <MyNavLink to="/home">Home</MyNavLink>
                            <MyNavLink to="/about">About</MyNavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                <Switch>
                                    <Route path="/home" component={Home} />
                                    <Route path="/about" component={About} />
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

6)ルーティングの厳密なマッチングとあいまいマッチング

  1. デフォルトではあいまい一致が使用されます(単に覚えておいてください:[入力パス]には[一致パス]が含まれている必要があり、順序は同じである必要があります)
  2. 厳密一致をオンにします。<Route exact={true} path="/about" component={About}/>
  3. 厳密なマッチングは、さりげなくオンにするのではなく、再度オンにする必要があります。オンにすると、セカンダリルートのマッチングを続行できなくなる場合があります。

7)リダイレクトの使用

通常、すべてのルーティング登録の下部に書き込まれます。すべてのルートが一致しない場合は、リダイレクトで指定されたルートにジャンプします。

<Switch>
	<Route path="/home" component={Home} />
	<Route path="/about" component={About} />
	<Redirect to="/about" />
</Switch>

8)、ネストされたルーティング

  1. 子ルートを登録するときは、親ルートのパス値を書き込んでください
  2. ルートのマッチングは、登録されたルートの順に実行されます。

9)、ルーティングコンポーネントにパラメータを渡します

1)パラメータパラメータ

ルーティングリンク(パラメータを運ぶ):

<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>

登録ルート(領収書の申告):

<Route path="/home/message/detail/:id/:title" component={Detail} />

受信パラメータ:this.props.match.params

親コンポーネント

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail/index'

export default class Message extends Component {
    state = {
        messageArr: [
            { id: '01', title: '消息1' },
            { id: '02', title: '消息2' },
            { id: '03', title: '消息3' }
        ]
    }
    render() {
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    {/* 向路由组件传递params参数 */}
                                    <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                {/* 声明接收params参数 */}
                <Route path="/home/message/detail/:id/:title" component={Detail} />
            </div>
        )
    }
}

サブコンポーネント

import React, { Component } from 'react'

const detailData = [
    { id: '01', content: '消息1详情' },
    { id: '02', content: '消息2详情' },
    { id: '03', content: '消息3详情' }
]
export default class Detail extends Component {
    render() {
        //接收params参数
        const { id, title } = this.props.match.params
        const findResult = detailData.find((detailObj) => {
            return detailObj.id === id
        })

        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:{findResult.content}</li>
            </ul>
        )
    }
}
2)検索パラメータ

ルーティングリンク(パラメータを運ぶ):

<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>

銀行コードの登録(宣言する必要はありません。通常の登録で十分です):

<Route path="/home/message/detail/" component={Detail} />

受信パラメータ:this.props.location.search

注:取得された検索は、urlencodedエンコードされた文字列であり、querystringで解析する必要があります

親コンポーネント

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail/index'

export default class Message extends Component {
    state = {
        messageArr: [
            { id: '01', title: '消息1' },
            { id: '02', title: '消息2' },
            { id: '03', title: '消息3' }
        ]
    }
    render() {
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    {/* 向路由组件传递search参数 */}
                                    <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                {/* search参数无需声明接收,正常注册路由即可 */}
                <Route path="/home/message/detail/" component={Detail} />
            </div>
        )
    }
}

サブコンポーネント

import React, { Component } from 'react'
import qs from 'querystring'

const detailData = [
    { id: '01', content: '消息1详情' },
    { id: '02', content: '消息2详情' },
    { id: '03', content: '消息3详情' }
]
export default class Detail extends Component {
    render() {
        //接收search参数
        const { search } = this.props.location
        const { id, title } = qs.parse(search.slice(1))
        const findResult = detailData.find((detailObj) => {
            return detailObj.id === id
        })

        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:{findResult.content}</li>
            </ul>
        )
    }
}
3)状態パラメータ

ルーティングリンク(パラメータを運ぶ):

<Link to={
   
   { pathname: '/home/message/detail/', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>

銀行コードの登録(宣言する必要はありません。通常の登録で十分です):

<Route path="/home/message/detail/" component={Detail} />

受信パラメータ:this.props.location.state

注:更新ではパラメーターを保持することもできます

親コンポーネント

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail/index'

export default class Message extends Component {
    state = {
        messageArr: [
            { id: '01', title: '消息1' },
            { id: '02', title: '消息2' },
            { id: '03', title: '消息3' }
        ]
    }
    render() {
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    {/* 向路由组件传递state参数 */}
                                    <Link to={
   
   { pathname: '/home/message/detail/', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>&nbsp;&nbsp;
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                {/* state参数无需声明接收,正常注册路由即可 */}
                <Route path="/home/message/detail/" component={Detail} />
            </div>
        )
    }
}

サブコンポーネント

import React, { Component } from 'react'

const detailData = [
    { id: '01', content: '消息1详情' },
    { id: '02', content: '消息2详情' },
    { id: '03', content: '消息3详情' }
]
export default class Detail extends Component {
    render() {
        //接收state参数
        const { id, title } = this.props.location.state || {}
        const findResult = detailData.find((detailObj) => {
            return detailObj.id === id
        }) || {}

        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:{findResult.content}</li>
            </ul>
        )
    }
}

10)プログラムによるルーティングとナビゲーション

this.prosp.historyオブジェクトのAPIを使用して、操作ルートにジャンプ、転送、および戻ります

  • this.prosp.history.push()
  • this.prosp.history.replace()
  • this.prosp.history.goBack()
  • this.prosp.history.goForward()
  • this.prosp.history.go()

11)、BrowserRouterとHashRouterの違い

  1. 基本的な原則は異なります

    BrowserRouterは、IE9以下と互換性のないH5履歴APIを使用します

    HashRouterはURLのハッシュ値を使用します

  2. パス式が異なります

    BrowserRouterのパスに#はありません。例:localhost:3000 / demo / test

    HashRouterのパスには#が含まれています。例:localhost:3000 /#/ demo / test

  3. 更新後のルーティング状態パラメータへの影響

    状態は履歴オブジェクトに保存されるため、BrowserRouterは効果がありません。

    HashRouterが更新されると、ルーティング状態パラメーターは失われます

  4. 注:HashRouterは、パスエラーに関連するいくつかの問題を解決するために使用できます

ビデオ情報

https://www.bilibili.com/video/BV1wy4y1D7JT

送信元アドレス

https://github.com/hxt970311/react_demo

おすすめ

転載: blog.csdn.net/qq_40378034/article/details/113813680