我不一定按照文档顺序记录
jsx语法系列
JSX 中通过大括号使用 JavaScript
可以在哪使用大括号 ?
- 用作 JSX 标签内的文本 :
<h1>{name}'s To Do List</h1>
是有效的,但是<{tag}>Gregorio Y. Zara's To Do List</{tag}>
无效。 - 用作紧跟在 = 符号后的属性:src={avatar} 会读取 avatar 变量,但是 src="{avatar}" 只会传一个字符串 {avatar}。
使用 "双大括号"
可以在 JSX 中传递对象。
对象也用大括号表示,为了能在 JSX 中传递,你必须用另一对额外的大括号包裹对象。
JSX 中看到 {{ 和 }}时,它只不过是包在大括号里的一个对象。
将 Props 传递给组件
1.props 传递给子组件
组件使用 props 来互相通信,直接在组件里写属性
例如
javascript
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
- 在子组件中读取 props
子组件的括号内直接列出他们( 不要忘记 ( 和 ) 之间的一对花括号 { 和 } )
javascript
function Avatar({ person, size }) {
// 在这里 person 和 size 是可访问的
}
或者通过整个 props 对象,将它解构。
javascript
function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}
-
给 prop 指定一个默认值
默认值仅在缺少 size prop 或 size={undefined } 时生效。 但是如果你传递了 size={null} 或 size={0} ,默认值将 不 被使用。
-
使用 JSX 展开语法传递 props
javascript
<Avatar {...props} />
不要尝试"更改 props"。当一个组件需要改变它的 props(例如,响应用户交互或新数据)时,它不得不"请求"它的父组件传递 不同的 props
你可以设置 state。
state
既然谈到props,接着看看state
组件需要"记住"某些东西,就需要用state
例如,下面这种不起作用,index的值不会改变
javascript
export default function Gallery() {
let index = 0;
function handleClick() {
index = index + 1;
}
return (
<>
<button onClick={handleClick}>
Next
</button>
<h3>
{index + 1}
</h3>
</>
)
存在两个原因使得变化不可见:
- 局部变量无法在多次渲染中持久保存。 当 React 再次渲染这个组件时,它会从头开始渲染------不会考虑之前对局部变量的任何更改。
- 更改局部变量不会触发渲染。 React 没有意识到它需要使用新数据再次渲染组件。
要使用新数据更新组件,需要做两件事:
- 保留 渲染之间的数据。
- 触发 React 使用新数据渲染组件(重新渲染)。
useState
在 React 中,useState 以及任何其他以"use"开头的函数都被称为 Hook 。
Hooks ------以 use 开头的函数------只能在组件或自定义 Hook 的最顶层调用 ,你不能在条件语句、循环语句或其他嵌套函数内调用 Hook(遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。------这样React 才知道返回的是哪个 state )。只在 React 渲染时有效
useState里发生了什么?
javascript
const [index, setIndex] = useState(0);
1.组件进行第一次渲染。 因为你将 0 作为 index 的初始值传递给 useState,它将返回 [0, setIndex]。 React 记住 0 是最新的 state 值。
2.你更新了 state。当用户点击按钮时,它会调用 setIndex(index + 1)。 index 是 0,所以它是 setIndex(1)。这告诉 React 现在记住 index 是 1 并触发下一次渲染。
3.组件进行第二次渲染 。React 仍然看到 useState(0),但是因为 React 记住 了你将 index 设置为了 1,它将返回 [1, setIndex]。
4.以此类推!
React 如何知道返回哪个 state ?
原因:在同一组件的每次渲染中,Hooks 都依托于一个稳定的调用顺序。只要 Hook 的调用顺序在多次渲染之间保持一致,React 就能正确地将内部 state 和对应的 Hook 进行关联。
这就是为什么 Hook 需要在我们组件的最顶层调用
state特性
**State 是隔离且私有的:**如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!改变其中一个不会影响另一个。
渲染和提交
在一个 React 应用中一次屏幕更新都会发生以下三个步骤:
- 触发
- 渲染
- 提交
1. 触发一次渲染
有两种原因会导致组件的渲染:
- 组件的初次渲染。
- 组件(或者其祖先之一)的 状态发生了改变。
2. React 渲染你的组件
- 在进行初次渲染时, React 会调用根组件,创建DOM节点。
- 对于后续的渲染, React 会调用内部状态,更新触发了渲染的函数组件。(递归地更新这些触发了渲染的组件)
渲染必须是纯函数。
纯函数:输入如果相同,那么输出也相同;只做它自己的事情,不会更改在该函数调用前就已存在的对象或变量。
可以使用严格模式去找到组件中的错误:"严格模式" 下开发时,React 会调用每个组件的函数两次,这可以帮助发现由不纯函数引起的错误。
3. React 把更改提交到 DOM 上
在渲染(调用)你的组件之后,React 将会修改 DOM。
- 对于初次渲染, React 会使用 appendChild() DOM API 将其创建的所有 DOM 节点放在屏幕上。
- 对于重渲染 , React 将应用最少的必要操作(在渲染时计算!),以使得 DOM 与最新的渲染输出相互匹配。
React 仅在渲染之间存在差异时才会更改 DOM 节点。
4. 浏览器绘制
在渲染完成并且 React 更新 DOM 之后,浏览器就会重新绘制屏幕。
纯函数
例子
javascript
let guest = 0;
function Cup() {
// Bad:正在更改预先存在的变量!
guest = guest + 1;
return <h2>Tea cup for guest #{guest}</h2>;
}
export default function TeaSet() {
return (
<>
<Cup />
<Cup />
<Cup />
</>
);
}
这里输出是2,4,6而不是1,2,3 的原因是开启了严格模式,所以执行了两次加一操作;
并且react在提交阶段更新DOM,而不是渲染阶段,因此,不会输出第一次执行的结果。
其次,在每个cup中间输出guest的值,发现都是0,这是因为渲染顺序是父到子,所以teaset会先渲染,还没执行子。
条件渲染
切勿将数字放在 && 左侧
如果左侧是 0,整个表达式将变成左侧的值(0),React 此时则会渲染 0 而不是不进行渲染。
可以将左侧的值改成布尔类型:messageCount > 0