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)ルーティングの基本的な使用法
- インターフェイスのナビゲーション領域と表示領域を明確にする
- ナビゲーション領域のタグがリンクタグに変更されます
<Link to="/xxxxx">Demo</Link>
- パスに一致するように表示領域にルートタグを書き込みます
<Route path='/xxxx' component={Demo}/>
<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
- NavLinkは、ルーティングリンクの強調表示を実現し、activeClassNameを介してスタイル名を指定できます。
- タグ本体の内容は特別なタグ属性です
- 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で対応しています。
- スイッチはルーティングマッチング効率を向上させることができます(シングルマッチング)
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)ルーティングの厳密なマッチングとあいまいマッチング
- デフォルトではあいまい一致が使用されます(単に覚えておいてください:[入力パス]には[一致パス]が含まれている必要があり、順序は同じである必要があります)
- 厳密一致をオンにします。
<Route exact={true} path="/about" component={About}/>
- 厳密なマッチングは、さりげなくオンにするのではなく、再度オンにする必要があります。オンにすると、セカンダリルートのマッチングを続行できなくなる場合があります。
7)リダイレクトの使用
通常、すべてのルーティング登録の下部に書き込まれます。すべてのルートが一致しない場合は、リダイレクトで指定されたルートにジャンプします。
<Switch>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
<Redirect to="/about" />
</Switch>
8)、ネストされたルーティング
- 子ルートを登録するときは、親ルートのパス値を書き込んでください
- ルートのマッチングは、登録されたルートの順に実行されます。
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>
</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>
</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>
</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の違い
-
基本的な原則は異なります
BrowserRouterは、IE9以下と互換性のないH5履歴APIを使用します
HashRouterはURLのハッシュ値を使用します
-
パス式が異なります
BrowserRouterのパスに#はありません。例:localhost:3000 / demo / test
HashRouterのパスには#が含まれています。例:localhost:3000 /#/ demo / test
-
更新後のルーティング状態パラメータへの影響
状態は履歴オブジェクトに保存されるため、BrowserRouterは効果がありません。
HashRouterが更新されると、ルーティング状態パラメーターは失われます
-
注:HashRouterは、パスエラーに関連するいくつかの問題を解決するために使用できます
ビデオ情報:
https://www.bilibili.com/video/BV1wy4y1D7JT
送信元アドレス:
https://github.com/hxt970311/react_demo