学习视频
12. Props, Immutability, and One-Way Data Flow_哔哩哔哩_bilibili
React笔记
前置知识 这里写了常用到的 js知识
const { title,author,publicationDate,hasMovieAdaptation,genres,reviews,translations } = book; console .log (title, author);const [firstBook, secondBook, ...otherBooks ] = books; console .log (firstBook, secondBook, otherBooks);const newGenres = [...book.genres , "horror" ];console .log (newGenres);const updateBook = { ...books, data :"123" }; updateBook;const summary = `${title} is a book,and published in ${publicationDate.split("-" )[0 ]} ` ; summary;const hasMovie = books.hasMovieAdaptation ? "Yes" : "No" ; hasMovie;const publicationDateYear = (str ) => str.publicationDate .split ("-" )[0 ];console .log (publicationDateYear (book));console .log ( true && "nihao" );console .log ( false || "nihao" );const count = book.reviews .librarything ?? 0 ; count;function getTotalReviewcount (book ){ const goodreads = book.reviews ?.goodreads ; const librarything = book.reviews ?.librarything ?? 0 ; return goodreads + librarything; }const totalReviewCount = getTotalReviewcount (book); totalReviewCount;const x =[1 ,2 ,3 ,4 ,5 ].map (num => num * 2 );console .log (x);const arr = [1 ,2 ,3 ,4 ,5 ];const sum = arr.reduce ((sum, cur ) => sum + cur, 0 );console .log (sum);const arr3 = [1 , 3 , 2 , 4 , 5 ];const filteredArr = arr3.filter ((num ) => num % 2 === 0 ); filteredArr;const arr1 = [1 , 3 , 2 , 4 , 5 ];const sortedArr = arr1.sort ((a, b ) => a - b); sortedArr; arr1;const arr2 = [1 , 3 , 2 , 4 , 5 ];const slicedArr2 = arr2.slice (0 , 5 ).sort ((a, b ) => a - b);console .log (slicedArr2); arr2; onClick={() => onDeleteItem (item.id )} function greet ( ) { console .log ("Hello!" ); }setTimeout (greet, 2000 );
概述 React 是用于构建用户界面的 JavaScript 库。
它提供了组件、状态管理、生命周期方法等功能来帮助开发者构建复杂的前端应用
其主要功能是实现后端数据与前端页面的即时更新,同时减少单一使用js
时的繁冗工作量
项目结构 采用 npx create-react-app my-app
,创建react项目文件夹
my-app/ ├── node_modules/ ├── public/ │ ├── favicon.ico │ ├── index.html │ ├── manifest.json │ └── robots.txt ├── src/ │ ├── App.css │ ├── App.tsx │ ├── App.test.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── reportWebVitals.ts │ └── setupTests.ts ├── .gitignore ├── package.json ├── README.md ├── tsconfig.json └── yarn.lock / package-lock.json
React 三要素 1. 组件(Component) 组件是 React 的基础构建块,每个 React 应用都是由一个个组件组合而成的。React为每一个组件渲染一个视图,这些视图组成UI。每个组件都拥有自己的 “数据 ” “(js)逻辑 ” “外观 ”
类组件 :通过 ES6 的类来定义,包含状态(state)和生命周期方法。
函数组件 :React 16.8 之后推荐的方式,使用函数定义组件并结合钩子(Hooks)来管理状态和生命周期。
组件不可嵌套
示例 :
function Welcome (props ) { return <h1 > Hello, {props.name}</h1 > ; }
什么是 JSX ? jsx是一种声明语法,用来描述组件的外观,根据数据和逻辑工作。通常与 React 一起使用,允许在 JavaScript 代码中编写类似 HTML 的标签
类 HTML 的语法 :
JSX 允许在 JavaScript 代码中嵌入类似 HTML 的标签,使得编写用户界面时更加直观和简洁。虽然看起来像 HTML,但 JSX 实际上会被编译成 JavaScript 函数调用。
支持表达式 :
必须返回一个父元素 :
样式和属性的处理 :
2. 状态(State) 状态是组件内部的数据,它决定了组件的行为和显示的内容。
状态是可变的,随着用户的交互或其他事件触发,它会发生变化并重新渲染 组件。
在类组件中,状态通过 this.state
来管理,在函数组件中使用 useState
钩子 来管理。
示例 :
// 函数组件使用状态 import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); //字符串参数 {/*const [test, setTest] = useState(name) setTest({name:"john"}*/} return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }
什么是钩子?
在 React 中,钩子就是use开头的状态组件,允许你在函数组件中使用状态和其他 React 特性,而不需要编写类组件。
常见的 React 钩子有:
useState
:用于在函数组件中添加状态变量。
useEffect
:用于执行副作用操作(如数据获取、订阅或手动更改 DOM)。
useContext
:用于在组件树中共享数据,而无需逐层传递 props。
3. 属性(Props) props
是组件之间传递数据的方式。
父组件可以通过 props
向子组件传递数据,子组件无法修改 props
,它们是只读的。props
的主要作用是让组件的渲染更加灵活和可复用 。
在传递中,我们可以使用 js 中的重构
来传递对象的名称而不是props
,但是不要忘记使用{}
注 : React是单向数据流,数据只能从父组件流向子组件
示例 :
// 父组件向子组件传递数据 function Menu() { return ( <main className="menu"> <h2>our pizzas</h2> <Pizza name= "Focaccia" ingredients= "Bread with italian olive oil and rosemary" price="6" photoName="pizzas/focaccia.jpg"/> </main> function Pizza(props) { return ( <div className="pizza"> <img src={props.photoName} alt={props.name} /> <div className="pizzas"> <h3>{props.name}</h3> <p>{props.ingredients}</p> <span>{props.price}</span> </div> </div> ); }
三要素关系总结:
组件 是 UI 的基本单元,通过组合形成完整的应用。
状态 是组件内部的动态数据,控制着组件的行为和显示。
属性(props) 用于在组件间传递数据,通常是父组件传递给子组件的数据。
状态与道具有什么区别?
状态(state) :状态是组件内部管理的数据,数据归创建他的组件所有,它可以看作组件的存储,可以用来长期保存数据。状态可以在组件内部被修改(通过setState
或useState
),并会在变化时触发组件重新渲染,用来控制组件的行为、渲染和交互。
用于存储组件内部动态变化的数据 ,比如用户输入的表单值、加载数据的结果、组件的交互状态(如打开或关闭某个UI元素)。
当状态发生变化时,React会自动触发两个组件的重新渲染
道具(props) :道具是从父组件传递给子组件的数据,数据被父组件所有,可以把它想象函数参数。因为它是只读的,子组件无法直接修改它 。当子组件收到更新的props时,也会重新渲染组件
道具主要用来让组件间进行静态数据传 递,通常是父组件将数据通过道具传递给子组件,子组件根据道具的值渲染。
当道具的值在父组件中发生变化时,子组件会重新渲染。
怎么渲染列表(rendering a list) 概念:可以理解为创建一个数组,并为数组里的每个元素创建组件
通常我们会使用数组的 map()
方法来生成列表项。每个列表项需要一个唯一的 key
属性,以帮助 React 识别和优化列表中的元素
示例:
function Menu ( ) { return ( <main className ="menu" > <h2 > our pizzas</h2 > <div > {pizzaData.map((pizzas) => ( <Pizza pizzaObj ={pizzas} key ={pizzas.name} /> ))} {/*这一段代码是 React 中通过数组的 map() 方法渲染列表的常用方式。它的作用是遍历 pizzaData 数组,为数组中的每个对象生成一个对应的 Pizza 组件*/} </div > </main > ); }function Pizza (props ) { return ( <div className ="pizza" > <img src ={props.pizzaObj.photoName} alt ={props.pizzaObj.name} /> <div className ="pizzas" > <h3 > {props.pizzaObj.name}</h3 > <p > {props.pizzaObj.ingredients}</p > <span > {props.pizzaObj.price}</span > </div > </div > ); }
条件渲染 方法一:使用 && 运算符的短路逻辑 ,在特定条件下选择内容
示例:
function Footer ( ) { const data = new Date ().getHours (); console .log (data); const open = 20 ; const close = 22 ; const isOpen = data >= open && data < close; return ( <footer className ="footer" > {isOpen && <p > Open</p > } </footer > ); }
方法2:使用三元运算符
示例:
function Footer ( ) { const data = new Date ().getHours (); console .log (data); const open = 20 ; const close = 22 ; const isOpen = data >= open && data < close; return ( <footer className ="footer" > {isOpen = true ?(<p > Open</p > ): null} </footer > ); }
方法三:多重返回
示例:
function Footer ( ) { const data = new Date ().getHours (); console .log (data); const open = 20 ; const close = 22 ; const isOpen = data >= open && data < close; if (!isOpen) { return (<p > Close</p > ); } return ( <footer className ="footer" > {/* {isOpen && */} <div className ="order" > <p > We're open for orders from {open} to {close}. Call us at 123-456-7890.</p > <button className ="btn" style ={{color: 'yellow '}} > Order</button > </div > </footer > ); }
React Fragment(react 片段) 概念:React.Fragment
是 React 中用于包裹多个子元素 而不额外生成 HTML 元素的组件。
通常在 JSX 中,如果你返回多个元素,它们需要被一个父级元素<div></div>
包裹,而 React.Fragment
可以在不生成额外 DOM 节点的情况下包裹这些元素。
示例:
function App ( ) { return ( <react.fragment > <Header /> <Menu /> <Footer /> </react.fragment > ); }function App ( ) { return ( <> <Header /> <Menu /> <Footer /> </> ); }
如何在React中使用表单? 从代码理解
function Form (){ const [description, setDescription] = useState ('' ); function handleSubmit (e ){ e.preventDefault (); } return ( <form className ="add-form" onSubmit ={handleSubmit} > <h3 > What do you need for your trip</h3 > <select > {Array.from({length: 20}, (_, i) => i+1).map ((num) => ( <option value ={num} key ={num} > {num} </option > ))} </select > <input type ="text" placeholder ="Item..." value ={description} onChange ={(e) => setDescription(e.target.value)}/> <button > Add</button > </form > ); }
{Array.from({length: 20}, (_, i) => i+1).map ((num) => ( <option value={num} key={num}> {num} </option>))}
:
利用Array.from()
生成一个数组,并通过map()
来遍历数组,动态生成一组<option>
标签
onChange
:当用户在输入框中输入内容时,onChange
事件会触发,更新React状态,从而动态更新表单值
如何将表单中的数据导入事件?
常见的React事件类型:
**onClick
**:点击事件
**onChange
**:表单元素(如输入框、选择框)的值改变事件
**onSubmit
**:表单提交事件
**onKeyDown
、 onKeyUp
**:键盘按下、松开事件
**onMouseEnter
、 onMouseLeave
**:鼠标进入、离开事件
受控元素 在React中,使用受控组件可以将HTML表单中的数据与组件的状态(state
)直接绑定,从而避免直接操作DOM。这样做的好处是表单数据的更新和管理完全交由React来处理,无需手动获取DOM元素的值
三个步骤:
设置状态 const [description, setDescription] = useState('');
目的 :创建一个变量来存储用户输入的值,并在用户与表单交互时,React能够追踪和管理这个值。
绑定变量 通过value
属性,将表单元素(例如<input>
或<textarea>
)的值与刚刚创建的状态变量绑定。这样,表单的值由状态控制,React状态和UI之间建立了双向绑定关系。
操作 :在表单元素上使用value={description}
,使输入框的值与description
状态保持同步
更新状态 onChange={(e) => setDescription(e.target.value)}
,当用户在表单元素中输入内容时,onChange
事件会触发。此时,你可以使用setDescription
函数更新状态,确保状态随用户输入的变化而改变。事件处理函数将接收事件对象,通过e.target.value
获取表单元素的新值。
操作 :在onChange
事件处理函数中调用setDescription(e.target.value)
,将表单的新值更新到状态中
完整代码:
function Form (){ const [description, setDescription] = useState ('' ); const [quantity, setQuantity] = useState (1 ); function handleSubmit (e ){ e.preventDefault (); } return ( <form className ="add-form" onSubmit ={handleSubmit} > <h3 > What do you need for your trip</h3 > <select value ={quantity} onChange ={(e) => setQuantity(Number(e.target.value)} > {Array.from({length: 20}, (_, i) => i+1).map ((num) => ( <option value ={num} key ={num} > {num} </option > ))} </select > <input type ="text" placeholder ="Item..." value ={description} onChange ={(e) => setDescription(e.target.value)}/> <button > Add</button > </form > ); }
什么时候选择使用状态? 什么时候创建状态?
需要存储数据?
数据会发生变化吗
是否可以从现有的道具/状态中计算?
更新状态是否需要重新渲染组件?
不会 => 使用Ref (像普通状态一样持久的保持数据,但无需重新渲染组件)
使用useState创建一个状态,并放置在组件中
在哪里使用状态?
当前组件 、通过道具传递给子组件 、将状态传递给同级组件的公共父组件 中去(状态上移)、所有组件使用(全局状态 )
什么是派生状态? 派生状态就是简单地从一个现有状态或者道具中计算出来的状态
const [total,setTotal] = useState (0 );const tip = total /2 ;
子代道具 在 React 中,子代道具(Children Props) 是指通过 props.children
传递的内容,它允许父组件将嵌套在其内部的 JSX 代码或组件传递给子组件。它提供了一种灵活的方式来构建可复用的组件,使得父组件可以决定子组件的内部内容,而不需要在子组件中明确指定。
示例:
function Wrapper (props ) { return <div className ="wrapper" > {props.children}</div > ; }function App ( ) { return ( <Wrapper > <h1 > Hello, World!</h1 > <p > This is a paragraph inside the Wrapper component.</p > </Wrapper > ); }