React 是一個(gè)用于構(gòu)建用戶界面的 JavaScript 庫
import {createRoot} from 'react-dom/client'
import App from './App'
const elm = document.getElementById('app')
const root = createRoot(elm);
root.render(<App />);
npx create-react-app my-app
import React, {Component} from 'react'
import ReactDOM from 'react-dom'
export class Hello extends Component {
...
}
export default function World() {
/* ... */
}
使用 export 導(dǎo)出 Hello,export default 導(dǎo)出 World 組件
import World, { Hello } from './hello.js';
使用 import 導(dǎo)入 Hello 組件,在示例中使用。
import React from "react";
import "./Student.css";
export const Student = (
<div className="Student"></div>
);
注意:類屬性 className
const divStyle = {
backgroundImage: 'url(' + imgUrl + ')',
};
export const Student = (
<div style={divStyle}></div>
);
<Student name="Julie" age={23}
pro={true} />
函數(shù)組件 Student 中訪問屬性
function Student(props) {
return <h1>Hello, {props.name}</h1>;
}
Class 組件 Student 中訪問屬性
class Student extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
class 組件使用 this.props 訪問傳遞給組件的屬性。
function Example() {
return (
<AlertBox>
<h1>您有待處理的通知</h1>
</AlertBox>
)
}
函數(shù) AlertBox 組件
function AlertBox(props) {
return (
<div className="alert-box">
{props.children}
</div>
);
}
{props.children}
Class AlertBox 組件,與函數(shù)組件 AlertBox 組件相同
class AlertBox extends React.Component {
render () {
return (
<div className="alert-box">
{this.props.children}
</div>
);
}
}
{this.props.children}
children 作為子組件的的屬性傳遞。
函數(shù)中的 State,Hook 是 React 16.8 的新增特性
import { useState } from 'react';
function Student() {
const [count, setCount] = useState(0);
const click = () => setCount(count + 1);
return (
<div>
<p>您點(diǎn)擊了 {count} 次</p>
<button onClick={click}>
點(diǎn)擊我
</button>
</div>
);
}
使用 setState 更新狀態(tài),下面是函數(shù)組件讀取狀態(tài)
<p>您點(diǎn)擊了 {count} 次</p>
import React from 'react';
class Student extends React.Component {
constructor(props) {
super(props);
this.state = {count: 1};
// 確保函數(shù)可以訪問組件屬性(ES2015)
this.click = this.click.bind(this);
}
click() {
const count = this.state.count;
this.setState({ count: count + 1})
}
render() {
return (
<div>
<button onClick={this.click}>
點(diǎn)擊我
</button>
<p>您點(diǎn)擊了{this.state.count}次</p>
</div>
);
}
}
使用 setState 更新狀態(tài),class 組件中不能使用 hooksclass 組件讀取狀態(tài)
<p>您點(diǎn)擊了{this.state.count}次</p>
const elm = ['one', 'two', 'three'];
function Student() {
return (
<ul>
{elm.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
);
}
key 值在兄弟節(jié)點(diǎn)之間必須唯一
export default function Hello() {
function handleClick(event) {
event.preventDefault();
alert("Hello World");
}
return (
<a href="/" onClick={handleClick}>
Say Hi
</a>
);
}
function addNumbers(x1, x2) {
return x1 + x2;
}
const element = (
<div>
{addNumbers(2, 5)}
</div>
);
import { useState } from 'react'
import Avatar from './Avatar';
import Profile from './Profile';
function Student() {
const [count, setCount] = useState(0);
return (
<div>
<Avatar src={count} />
<Profile username={count} />
</div>
);
}
React 并_沒有_創(chuàng)建一個(gè)新的 div。它只是把子元素渲染到 domNode 中。domNode 是一個(gè)可以在任何位置的有效 DOM 節(jié)點(diǎn)。
render() {
return ReactDOM.createPortal(
this.props.children,
domNode
);
}
提供了一種將子節(jié)點(diǎn)渲染到存在于父組件以外的 DOM 節(jié)點(diǎn)的優(yōu)秀的方案
import { Fragment } from 'react'
import Avatar from './Avatar';
import Profile from './Profile';
const Student = () => (
<Fragment>
<Avatar src="./demo.jpg" />
<Profile username="name" />
</Fragment>
);
從 v16.2.0 開始 Fragment 可用于返回多個(gè)子節(jié)點(diǎn),而無需向 DOM 添加額外的包裝節(jié)點(diǎn)?;蛘呤褂?<></> 效果是一樣的。
const Student = () => (
<>
<Avatar src="./demo.jpg" />
<Profile username="name" />
</>
);
render() {
return 'Look ma, no spans!';
}
您可以只返回一個(gè)字符串。查看: Fragments & strings
const Student = () => [
<li key="A">First item</li>,
<li key="B">Second item</li>
];
不要忘記 key!查看: Fragments & strings
const FancyButton = React.forwardRef(
(props, ref) => (
<button ref={ref} className="btn">
{props.children}
</button>
)
);
// 你可以直接獲取 DOM button 的 ref:
const ref = React.createRef();
<FancyButton ref={ref}>
點(diǎn)擊我
</FancyButton>;
import {Component,createRef} from 'react'
class MyComponent extends Component {
constructor(props) {
super(props);
this.myRef = createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
提示:Refs 適用于類組件,但不適用于函數(shù)組件(除非您使用 useRef hook,請參閱hooks)
function CustomTextInput(props) {
// 這里必須聲明 $input,這樣 ref 才可以引用它
const $input = useRef(null);
function handleClick() {
$input.current.focus();
}
return (
<div>
<input type="text" ref={$input} />
<input
type="button" value="聚焦文本輸入"
onClick={handleClick}
/>
</div>
);
}
<div>
<Header />
<React.StrictMode>
<div>
<ComponentOne />
<ComponentTwo />
</div>
</React.StrictMode>
<Footer />
</div>
突出顯示應(yīng)用程序中潛在問題的工具。請參閱:嚴(yán)格模式
測量一個(gè) React 應(yīng)用多久渲染一次以及渲染一次的 代價(jià)
<Profiler id="Navigation" onRender={callback}>
<Navigation {...props} />
</Profiler>
為了分析 Navigation 組件和它的子代。應(yīng)該在需要時(shí)才去使用它。
| :- | :- |
|---|---|
id(string) | 發(fā)生提交的 Profiler 樹的 id |
onRender(function) | 組件樹任何組件 “提交” 一個(gè)更新的時(shí)候調(diào)用這個(gè)函數(shù) |
| :- | :- |
|---|---|
phase: "mount" | "update" | 判斷是由 props/state/hooks 改變 或 “第一次裝載” 引起的重渲染 |
actualDuration: number | 本次更新在渲染 Profiler 和它的子代上花費(fèi)的時(shí)間 |
baseDuration: number | 在 Profiler 樹中最近一次每一個(gè)組件 render 的持續(xù)時(shí)間 |
startTime: number | 本次更新中 React 開始渲染的時(shí)間戳 |
commitTime: number | 本次更新中 React commit 階段結(jié)束的時(shí)間戳 |
interactions: Set | 當(dāng)更新被制定時(shí),“interactions” 的集合會被追蹤 |
class CustomButton extends React.Component {
// ...
}
CustomButton.defaultProps = {
color: 'blue'
};
<CustomButton /> ;
不傳值 props.color 將自動設(shè)置為 blue
class Hello extends Component {
constructor (props) {
super(props)
this.state = { visible: true }
}
}
在構(gòu)造 constructor()中設(shè)置默認(rèn)狀態(tài)。
class Hello extends Component {
state = { visible: true }
}
function CustomButton(props) {
const { color = 'blue' } = props;
return <div>{color}</div>
}
function CustomButton() {
const [color, setColor]=useState('blue')
return <div>{color}</div>
}
JSX 僅僅只是 React.createElement(component, props, ...children) 函數(shù)的語法糖
<MyButton color="blue" shadowSize={2}>
點(diǎn)擊我
</MyButton>
會編譯為
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'點(diǎn)擊我'
);
沒有子節(jié)點(diǎn)
<div className="sidebar" />
會編譯為
React.createElement(
'div',
{className: 'sidebar'}
)
const Menu = ({ children }) => (
<div className="menu">{children}<div>
);
Menu.Item = ({ children }) => (
<div>{children}<div>
);
<Menu>
<Menu.Item>菜單一</Menu.Item>
<Menu.Item>菜單二</Menu.Item>
<Menu>
let element = <h1>Hello, world!</h1>;
let emptyHeading = <h1 />;
const root = ReactDOM.createRoot(
document.getElementById('root')
);
const element = <h1>Hello, world</h1>;
root.render(element);
參考:渲染元素
const avatarUrl = "img/picture.jpg"
const element = <img src={avatarUrl} />;
const element = (
<button className="btn">
點(diǎn)擊我
</button>
);
注意:類屬性 className
let name = '張三';
let element = <h1>Hello, {name}</h1>;
function fullName(firstName, lastName) {
return firstName + ' ' + lastName;
}
let element = (
<h1>
Hello, {fullName('三', '張')}
</h1>
);
const divStyle = {
color: 'blue',
backgroundImage: 'url(' + imgUrl + ')',
};
function MyComponent() {
return <div style={divStyle}>組件</div>;
}
const markup = {__html: '我 · 你' };
const MyComponent = () => (
<div dangerouslySetInnerHTML={markup} />
);
dangerouslySetInnerHTML 是 React 為瀏覽器 DOM 提供 innerHTML 的替換方案。
const MyComponent = () => (
<div>
<input type="radio" id="ab" name="v">
<label for="ab">HTML</label>
</div>
);
for 在 JS 中是保留字,JSX 元素使用了 htmlFor 代替
非受控組件的屬性,設(shè)置組件第一次掛載時(shí)的 value
<textarea defaultValue="Hello" />
<input>、<select> 和 <textarea> 支持 value 屬性
非受控組件的屬性,設(shè)置組件是否被選中
<input type="radio" defaultChecked />
類型為 checkbox 或 radio 時(shí),組件支持 checked 屬性
import React from "react";
function formatName(user) {
return user.firstName
+ ' '
+ user.lastName;
}
export function Greeting(user) {
if (user) {
return (
<h1>你好, {formatName(user)}!</h1>
);
}
return (
<h1>你好, 先生。</h1>
);
}
注意:組件必須總是返回一些東西。
<Greeting firstName="三" lastName="張" />
export default function Weather(props) {
const isLoggedIn = props.isLoggedIn;
return (
<div>
<b>{isLoggedIn ? '已' : '未'}</b>登錄。
</div>
);
}
{isShow && <div>內(nèi)容</div>}
<Dropdown>
下拉列表
<Menu>
<Menu.Item>菜單一</Menu.Item>
<Menu.Item>菜單二</Menu.Item>
<Menu.Item>菜單三</Menu.Item>
</Menu>
</Dropdown>
組件名稱以大駝峰式命名。
function Greeting(props) {
let button;
if (props.isLoggedIn) {
button = <UserGreeting />;
} else {
button = <GuestGreeting />;
}
return <div>{button}</div>;
}
function Student() {
const [count, setCount] = useState(0);
return (
<Fragment>
{/* 這里寫注釋 */}
</Fragment>
);
}
import React from 'react';
const UserName = () => <h1>Kenny</h1>;
export default function UserProfile() {
return (
<div className="UserProfile">
<div>Hello</div>
<UserName />
</div>
);
}
注意:每個(gè)組件都需要一個(gè)根元素,更多說明。
class Welcome extends React.Component {
render() {
return <h1>{this.props.name}</h1>;
}
}
| :- | - |
|---|---|
this.forceUpdate() | 強(qiáng)制重新渲染 |
this.setState({ ... }) | 更新狀態(tài) |
this.setState(state =>{ ... }) | 更新狀態(tài) |
| :- | - |
|---|---|
defaultProps | 默認(rèn) props |
displayName | 顯示組件名稱(用于調(diào)試) |
| :- | - |
|---|---|
this.props | 組件接受參數(shù) |
this.state | 組件內(nèi)狀態(tài) |
import React, {PureComponent} from 'react'
class MessageBox extends PureComponent {
···
}
import React, { Component } from 'react';
// 高階組件 with
const with = data => WrappedComponent => {
return class extends Component {
constructor(props) {
super(props);
}
render() {
return (
<WrappedComponent data={data} />
)
}
}
}
使用高階組件
const LowComponent = (props) => (
<div>{props.data}</div>
);
const MyComp = with('Hello')(LowComponent)
function FancyBorder(props) {
return (
<div className={'Fancy'+props.color}>
{props.children}
</div>
);
}
組件可以通過 JSX 嵌套
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="title">歡迎</h1>
<p className="message">
感謝您訪問我們的宇宙飛船
</p>
</FancyBorder>
);
}
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="left">
{props.left}
</div>
<div className="right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={<Contacts />}
right={<Chat />}
/>
);
}
給組件 SplitPane 傳遞 left 和 right 兩個(gè)組件參數(shù)
import React from 'react';
import UserAvatar from "./UserAvatar";
export default function UserProfile() {
return (
<div className="UserProfile">
<UserAvatar />
<UserAvatar />
</div>
);
}
注意:假設(shè) UserAvatar 在 UserAvatar.js 中聲明
const Menu = ({ children }) => (
<div className="menu">{children}<div>
);
Menu.Item = ({ children }) => (
<div>{children}<div>
);
<Menu>
<Menu.Item>菜單一</Menu.Item>
<Menu.Item>菜單二</Menu.Item>
<Menu>
| 方法 | 描述 |
|---|---|
useState | 返回一個(gè) state,更新 state 的函數(shù) # |
useEffect | 可能有副作用代碼的函數(shù) # |
useContext | 接收并返回該 context 的當(dāng)前值 # |
| 方法 | 描述 |
|---|---|
useReducer | useState 的替代方案 # |
useCallback | 返回一個(gè)回調(diào)函數(shù) # |
useMemo | 返回一個(gè) memoized 值# |
useRef | 返回一個(gè)可變的 ref 對象 # |
useImperativeHandle | 暴露給父組件的實(shí)例值 # |
useLayoutEffect | DOM 變更后同步調(diào)用函數(shù) # |
useDebugValue | 開發(fā)者工具中顯示標(biāo)簽 # |
useDeferredValue | 接受并返回該值的新副本 # |
useTransition | 過渡任務(wù)的等待狀態(tài) # |
useId | 用于生成唯一 ID # |
| 方法 | 描述 |
|---|---|
useSyncExternalStore | 讀取和訂閱外部數(shù)據(jù)源 # |
useInsertionEffect | DOM 突變之前 同步觸發(fā) # |
function Counter({ initialCount }) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count} <button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}
function TextInputWithFocusButton() {
const $input = useRef(null);
const onButtonClick = () => {
$input.current.focus();
};
return (
<>
<input ref={$input} type="text" />
<button onClick={onButtonClick}>
聚焦輸入
</button>
</>
);
}
current 指向已掛載到 DOM 上的文本輸入元素
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} />;
}
FancyInput = forwardRef(FancyInput);
父組件使用
<FancyInput ref={inputRef} />
inputRef.current.focus()
useEffect(() => {
const subs = props.source.subscribe();
return () => {
subs.unsubscribe();
};
}, [props.source]);
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
const memoizedValue = useMemo(
() => {
return computeExpensiveValue(a, b)
},
[a, b]
);
function Checkbox() {
const id = useId();
return (
<>
<label htmlFor={id}>
你喜歡React嗎?
</label>
<input id={id} type="checkbox" />
</>
);
};
用于生成跨服務(wù)端和客戶端穩(wěn)定的唯一 ID 的同時(shí)避免 hydration 不匹配
function useFriendStatus(friendID) {
const [
isOnline, setIsOnline
] = useState(null);
// ...
// 在開發(fā)者工具中的這個(gè) Hook 旁邊顯示標(biāo)簽
// e.g. "FriendStatus: Online"
useDebugValue(
isOnline ? 'Online' : 'Offline'
);
return isOnline;
}
不推薦你向每個(gè)自定義 Hook 添加 debug 值
useEffect(
() => {
// componentDidMount
// 組件掛載時(shí),可以在這里完成你的任務(wù)
return () => {
// componentWillUnmount
// 卸載時(shí)執(zhí)行,清除 effect
};
},
[ ]
);
這是一個(gè)類似 class 組件中 componentDidMount & componentWillUnmount 兩個(gè)生命周期函數(shù)的寫法。
| 方法 | 描述 |
|---|---|
constructor (props) | 渲染前 # |
static getDerivedStateFromProps() | 調(diào)用 render 方法之前調(diào)用 # |
render() | class 組件中唯一必須實(shí)現(xiàn)的方法 # |
componentDidMount() | 在組件掛載后(插入 DOM 樹中)立即調(diào)用 # |
UNSAFE_componentWillMount() | 在掛載之前被調(diào)用,建議使用 constructor() # |
在 constructor() 上設(shè)置初始狀態(tài)。在 componentDidMount() 上添加 DOM 事件處理程序、計(jì)時(shí)器(等),然后在 componentWillUnmount() 上刪除它們。
| 方法 | 描述 |
|---|---|
componentWillUnmount() | 在組件卸載及銷毀之前直接調(diào)用 # |
| 方法 | 描述 |
|---|---|
static getDerivedStateFromProps(props, state) | 調(diào)用 render 之前調(diào)用,在初始掛載及后續(xù)更新時(shí)都會被調(diào)用 # |
shouldComponentUpdate(nextProps, nextState) | 如果返回 false,則跳過 render() # |
render() | 在不修改組件 state 的情況下,每次調(diào)用時(shí)都返回相同的結(jié)果 # |
getSnapshotBeforeUpdate() | 在發(fā)生更改之前從 DOM 中捕獲一些信息(例如,滾動位置) # |
componentDidUpdate() | 這里使用 setState(),但記得比較 props。首次渲染不會執(zhí)行此方法 # |
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
constructor(props) {
super(props);
// 不要在這里調(diào)用 this.setState()
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以顯降級 UI
return { hasError: true };
}
render() {
if (this.state.hasError) {
// 你可以渲染任何自定義的降級 UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
componentDidUpdate(prevProps) {
// 典型用法(不要忘記比較 props):
if (this.props.uid !== prevProps.uid) {
this.fetchData(this.props.uid);
}
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 我們是否在 list 中添加新的 items ?
// 捕獲滾動??位置以便我們稍后調(diào)整滾動位置。
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
import PropTypes from 'prop-types'
| :- | - |
|---|---|
any | 任意類型 |
(props, propName, 組件名稱)=>{} | 自定義驗(yàn)證器 |
| :- | - |
|---|---|
string | 字符串 |
number | 數(shù)組 |
func | 函數(shù) |
bool | 布爾值 |
symbol | - |
| :- | - |
|---|---|
oneOf(any) | 枚舉類型 |
oneOfType([type]) | 幾種類型中的任意一個(gè)類型 |
| :- | - |
|---|---|
array | 數(shù)組 |
arrayOf | 數(shù)組由某一類型的元素組成 |
| :- | - |
|---|---|
object | 對象 |
objectOf | 對象由某一類型的值組成 |
instanceOf(...) | 類的實(shí)例 |
shape | 對象由特定的類型值組成 |
exact | 有額外屬性警告 |
| :- | - |
|---|---|
element | React 元素 |
elementType | React 元素類型(即 MyComponent) |
node | DOM 節(jié)點(diǎn) |
| :- | - |
|---|---|
(···).isRequired | 必需的 |
MyComponent.propTypes = {
email: PropTypes.string,
seats: PropTypes.number,
callback: PropTypes.func,
isClosed: PropTypes.bool,
any: PropTypes.any
symbol: PropTypes.symbol,
}
你可以將屬性聲明為 JS 原生類型,默認(rèn)都是可選的。
MyComponent.propTypes = {
// 確保這個(gè) prop 沒有被提供時(shí),會打印警告信息
requiredFunc: PropTypes.func.isRequired,
// 任意類型的必需數(shù)據(jù)
requiredAny: PropTypes.any.isRequired,
}
你可以在任何 PropTypes 屬性后面加上 isRequired。
MyComponent.propTypes = {
// 只能是特定的值,枚舉類型。
optionalEnum: PropTypes.oneOf([
'News', 'Photos'
]),
// 一個(gè)對象可以是幾種類型中的任意一個(gè)類型
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
}
MyComponent.propTypes = {
// 任何可被渲染的元素
// (包括數(shù)字、字符串、元素或數(shù)組)
// (或 Fragment) 也包含這些類型。
node: PropTypes.node,
// 一個(gè) React 元素。
element: PropTypes.element,
// 一個(gè) React 元素類型(即,MyComponent)
elementType: PropTypes.elementType,
}
MyComponent.propTypes = {
// 可以指定一個(gè)對象由某一類型的值組成
objectOf: PropTypes.objectOf(
PropTypes.number
),
// 可以指定一個(gè)對象由特定的類型值組成
objectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// 帶有額外屬性警告的對象
objectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
}
MyComponent.propTypes = {
custom: (props, propName, compName) => {
if (!/matchm/.test(props[propName])) {
// 它在驗(yàn)證失敗時(shí)應(yīng)返回一個(gè) Error 對象
return new Error(
'無效的prop `'
` \`${propName}\` 提供給` +
` \`${compName}\`。驗(yàn)證失敗。`
);
}
},
}
請不要使用 console.warn 或拋出異常,因?yàn)檫@在 oneOfType 中不會起作用。
arrayOf 或 objectOf 驗(yàn)證器MyComponent.propTypes = {
arrayProp: PropTypes.arrayOf((propValue, key, componentName, location, propFullName) => {
if (!/matchme/.test(propValue[key])) {
// 它應(yīng)該在驗(yàn)證失敗時(shí)返回一個(gè) Error 對象。
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
}
propValue 是數(shù)組或?qū)ο蟊旧恚?code>key 是他們當(dāng)前的鍵。
MyComponent.propTypes = {
arr: PropTypes.arrayOf(PropTypes.number),
};
可以指定一個(gè)數(shù)組由某一類型的元素組成
MyComponent.propTypes = {
message: PropTypes.instanceOf(Message),
};
聲明 message 為類的實(shí)例
感谢您访问我们的网站,您可能还对以下资源感兴趣:
国产成人精品999视频&日本一区二区亚洲人妻精品&久久久精品国产99久久精&99热这里只有成人精品国产&精品国产剧情av一区二区&成人亚洲精品久久久久app&国产精品美女高潮抽搐A片