react文档
编写函数式组件
- React组件的名称必须以大写字母开头
- return 关键字返回不在同一行,则必须把它包裹在一对括号中;如果一行可以省略()
- 在 JSX 中使用大括号编写 JavaScript:例如
{ person.name }早上好 - React 组件使用
props来进行组件之间的通讯:利用属性传递对象、数组、函数、甚至是 JSX,使用props对象接收参数,也可以采用解构的方式
// 子组件
export function Profile(props) {return (<div>{ props.name }早上好</div><img src="https://i.imgur.com/QIrZWGIs.jpg" alt="Alan" />);
}
// 父组件
import { Profile } from './Profile.js';export default function Gallery() {return (<section><Profile name = "ququ"/><Profile /> </section>);
}
条件渲染 && 、 ||、三元运算符、if
-
&& 是 JavaScript 中的逻辑与运算符。如果左侧操作数为真,则返回右侧操作数;否则,返回左侧操作数。
-
在 React 组件中,&& 通常用于条件渲染。当某个条件为真时,渲染出某些内容;条件为假时,不进行任何渲染
-
如果左侧是 0,整个表达式将变成左侧的值(0),React 此时则会渲染 0 而不是不进行渲染。
-
||是逻辑或运算符。它返回第一个真值表达式的值,如果都为假值,则返回最后一个表达式的值
-
使用三元运算符对条件进行判断。基本语法为: condition ? expressionIfTrue : expressionIfFalse
function MyComponent(props) {const {name} = props;return (<div>{name && <p>Hello, {name}!</p>} // 当name存在时,渲染P标签,否则不渲染</div><div>{props.message || '默认信息'} // 当message不存在时,渲染默认值</div><div>{isLoggedin ? <p>Welcome back!</p> : <p>Please log in.</p>}</div>)
}
- 通过条件语句(if、else if、else 或 switch)进行条件判断
function MyComponent(props) {const [isLoggedin, setIsLoggedIn] = useState(false);let message;if (isLoggedin) {message = <p>Welcome back!</p>;} else {message = <p>Please log in.</p>;}return (<div>{message}</div>);
}
- 返回null:不想有任何东西进行渲染,可以
return null;
渲染列表
- 使用 filter() 和 map() 来实现数组的过滤和转换,将数据数组转换为组件数组。
- 对于数组的每个元素项,你需要指定一个 key
export default function List(props) {const people= props.items.filter(item => item.name); const listItems = people.map(person =><li key={person.id}><imgsrc={getImageUrl(person)}alt={person.name}/></li>);return (<article><h1>Scientists</h1><ul>{listItems}</ul></article>);
}
组件的导入导出:默认导出 vs 具名导出

JSX 语法
- JSX and React 是相互独立的 东西。 JSX 是一种语法扩展,而 React 则是一个 JavaScript 的库。
- 只能返回一个根元素 :需要一个跟标签包裹,
可以用 <> 和 > 元素来代替 - 标签必须闭合
、
- oranges
- 使用驼峰式命名法给
大部分属性命名:变量名称不能包含 - 符号或者像 class 这样的保留字
//由于 class 是一个保留字,所以在 React 中需要用 className 来代替
<img src="https://i.imgur.com/yXOvdOSs.jpg" alt="Hedy Lamarr" className="photo"
/>
- 在 JSX 中通过大括号使用 JavaScript
const today = new Date();function formatDate(date) {return new Intl.DateTimeFormat('en-US',{ weekday: 'long' }).format(date);
}
const avatar = 'https://i.imgur.com/7vQD0fPs.jpg';
export default function TodoList() {return (<h1 style={{backgroundColor: 'black',color: 'pink'}}>To Do List for {formatDate(today)}</h1> //使用方法<imgclassName="avatar"src={avatar} // 变量不能加引号alt= "aaa"/>);
}
- 在 JSX 中,只能在以下两种场景中使用大括号:
- 用作 JSX 标签内的文本:
是有效的{name}'s To Do List
- 用作紧跟在 = 符号后的 属性:
src={avatar}会读取 avatar 变量,但是src="{avatar}" 只会传一个字符串 {avatar}。 - 内联样式需要传入一个对象,所以会出现{{}}
- 内联 style 属性 使用驼峰命名法编写
可以将多个表达式合并到一个对象中使用
const person = {name: 'Gregorio Y. Zara',theme: {backgroundColor: 'black',color: 'pink'}
};export default function TodoList() {return (<div style={person.theme}><h1>{person.name}'s Todos</h1><imgclassName="avatar"src="https://i.imgur.com/7vQD0fPs.jpg"alt="Gregorio Y. Zara" /></div>);
}
将 Props 传递给子组件
- 1、普通传参
- 在父组件中引入的子组件标签上定义任意属性并赋值(数值、对象、数组、函数)
- 在子组件的参数中接收props = {属性名:传递的值}。可直接解构
- 可以为参数设置默认值(不传的时候取默认值)
- 把 对象里的每个属性都作为 props 传给 子组件,可使用简写方式
,等价于
function Avatar({ person, size = 100 }) {// 在这里 person 和 size 是可访问的
}
export default function Profile() {return (<Avatarperson={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}/>);
}
- 2、传递任意 jsx
- 在父组件中引入的子组件标签中间 :插入任意jsx
- 在子组件的参数接收 props = {children :传递的jsx} ,类似vue中的slot
// card 公共组件,只有标题下面的地方内容不同,一个是图片,一个是文字,所以有父组件传入jsx
function Card({ children, title }) {return (<div className="card"><div className="card-content"><h1>{title}</h1>{children} //不同的地方</div></div>)
}export default function Profile() {return (<div><Card title="11111"><imgclassName="avatar"src="https://i.imgur.com/OKS67lhm.jpg"alt="Aklilu Lemma"width={70}height={70}/></Card><Card title="2222"><p>一段佳话</p></Card></div>);
}
- 3、传递函数
等内置组件只支持内置浏览器事件,如 onClick
export default function App() {return (<ToolbaronPlayMovie={() => alert('Playing!')}onUploadImage={() => alert('Uploading!')}/>);
}function Toolbar({ onPlayMovie, onUploadImage }) {return (<div><Button onClick={onPlayMovie}>Play Movie</Button><Button onClick={onUploadImage}>Upload Image</Button></div>);
}function Button({ onClick, children }) {return (<button onClick={onClick}>{children}</button>);
}
-
4、Props 随时间变化实时更新——Hook useState
- Hook 是能让你的组件使用 React 功能的特殊函数(状态是这些功能之一)
- useState Hook 让你声明一个状态变量。它接收初始状态并返回一对值:当前状态,以及更新状态的设置函数。
- 设置状态 并不改变你已有的状态变量,而是触发一次重新渲染
import { useState } from 'react';
import { sculptureList } from './data.js';export default function Gallery() {const [index, setIndex] = useState(0);const hasNext = index < sculptureList.length - 1;function handleNextClick() {if (hasNext) {setIndex(index + 1);} else {setIndex(0);}}return (<><button onClick={handleNextClick}>下一个</button><h3>({index + 1} of {sculptureList.length})</h3></>);
}
事件
- 通常在你的组件 内部 定义。名称以 handle 开头,后跟事件名称。
- 也可以在 JSX 中定义一个内联的事件处理函数
export default function Button() {function handleClick() {alert('你点击了我!');}return (<button onClick={handleClick}>点我</button>// 内联事件<button onClick={() => {alert('哈哈哈!');}}>哈哈哈</button>);
}
- bug:
与的区别- handleClick 函数作为 onClick 事件处理函数传递。这会让 React 记住它,并且只在用户点击按钮时调用你的函数。
- handleClick() 会在 渲染 过程中 立即 触发函数,即使没有任何点击。这是因为在 JSX { } 之间的 JavaScript 会立即执行
- 事件处理函数声明于组件内部,因此它们可以直接访问组件的 props
- 事件处理函数可以作为 props 传递 给子组件,事件处理函数 props 应该以 on 开头,后跟一个大写字母
- 阻止事件传播(事件冒泡):e.stopPropagation();
function Button({ onClick, children }) {return (<button onClick={e => {e.stopPropagation(); //子组件事件onClick();}}>{children}</button>);
}
- 阻止默认行为(
表单内部的按钮会触发表单提交事件):e.preventDefault();
export function Signup() {function handleClick(e) {e.preventDefault(); //阻止a标签跳转alert('你点击了链接');}return (<a href="#" onClick={handleClick}>点击这里</a>);
}
HOOK
- 在 React 中,useState 以及任何其他
以“use”开头的函数都被称为 Hook。 - Hook 是特殊的函数,只在 React 渲染时有效
- Hook 只能在组件函数的顶层调用,不能在代码逻辑里定义
State:组件的记忆
-
局部变量
- 局部变量无法在多次渲染中持久保存。 当 React 再次渲染这个组件时,它会从头开始渲染——不会考虑之前对局部变量的任何更改。
- 更改局部变量不会触发渲染。 React 没有意识到它需要使用新数据再次渲染组件。
-
useState Hook
-
state 变量 (index) 会保存上次渲染的值。
-
state setter 函数 (setIndex) 可以更新 state 变量并触发 React 重新渲染组件。
-
state 变量 (index) 的值在同一个事件处理函数是一样的:变量在set方法之前或之后都一样 因为React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新;这让你可以更新多个 state 变量——甚至来自多个组件的 state 变量——而不会触发太多的 重新渲染,这种特性也就是 批处理
-

把一系列 state 更新加入队列
- React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新。
import { useState } from 'react';export default function Counter() {const [number, setNumber] = useState(0);return (<><h1>{number}</h1> // 1<button onClick={() => {setNumber(number + 1); setNumber(number + 1);setNumber(number + 1);}}>+3</button></>)
}
- 点击一次按钮结果是1
| 更新队列 | n 返回值 |
|---|---|
| setNumber(number + 1) | 0 + 1=1 |
| setNumber(number + 1) | 0 + 1=1 |
| setNumber(number + 1) | 0 + 1=1 |
例2:更新函数
- n => n + 1 被称为更新函数:n是set之后的变量值 。当你将它传递给一个 state 设置函数时:
- React 会将此函数加入队列,以便在事件处理函数中的所有其他代码运行后进行处理。
- 在下一次渲染期间,React 会遍历队列并给你更新之后的最终 state。
import { useState } from 'react';export default function Counter() {const [number, setNumber] = useState(0);return (<><h1>{number}</h1> // 3<button onClick={() => {setNumber(n => n + 1);setNumber(n => n + 1);setNumber(n => n + 1);}}>+3</button></>)
}
- 点击一次按钮结果是3
| 更新队列 | n | 返回值 |
|---|---|---|
| setNumber(n => n + 1) | 0 | 0 + 1=1 |
| setNumber(n => n + 1) | 1 | 1 + 1=2 |
| setNumber(n => n + 1) | 2 | 2 + 1=3 |
例3
export default function Counter() {const [number, setNumber] = useState(0);return (<><h1>{number}</h1> // 42<button onClick={() => {setNumber(number + 5);setNumber(n => n + 1);setNumber(42);}}>增加数字</button></>)
}
- 点击一次按钮结果是42
| 更新队列 | n | 返回值 |
|---|---|---|
| setNumber(number + 5) | 0 | 0 + 5=5 |
| setNumber(n => n + 1) | 5 | 5 + 1=6 |
| setNumber(42) | 6 | 42 |
更新状态中的对象
- 状态可以持有任何类型的 JavaScript 值,包括对象,不应该直接改变你在 React 状态中持有的对象和数组。
- 当你想更新一个对象和数组时,你需要创建一个新的对象(或复制现有的对象),然后用这个副本来更新状态。
- 通常情况下, 使用 … 展开语法来复制你想改变的对象和数组
import { useState } from 'react';export default function Form() {const [person, setPerson] = useState({name: 'Niki de Saint Phalle',artwork: {title: 'Blue Nana',}});function handleNameChange(e) {setPerson({...person,name: e.target.value});}function handleTitleChange(e) {setPerson({...person,artwork: {...person.artwork,title: e.target.value}});}return (<><label>Name: <input value={person.name} onChange={handleNameChange} /></label><label>Title: <input value={person.artwork.title} onChange={handleTitleChange} /></label></>);
}
使用 Immer 之类的库更新state中的对象
import { useImmer } from 'use-immer';export default function Form() {const [person, updatePerson] = useImmer({name: 'Niki de Saint Phalle',artwork: {title: 'Blue Nana',}});function handleNameChange(e) {updatePerson(draft => {draft.name = e.target.value;});}function handleTitleChange(e) {updatePerson(draft => {draft.artwork.title = e.target.value;});}return (<><label>Name: <input value={person.name} onChange={handleNameChange} /></label><label>Title: <input value={person.artwork.title} onChange={handleTitleChange} /></label></>);
}
更新 state 中的数组

- 数组前后添加元素
setArtists( // 替换 state[ // 是通过传入一个新数组实现的{ id: nextId--, name: name } // 并在前边添加了一个新的元素...artists, // 新数组包含原数组的所有元素{ id: nextId++, name: name } // 并在末尾添加了一个新的元素]
);
- 数组中间插入元素 slice
function handleClick() { const nextArtists = [// 插入点之前的元素:...artists.slice(0, 3),// 新的元素:{ id: nextId++, name: name },// 插入点之后的元素:...artists.slice(3)];setArtists(nextArtists); }
- 删除元素 filter
setArtists(artists.filter(a => a.id !== artist.id)
);
- 修改元素 map
function handleIncrementClick(index) {const nextCounters = counters.map((c, i) => {if (i === index) {// 递增被点击的计数器数值return c + 1;} else {// 其余部分不发生变化return c;}});setCounters(nextCounters);}
- 其他改变数组的情况:你可以先拷贝这个数组,再改变这个拷贝后的值
function handleClick() {const nextList = [...list]; nextList.reverse();setList(nextList);
}
- 复制数组不能更新数组内部的对象 :nextList 属于浅拷贝,所以可以修改 nextList [0]的值,但是不能直接修改 nextList [0].属性,因为会改变 list[0].属性
- 更新数组内部的对象 map
import { useState } from 'react';const [myList, setMyList] = useState([{ id: 0, title: 'Big Bellies', seen: false },{ id: 1, title: 'Lunar Landscape', seen: false },{ id: 2, title: 'Terracotta Army', seen: true },];
);
setMyList(myList.map(item=> {if (item.id === artworkId) {// 创建包含变更的*新*对象return { ...item, seen: nextSeen }; //循环修改每一项的seen属性} else {// 没有变更return item;}
}));
使用 Immer 修改state中的数组
- Immer ,它让你可以继续使用方便的,但会直接修改原值的语法,并负责为你生成拷贝值。
import { useState } from 'react';
import { useImmer } from 'use-immer';
import AddTodo from './AddTodo.js';
import TaskList from './TaskList.js';let nextId = 3;
const initialTodos = [{ id: 0, title: 'Buy milk', done: true },{ id: 1, title: 'Eat tacos', done: false },{ id: 2, title: 'Brew tea', done: false },
];export default function TaskApp() {const [todos, updateTodos] = useImmer(initialTodos);function handleAddTodo(title) {updateTodos(draft => {draft.push({id: nextId++,title: title,done: false});});}function handleChangeTodo(nextTodo) {updateTodos(draft => {const todo = draft.find(t =>t.id === nextTodo.id);todo.title = nextTodo.title;todo.done = nextTodo.done;});}function handleDeleteTodo(todoId) {updateTodos(draft => {const index = draft.findIndex(t =>t.id === todoId);draft.splice(index, 1);});}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
