1 creat-react-app を使用して反応プロジェクトを作成する
スキャフォールディングは webpack で構築されているため、最初から構築する必要はありません。
Xxx scaffolding: プログラムが xxx ライブラリに基づいてテンプレート プロジェクトをすばやく作成できるようにするために使用されます。
- 必要なすべての構成が含まれています (構文チェック、jsx コンパイル、devServer...)
- 関連するすべての依存関係をダウンロードしました
- シンプルなエフェクトを直接実行できます
React は、react プロジェクトを作成するためのスキャフォールディング ライブラリを提供します: create-react-app (React スキャフォールディングに基づくプロジェクトで、プロジェクトの各ファイルを読み取り、独自のビジネス ロジックを追加します)
プロジェクトの全体的な技術アーキテクチャは次のとおりです。react+webpack+es6+eslint
足場を使用して開発されたプロジェクトの機能: モジュール化、コンポーネント化、およびエンジニアリング
このライブラリを使用するとcreate-react-app
、足場を作成できます
1.1 プロジェクトを作成して開始する
プロジェクトを作成する手順の古いバージョン
グローバル インストール:npm i -g create-react-app
プロジェクトを作成するディレクトリに切り替えて、次のコマンドを使用します。create-react-arr hello-react
プロジェクト フォルダーに移動します。cd hello-react
スタートアップ プロジェクト:npm start
プロジェクトを作成する手順
npx create-react-app my-app
cd my-app
npm start
1.2 反応足場プロジェクト構造
public ---- 静的リソース フォルダー
favicon.icon ------ ウェブサイトのタブアイコン
index.html -------- メインページ
logo192.png ------- ロゴ画像
logo512.png ------- ロゴ画像
manifest.json ----- アプリケーションパッカー設定ファイル
robots.txt -------- クローラー プロトコル ファイル
src ---- ソースコードフォルダ
App.css -------- アプリ コンポーネントのスタイル
App.js --------- アプリコンポーネント
App.test.js ---- アプリのテストに使用
index.css ------ スタイル
index.js ------- エントリファイル(main.js 相当)
logo.svg ------- ロゴ画像
reportWebVitals.js
— ページ パフォーマンス分析ファイル (web-vitals ライブラリのサポートが必要)
setupTests.js
---- コンポーネント単体テストファイル (jest-dom ライブラリのサポートが必要)
<!-- React.StrictMode帮我们检查App组件及其子组件里面的写法是否合理 -->
<React.StrictMode>
<App />
</React.StrictMode>
1.3 Hello コンポーネント エクスペリエンス
詳細
第一种情况:
//文件module.js中定义
const React = {
a:1, b:2}
React.Component = class Component {
}
export default React
//使用
import React from './module.js'
const {
Component} = React//这叫从React身上解构
第二种情况:
const React = {
a:1, b:2}
export class Component {
}//使用分别暴露,暴露Component
export default React//使用默认暴露,暴露React
//使用
import React,{
Component} from './module.js'
//注意这不叫解构!!!这就是分别暴露之后的与引入,说明module文件里面使用了多种暴露形式
コンポーネント ファイルと通常の関数ファイルを区別する
最初のタイプ: すべての js が終了したら、最初の文字を見て、コンポーネントの最初の文字を大文字にします
2 番目の方法: コンポーネント ファイルのサフィックスを のように記述します.jsx
。react でファイルをインポートするときに省略できるサフィックスには、js と jsx の 2 種類があります。
最適化ポイント: ファイルのインポート時にパス名が長すぎるため、インデックスを定義できます。
エントリーファイル index.js
//React18不推荐这样写,会有警告,新写法可以参考React18
//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom";
import App from './App'
//渲染App组件到页面
ReactDOM.render(<App />, document.getElementById('root'))
1 つの注意事項: サブコンポーネントは最終的に導入され、App コンポーネントで使用されるため、サブコンポーネント スタイルの名前付けの競合が発生する場合は、スタイルのモジュール化を行う必要がある場合があります (関係をネストすることで回避できることは少なくなります)。
2 VScode の React プラグイン
ES7+ React/Redux/React-Native スニペット 作者:dsznajder
3. 機能インターフェースのコンポーネントコーディングプロセス
コンポーネントの分割: インターフェイスの分割、コンポーネントの抽出
静的コンポーネントを実現する: コンポーネントを使用して静的ページ効果を実現します
動的コンポーネントを実装する
初期化データを動的に表示する
データ型
データ名
どのコンポーネントに保存されますか?
インタラクション (バインディングイベントのリッスンから開始)
4 TodoList ケース
静的コンポーネントとスタイルを分割する
App.jsx はサブコンポーネントを置き、App.css は public スタイルを置き、残りのコンポーネントは取り除きます
todosデータの置き場所について
現時点では、父から息子へデータ props を渡す方法しか学習していないため、データは一時的に共通の父アプリに配置されます。
親から子へのデータ転送
//App给List组件传
<List todos={
this.state.todos} />
//List组件给Item组件传
//接收、解构
const {
todos } = this.props
//传递的两种写法
//return <Item key={todo.id} id={todo.id} name={todo.name} done={todo.done} />
return <Item key={
todo.id} {
...todo} />
//Item组件同样接收、解构、展示即可
Todo を追加: ヘッダーの入力により、App コンポーネントの状態が変化する必要があります (子から親への転送)。
アプリ コンポーネントはヘッダー サブコンポーネントに関数を渡します. 関数のコールバックはアプリに記述されており、サブコンポーネント内のデータはパラメーターの形式で親コンポーネントのアプリに返すことができます.
App.jsx
//用于添加一个todo,接收一个todo对象
addTodo = (todoObj) => {
//获取原todos
const {
todos } = this.state
//在数组前方追加一个todo
const newTodos = [todoObj, ...todos]
//更新状态
this.setState({
todos: newTodos })
}
<Header addTodo={
this.addTodo} />
ヘッダー.jsx
//绑定回车事件
<input onKeyUp={
this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认" />
//绑定事件的元素和要操作的元素相同,可以不用ref
handleKeyUp = (event) => {
//回车键keycode是13,现在不推荐使用keyCode了,event.keyCode !== 13
if (event.key !== 'Enter') return
//添加的todo名字不能为空
if (event.target.value.trim() === '') {
alert('输入不能为空')
return
}
//准备好新增的todoObj
const todoObj = {
id: nanoid(), name: event.target.value, done: false }
//将todoObj传递给App(子给父)
this.props.addTodo(todoObj)
//清空输入框
event.target.value = ''
}
マウスの移動効果
アイテム.jsx
state = {
mouse: false }
//鼠标移入移出的回调,高阶函数写法
handleMouse = (flag) => {
//注意:回调中函数可以写小括号,但是无论什么情况都要给事件一个回调函数,返回值是函数耶ok
return () => {
this.setState({
mouse: flag })
}
}
<li style={
{
backgroundColor: this.state.mouse ? '#95b196' : 'white' }} onMouseEnter={
this.handleMouse(true)} onMouseLeave={
this.handleMouse(false)}>
...
<button className="btn btn-danger" style={
{
display: this.state.mouse ? 'block' : 'none' }}>删除</button>
</li>
Todo がチェックされ、状態の変更に焦点が当てられます
アイテム サブコンポーネントで操作されるアイテムの ID を取得し、ステータスを確認します。状態データを更新するようにアプリに通知します (太陽から父へ ---- レイヤーごとに渡します)。
App.jsx
//更新todo对象---接收Item传过来的id和勾选
updateTodo = (id, done) => {
//获取原状态的todos
const {
todos } = this.state
//匹配处理数据
const newTodos = todos.map((todoObj) => {
//解构,然后相同的覆盖
if (todoObj.id === id) return {
...todoObj, done: done }
else return todoObj
})
//更新状态
this.setState({
todos: newTodos })
}
//给子组件List传递一个函数
<List todos={
this.state.todos} updateTodo={
this.updateTodo} />
リスト.jsx
//自己不用,反手就交给自己的子组件Item
const {
todos, updateTodo } = this.props
return <Item key={
todo.id} {
...todo} updateTodo={
updateTodo} />
アイテム.jsx
//给勾选框绑定onChange事件,传入操作的id
<input type="checkbox" defaultChecked={
done} onChange={
this.handleCheck(id)} />
//勾选、取消勾选的回调
handleCheck = (id) => {
//给input绑定,拿input的值,不需要ref,借助event即可
//孙子组件给App传递数据
return (event) => {
this.props.updateTodo(id, event.target.checked)
}
}
要約:状態があるところには、状態を操作する方法があります
小道具の配信を制限する
アプリはヘッダーとリストにデータを渡すため、ヘッダーとリストのコンポーネントで受信データを制限します
Header.jsx と List.jsx
//引入
import PropTypes from 'prop-types'
//对接收的props进行:类型、必要性限制
static propTypes = {
addTodo: PropTypes.func.isRequired
}
static propTypes = {
todos: PropTypes.array.isRequired,
updateTodo: PropTypes.func.isRequired
}
やることを削除する
App.jsx
//删除一个todo
deleteTodo = (id) => {
//获取原状态的todos
const {
todos } = this.state
//删除指定id的todo对象
const newTodos = todos.filter((todoObj) => {
return todoObj.id !== id
})
//更新状态
this.setState({
todos: newTodos })
}
//准备好的函数给孙子组件传过去,一层一层传,借助子组件List
<List todos={
this.state.todos} updateTodo={
this.updateTodo} deleteTodo={
this.deleteTodo} />
リスト.jsx
//反手交给Item,可以先解构
return <Item key={
todo.id} {
...todo} updateTodo={
updateTodo} deleteTodo={
deleteTodo} />
アイテム.jsx
//绑定事件
<button onClick={
() => this.handleDelete(id)} className="btn btn-danger" style={
{
display: this.state.mouse ? 'block' : 'none' }}>删除</button>
//删除一个todo的回调,非高阶写法
handleDelete = (id) => {
if (window.confirm('确定删除吗?')) {
this.props.deleteTodo(id)
}
}
ボトムフッター
defaultChecked は初回のみ有効で、変更後は応答がありませんdefaultChecked={doneCount === total ? true : false}
defaultChecked は実際にはかなりトリッキーです! ! !
checked はエラーを報告し、onChange が必要です
な<input type="checkbox" onChange={this.handleCheckAll} checked={doneCount === total ? true : false} />
最初に単純なすべて選択ボタンを完成させます
App.jsx
//全选
checkAll = (done) => {
//获取原状态的todos
const {
todos } = this.state
//加工数据
const newTodos = todos.map((todoObj) => {
return {
...todoObj, done: done }
})
//更新状态
this.setState({
todos: newTodos })
}
//传过去
<Footer todos={
this.state.todos} checkAll={
this.checkAll} />
フッター.jsx
//已完成个数--条件统计
const doneCount = todos.reduce((pre, todo) => {
return pre + (todo.done ? 1 : 0) }, 0)
//总数
const total = todos.length
//展示数据
<span>已完成{
doneCount}</span> / 全部{
total}
//写成defaultChecked会有bug(仅在第一次可以),写成checked会警告,所以写成回调形式
//全选checkbox的回调
handleCheckAll = (event) => {
this.props.checkAll(event.target.checked)
}
<input type="checkbox" onChange={
this.handleCheckAll} checked={
doneCount === total && total !== 0 ? true : false} />
次に、クリア完了ボタン関数を書き込みます
App.jsx
//清除已完成的
clearChecked = () => {
//获取原状态的todos
const {
todos } = this.state
const newTodos = todos.filter((todoObj) => {
return todoObj.done === false
})
//更新状态
this.setState({
todos: newTodos })
}
//传过去
<Footer todos={
this.state.todos} checkAll={
this.checkAll} clearChecked={
this.clearChecked} />
フッター.jsx
//清除已完成
handleClearChecked = () => {
this.props.clearChecked()
}
<button onClick={
this.handleClearChecked} className="btn btn-danger">清除已完成任务</button>
完全に機能するデモ