目次
6. Anti Desgin を使用した UI インターフェイスの実現
1. redux を保存するための新しい src/redux/index.js ファイルを作成します
1. HTML での React の適用
HTML で React を使用する際の核心は、3 つの依存関係をインポートすることです。
<!--React核心库-->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<!--React-dom用于支持react操作DOM-->
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!--引入babel用于将jsx转为js-->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
ケースコードは次のとおりです。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div id="root"></div>
</body>
<!--React核心库-->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<!--React-dom用于支持react操作DOM-->
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!--引入babel用于将jsx转为js-->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<!--这里一定要用这个type,让babel翻译script标签中的代码-->
<script type="text/babel">
//1、创建虚拟Dom
// 方式一 JSX
const VDOM = (
<h1 id="title">
<span>Hello,React</span>
</h1>
)
//方式二 js语法创建DOM
// const VDOM=React.createElement("h1",{id:"title"},React.createElement("span",{},"Hello,React"))
//2、将虚拟DOM转成真实DOM,并插入页面
ReactDOM.render(VDOM, document.getElementById("root"))
</script>
</html>
実行結果:
実行プロセスは次のとおりです。
2. Reactフレームワークの共通操作
足場の作成:
使用方法の詳細については、公式 Web サイトを確認してください。ここに私のメモがあります: React 公式中国語ドキュメント – ユーザー インターフェイスを構築するための JavaScript ライブラリ
npx create-react-app projectName
プロジェクトのパッケージ化
パッケージ化する際は、パスを対応付けるために package.json に属性 "homepage": "./" を追加する必要があります。
1. JSX の基本的な文法規則
ケース コード: object オブジェクトはレンダリングを実行できませんが、arr はマップ関数を介して走査および出力できます。
import React from 'react';
function App () {
const num=16
const bool=true
const name="string"
const arr=[1,2,3,4,"Jack",true]
const obj={name:"Mary",age:12}
return(
<div style={
{marginLeft:"20px"}}>
<div>num:{num}</div>
<div>bool:{bool}</div>
<div>name:{name}</div>
<div>arr:{arr}</div>
<div>arr遍历: {
arr.map((item,index)=>(
<p key={index}><span color={"red"}>{item}</span></p>
))
}</div>
{/*对象不能直接打印*/}
{/*<div>obj:{obj}</div>*/}
<div>obj.name:{obj["name"]}</div>
</div>
)
}
export default App;
効果:
2. 状態データの利用
参考ドキュメント:状態とライフサイクル – React
3. ライフサイクル
ネットワーク リクエストの送信は通常、componentDidMount で実行されます。
コンポーネントのオーバーヘッドの破棄は通常、componentWillUnmount で実行されます。
4. データとRefの双方向バインディング
方法 1:
class Test extends Component {
constructor (props, context) {
super(props, context)
this.state={
val: "233"
}
}
changeVal=(e)=>{
console.log(e)
this.setState({
val: e.target.value
})
console.log(e.target.value)
}
render () {
return (
<div>
<input type="text" onChange={this.changeVal} value={this.state.val} />
</div>
)
}
}
方法 2: ref を通じて実現する
class Test extends Component {
constructor (props, context) {
super(props, context)
this.state={
val: "233"
}
//1、在构造函数里创建ref的语法
this.myRef=React.createRef()
}
search=()=>{
//3、获取DOM元素
console.log(this.myRef.current.value)
}
render () {
return (
<div>
{/*2、绑定到元素上去*/}
<input type="text" ref={this.myRef} onChange={this.search}/>
</div>
)
}
}
refsの操作リファレンス:
5. PropTypes 検証ルール
参考:
6. React のスロット
参考:
7. エラー境界
何もレンダリングしないようにする
8. refs 要素の直接操作
関数コンポーネントでの使用:
参考: Refs 転送 – React
9. 上位コンポーネントの適用事例
コンポーネントのロード時間の再利用を実現
import React from "react"
export default function showTime (Comp) {
return class extends React.Component {
constructor (props, context) {
super(props, context)
this.state = {
startTime: new Date().getTime(),
loadingTime: 0
}
}
componentDidMount () {
let endTime = new Date().getTime()
this.setState({
loadingTime: endTime - this.state.startTime
})
}
render () {
return (
<Comp loadingTime={this.state.loadingTime}/>
)
}
}
}
このようにして、上位コンポーネントの再利用が実現され、この関数を使用する必要がある場合は、関数オブジェクトを呼び出して関数を追加するだけで済みます。
10. パフォーマンスの最適化
1. 新しいバージョン以降、コンポーネントは PureComponent を使用します。
PureComponent には独自の状態チェックと props チェックがありますが、変更がある場合はレンダリングを再書き込みします。それ以外の場合は、パフォーマンスを向上させるために再レンダリングは行いません。
関数コンポーネントの最適化: pureComonent と同等
React.memo() ライフサイクル フックは、pureCompnent と同等で、props と state が変更された場合にのみ更新されます。
ケースコード:
import React from "react"
const componentTwo = React.memo((props) => {
return (
<div>
</div>
)
})
export default componentTwo
2. コンポーネントが使い果たされた後は、忘れずにリソースを解放してください
11. フックのライフサイクルフックの使用
一般に関数コンポーネントはクラスコンポーネントよりも利用効率が高いのですが、関数コンポーネント(ステートレスコンポーネント)には状態などのプロパティが存在しないため、関数コンポーネントに状態やライフサイクルなどの要素を追加するフックがここで生まれました。
ケース 1: useState を使用して状態を変更する
import React,{useState} from "react"
function FunComponentOne () {
//定义一个变量,初始值为0,可通过setCount方法修改值
//第一个位置变量名,第二个位置方法名:修改变量的方法
const [count,setCount]=useState(0)
return (
<div>
<h2>{count}</h2>
<button onClick={()=>setCount(count+1)}>+</button>
</div>
)
}
export default FunComponentOne
ケース 2: useEffect ライフサイクル フック
import React,{useState,useEffect} from "react"
function FunComponentOne () {
//定义一个变量,初始值为0,可通过setCount方法修改值
//第一个位置变量名,第二个位置方法名
const [count,setCount]=useState(0)
//第二个参数为空,相当于生命周期钩子:componentDidMount+componentDidUpdate
//加载完成和数据修改都会走该函数
useEffect(() => {
console.log("=======================")
})
//第二个参数为空数组[],相当于componentDidMount,可以用于网络请求
useEffect(() => {
console.log("++++++++++++++++++++++++++++")
}, [])
//第二个参数可以传入有值的数组,当数组里的变量修改,会调用该函数
useEffect(() => {
console.log("!!!!!!!!!!!!!!!!!!!!!!!!!")
}, [count])
//当第二个参数为空数组[],且有返回函数时相当于componentWillUnMount
//一般用于销毁主键
useEffect(() => {
return function clearUp(){
console.log("clearUp")
}
},[])
return (
<div>
<h2>{count}</h2>
<button onClick={()=>setCount(count+1)}>+</button>
</div>
)
}
export default FunComponentOne
ケース 3: フック リデューサーは useState のアップグレード バージョンと同様です
ケース 4: カスタム フックによりカップリングが軽減される
頻繁に呼び出されるフックを独自のフックに定義できます。使用開始に注意してください。
12. React の計算されたプロパティ
Vue の計算と同等
3. コンポーネント間での値の受け渡し
1. 親コンポーネントと子コンポーネントの間で値を渡す
コンポーネントを介してパラメーターを渡す方法:
<ChildOne num={12}/>
<ChildTwo num={24}/>
サブコンポーネントはパラメータを受け取ります。
class ChildTwo extends Component {
render () {
return (
<div>
<h2>我是子组件ChildTwo: {this.props.name}</h2>
</div>
)
}
}
function ChildOne (prop) {
return(
<div>
<h2>ChildOne子组件:{prop.num}</h2>
</div>
)
}
2. 子から親に値を渡す
親コンポーネントを介してメソッドオブジェクトを子コンポーネントに渡すと、子コンポーネントはメソッドを呼び出し、対応するパラメータと処理を親コンポーネントに渡します。
親コンポーネント:
function ParentOne () {
function getSonData (data) {
console.log(data)
}
return (
<div>
<ChildThree getSonData={getSonData} />
</div>
)
}
サブアセンブリ:
function ChildThree (prop) {
function sendData(){
prop.getSonData("我是子组件的数据")
}
return(
<div>
<button onClick={sendData}>点击向父组件传值</button>
</div>
)
}
ここで、親コンポーネントはまず getSonData メソッド オブジェクトを子コンポーネントに渡します。子コンポーネントがメソッド オブジェクトを取得した後、prop を通じてそれを呼び出し、子コンポーネントのパラメータをメソッドに渡すことができます。このとき、メソッドは親コンポーネント内の が呼び出され、子コンポーネントのデータが取得されます。
3. 階層を超えたコミュニケーションを実現するコンテキスト
(1) まず、コンテキスト環境変数を管理するための MyContext.js を作成します
import React from "react"
//创建中间仓库
const MyContext=React.createContext(undefined)
export default MyContext
(2) ケース
データを提供する親コンポーネントの最初の層
class LayerOne extends Component {
constructor (props, context) {
super(props, context)
this.state={
name: "cute Tom"
}
}
render () {
return (
<div>
<h1>我是one</h1>
<MyContext.Provider value={this.state}>
<LayerTwo/>
</MyContext.Provider>
</div>
)
}
}
2 番目の層: 3 番目の層が含まれます
class LayerTwo extends Component {
render () {
return (
<div>
<h2>我是two</h2>
<LayerThree/>
</div>
)
}
}
3 番目のレイヤーはデータを直接使用できますが、どの MyContext であるかを宣言する必要があることに注意してください。
class LayerThree extends Component {
render () {
return (
<div>
<h3>我是three</h3>
<MyContext.Consumer>
{value => <div><h2>{value.name}</h2></div>}
</MyContext.Consumer>
</div>
)
}
}
LayerThree.contextType=MyContext
効果:
コンテキストフックケース
関数コンポーネントでの使用: コンテキストフック
リンク: useContext - ショートブック
4番目に、ネットワークリクエストフレームワークの使用
私のブログを参照してください:
フロントエンド フレームワークのネットワーク リクエスト Fetch Axios_Dragon Wu のブログ - CSDN ブログ
5、Reactルーティングの使用
公式ドキュメント: React Router: React.js の宣言型ルーティング
参考:
React Router 6 (React Routing) 最も詳細なチュートリアル - Alibaba Cloud Developer Community
6.v の新機能:
最初に依存関係をインストールします。
yarn add react-router-dom@6
宣言型ナビゲーション
(効率を高めるためにプログラムによるナビゲーションを使用することをお勧めします)
ケースコード: 通常、履歴レコードを含む BrowseRouter を使用します。
import React, { Component } from "react"
import { BrowserRouter, Routes, Route, Navigate, NavLink, useParams,Link,Outlet } from "react-router-dom"
class Home extends Component {
render () {
return (
<div>
<h1>Home</h1>
</div>
)
}
}
class About extends Component {
render () {
return (
<div>
<h1>About</h1>
</div>
)
}
}
function Detail () {
console.log(useParams())
return (
<div>
<h2>详情</h2>
<p>id: {useParams().id}</p>
</div>
)
}
function Main(){
return (
<div>
<h1>文档</h1>
<Link to={"/doc/one"}>文档1</Link>
<Link to={"/doc/two"}>文档2</Link>
<Link to={"/doc/three"}>文档3</Link>
{/*嵌套路由时注意书写这个标签*/}
<Outlet/> {/* 指定路由组件呈现的位置 */}
</div>
)
}
function App () {
return (
<div>
<BrowserRouter>
<div>
<NavLink to={"/home"}>首页</NavLink>|
<NavLink to={"/about"}>关于</NavLink>|
<NavLink to={"/detail/123"}>详情</NavLink>|
<NavLink to={"/doc"}>文档</NavLink>
</div>
<Routes>
<Route path={"/home"} element={<Home />} />
<Route path={"/about"} element={<About />} />
{/*嵌套路由*/}
<Route path={"doc"} element={<Main/>}>
<Route path={"one"} element={<h3>one</h3>} />
<Route path={"two"} element={<h3>two</h3>} />
<Route path={"three"} element={<h3>three</h3>} />
</Route>
{/*动态路由*/}
<Route path={"/detail/:id"} element={<Detail />} />
{/*路由重定向,也可用于404处理*/}
<Route path="/*" element={<Navigate to="/home" replace />} />
{/*404处理*/}
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
</div>
)
}
export default App
// 用来作为 404 页面的组件
const NotFound = () => {
return <div>你来到了没有知识的荒原</div>
}
プログラムによるナビゲーション
(1) src/router/index.js ファイルを新規作成します
import { Navigate } from "react-router-dom"
import Home from "../page/home/Home"
import HomeLeft from "../page/home/HomeLeft"
import HomeRight from "../page/home/HomeRight"
import About from "../page/About"
import Detail from "../page/Detail"
const routes=[
{
path: "/",
element: <Navigate to="/home" />
},
{
path: "home",
element: <Home />,
children: [
{
index: true,
element: <HomeLeft />
},
{
path: "right",
element: <HomeRight />
}]
},
{
path: "/about",
element: <About />
},
{
path: "/detail",
element: <Detail />
},
{ path: "*", element: <p>404页面不存在</p> }
]
export default routes
(2) src/index.jsにBrowserRouterコンテナを追加
注: BrowserRouter は App タグの外側の層に存在する必要があります
(3) App.jsは以下の通りです。
import React from 'react'
import routes from "./router/index.js"
import {useRoutes,NavLink } from "react-router-dom"
function App () {
// useRoutes可以用路由表生成<Routes>...</Routes>结构
// 根据路由表生成对应的路由规则
const element = useRoutes(routes)
return(
<div id="App">
<div>
<NavLink to={"/home"} >首页</NavLink>|
<NavLink to={"/about"}>关于</NavLink>|
<NavLink to={"/detail"}>详情</NavLink>
</div>
<div>
{element}
</div>
</div>
)
}
export default App
(4) ネストされたルートがある場合は、<Outlet/> タグを使用してサブコンポーネントが挿入される場所を示します
class Home extends Component {
render () {
return (
<div>
<h1>Home</h1>
<Link to={"/home/right"}>homeRight</Link>
<Link to={"/home"}>homeLeft</Link>
{/*嵌套路由时注意书写这个标签*/}
<Outlet/> {/* 指定路由组件呈现的位置 */}
</div>
)
}
}
プログラムによるジャンプ
push
デフォルトはモードです
export default function HomeNews() {
const navigate = useNavigate();
const jump = ()=>{
navigate('/home')
}
return (
<News>
<button onClick={jump}>点击跳转</button>
</News>
)
}
使用モード{replace:true}
になりますreplace
navigate('/home', { replace: true });
navigate(-1)
数字を使用してジャンプすることもできます
navigate(1)//传入数字
6. Anti Desgin を使用した UI インターフェイスの実現
公式ドキュメント: Ant Design - UI デザイン言語
1. プロジェクトに追加します。
yarn add antd
2. スタイルの紹介
スタイルをグローバルに反映: src/index.js にスタイルをインポートします。推奨されません。多くの無駄なスタイルがインポートされます。
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
オンデマンド、推奨
次の 2 つのメソッドは、使用されるコンポーネントのみをロードできます。
-
babel-plugin-importを使用します (推奨)。
-
yarn add babel-plugin-import
// .babelrc or babel-loader option { "plugins": [ ["import", { "libraryName": "antd", "style": "css" }] // `style: true` 会加载 less 文件 ] }
-
次に、antd からモジュールをインポートするだけで、スタイルを個別にインポートする必要はありません。以下の手動導入の方法に相当します。
// babel-plugin-import 会帮助你加载 JS 和 CSS import { DatePicker } from 'antd';
-
手動インポート
import DatePicker from 'antd/lib/date-picker'; // 加载 JS import 'antd/lib/date-picker/style/css'; // 加载 CSS // import 'antd/lib/date-picker/style'; // 加载 LESS
3. コンポーネント内で直接呼び出すことができます
七、Redux中央倉庫の使用
プロジェクトが少し複雑になると、ネイティブ状態ではデータキャッシュを効率的に管理・運用できない場合がありますが、Reduxを使用することでデータを均一に管理し、コード結合を減らすことができます。
フックリデューサーと同様に機能します
yarn add @reduxjs/toolkit
インストール参照:インストール | Redux 中国語公式 Web サイト
1. redux を保存するための新しい src/redux/index.js ファイルを作成します
//1、引入redux
import { configureStore } from "@reduxjs/toolkit"
//2、创建仓库
const store = configureStore({reducer})
//3、reducer为store服务的执行者, action={type:"",data:5}
function reducer (preState = 10, action) {
switch (action.type) {
case "add":
return preState + action.data
case "sub":
return preState - action.data
default:
return preState
}
}
//4、使用store
console.log(store)
//获取仓库的数据
console.log(store.getState())
//触发action
store.dispatch({
type: "add",
data: 5
})
console.log(store.getState())
2. src/index.jsに導入
実行結果:データが操作されていることがわかります
3. ロガーを通じて Redux ログを表示できます
yarn add redux-logger
ロガーを追加した後:
//1、引入redux
import { configureStore } from "@reduxjs/toolkit"
//引入日志
import { logger } from "redux-logger/src"
//2、创建仓库
// const store = configureStore({reducer})
const store = configureStore({
reducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger)
})
//3、reducer为store服务的执行者, action={type:"",data:5}
function reducer (preState = 10, action) {
switch (action.type) {
case "add":
return preState + action.data
case "sub":
return preState - action.data
default:
return preState
}
}
//4、使用store
console.log(store)
//获取仓库的数据
console.log(store.getState())
//触发action
store.dispatch({
type: "add",
data: 5
})
console.log(store.getState())
ログの出力を確認できます。
複数の減速機を組み合わせる
//1、引入redux
import { configureStore} from "@reduxjs/toolkit"
//引入日志
import { logger } from "redux-logger/src"
//2、创建仓库
// const store = configureStore({reducer})
const store = configureStore({
//合并多个reducer
reducer:{
reducer,
reducer2
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger)
})
//3、reducer为store服务的执行者, action={type:"",data:5}
function reducer (preState = 10, action) {
switch (action.type) {
case "add":
return preState + action.data
case "sub":
return preState - action.data
default:
return preState
}
}
function reducer2 (preState = { user: "", num: 5 }, action) {
const { type, data } = action
let newState = { ...preState }
switch (type) {
case "addUser":
newState.user = data.user
return newState
case "delUser":
newState.user = ""
return newState
default:
return newState
}
}
//4、使用store
console.log(store)
//获取仓库的数据
console.log(store.getState())
// //触发action
store.dispatch({
type: "add",
data: 5
})
console.log(store.getState())
store.dispatch({
type: "addUser",
data: {
user: "大猫"
}
})
store.dispatch({
type: "delUser"
})
操作結果:
4. Redux のモジュール管理
プロジェクトを作成するときは、重複を避けるために名前空間を追加する必要があります。
さらに、管理用に定数をファイルに抽出する必要もあります。
カテゴリ管理の削減要因:
Reducer/index.js: すべての Reducer をインポートして簡単に呼び出すことができます
import { count } from "./countReducer"
import {user} from "./userReducer"
export const reducers={
count,
user
}
redux/index.js は、Reducer のインデックス ファイルをインポートします。
//1、引入redux
import { configureStore} from "@reduxjs/toolkit"
//引入日志
import { logger } from "redux-logger/src"
//引入reducers
import { reducers } from "./reducers"
//2、创建仓库
// const store = configureStore({reducer})
const store = configureStore({
//合并多个reducer
reducer: reducers,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger)
})
5. 注意事項
戻り値の注意:
記述するときは、この形式のロジックに従うのが最善です。
Redux はデフォルトでは非同期操作をサポートしていません。一般的な実装の考え方は、非同期タスクの完了後に同期的にコールバックするときに Redux 操作を実行することです。
6. Redux を使用する完全な手順を要約する
インストールの依存関係:
yarn add @reduxjs/toolkit
yarn add react-redux
依存関係をログに記録します。
yarn add redux-logger
(1) 店舗倉庫を作成し、減速機を別管理
レデューサー: データ開発では、文字列型を一定の管理下に置く必要があります。
export function count(preState={num:0},action){
const {type,data}=action
let newState={...preState}
switch (type) {
case "num/add":
newState.num+=data.num
return newState
case "num/sub":
newState.num-=data.num
return newState
default:
return newState
}
}
export function user(preState={user:{name:"",age:1}},action){
const {type,data}=action
let newState={...preState}
switch (type) {
case "user/update":
newState.user=data.user
return newState
case "user/delete":
newState.user={name:"",age:1}
return newState
default:
return newState
}
}
すべてのリデューサーにインデックスを付けます。
import { count } from "./countReducer"
import { user } from "./userReducer"
export const reducers = {
count,
user
}
ストアウェアハウスを作成し、ログ記録を有効にします。
//1、引入redux
import { configureStore } from "@reduxjs/toolkit"
//引入日志
import { logger } from "redux-logger/src"
//导入reducers
import { reducers } from "./reducers"
//2、创建仓库
// const store = configureStore({reducer})
const store = configureStore({
//合并多个reducer
reducer: reducers,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger)
})
export default store
(2) src/index.jsファイルへインポート、グローバル設定
(3) 部品内での使用
import React from "react"
import { connect } from "react-redux"
function ReduxTestComp (props) {
return (
<div>
<h1>count: {props.count.num}</h1>
<h1>user:{props.user.user.age},{props.user.user.name}</h1>
<button onClick={()=>props.updateUser({user:{ name: "Jack", age: 12 }})}>修改用户</button>
<button onClick={()=> props.deleteUser()}>删除用户</button>
<button onClick={()=>props.addNum()}>+</button>
</div>
)
}
export default connect((state) => {//读取仓库中所有state
console.log(state)
return {
count: state.count,
user: state.user
}
}, (dispatch) => {//action操作
console.log(dispatch)
return {
updateUser: (data) => {
return dispatch({ type: "user/update", data: data })
},
deleteUser: ()=>{
return dispatch({type:"user/delete"})
},
addNum:()=>{
return dispatch({type:"num/add",data:{num:12}})
}
}
})(ReduxTestComp)
import React from "react"
import ReduxTestComp from "./component/reduxTest/ReduxTestComp"
function App () {
return (
<div id="App">
<ReduxTestComp />
</div>
)
}
export default App
これまでのところ、redux の完全な適用が実現されています。