https://react.dev/learn/installation
官网
https://react.dev/learn/react-developer-tools
React Developer Tools
原生React样例:demo.html
Document
是一种表达式,也是React的一种标准书写方式,使用html的方式去写React元素
Document
引入babel.js
浏览器本身不解析
babel会监听全局的document.onContentLoad
babel获取到所有的script标签:document.getElementByTagName
读取script的属性getAttributes("type")
如果有type="text/babel"
,则读取里面的内容,调用transform方法将其转换成js代码,新建一个script标签插入到head
标签中
#create-react-app官方脚手架
npx create-react-app react-first
#运行
npm run start
reportWebVitals.js 做性能指标的
删除reportWebVitals.js,在index.js中,删除相关引用
删除logo.svg,在App.js中,删除相关引用
删除App.css、index.css、App.test.js、setupTests.js
index.js中,删除严格模式
组件允许我们将UI
划分为独立的、可重用的部分来思考
React中组件大多数为一个函数
,都是在直接调用对应的组件函数App.js
function App() {
return (
hello world
);
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
);
创建组件
components/ReportButton/index.jsx
export default function ReportButton() {
const handleClick = () => {
console.log('click button')
}
return (
)
}
在App.js
中使用:
import ReportButton from "./components/ReportButton";
function App() {
return (
)
}
export default App;
React组件本质上就是函数
state
:组件内部的数据
渲染 === 函数组件的执行 / 重新渲染 === 函数组件的重新执行
如果想让函数组件重新渲染,有2条途径
如果想让页面跟随数据的变化而变化,必须使用useState
构建状态
const [count, setCount] = useState(0)
setCount(prev => prev + 1)
useState
返回的结果里的修改数据函数,在被调用时会重新渲染该组件
组件状态的更新是异步的,当更改状态的函数执行以后,是没有办法同步的获取到最新的值
延迟批量一起处理,减少渲染次数
import { useState } from "react"
export default function Counter() {
const [count, setCount] = useState(0)
const increase = () => {
// 传入函数,参数为上一次的值
setCount(prev => prev + 1)
// setCount(count + 1) 如果直接指定值,会在延迟批量处理时,count取值出现问题
}
const decrease = () => {
setCount(prev => prev - 1)
}
return (
{count}
)
}
标签元素:在html中有明确的对标元素就叫标签元素;会被React自行处理到对应底层的事件或者属性
传递给自定义组件的是组件属性
import { useState } from "react"
export default function Counter(props) {
// undefinde、null、false是不会在页面上渲染任何东西的
const [count, setCount] = useState(props.defaultValue || 0)
const increase = () => {
setCount(prev => prev + 1)
}
const decrease = () => {
setCount(prev => prev - 1)
}
return (
{count}
)
}
和原生的事件行为差不多
App.js
import Counter from "./components/Counter";
function App() {
let defaultValue = 10
const handleClick = () => {
console.log('React hello')
}
return (
)
}
export default App;
Counter.js
import { useState } from "react"
export default function Counter(props) {
console.log('Counter props', props)
// undefinde、null、false是不会在页面上渲染任何东西的
const [count, setCount] = useState(props.defaultValue || 0)
const increase = () => {
setCount(prev => prev + 1)
}
const decrease = () => {
setCount(prev => prev - 1)
}
return (
click div
{count}
)
}
React为了节约性能以及实现动态监听,React使用事件委托的机制
React事件委托是一种优化事件处理的技术,它通过将事件监听器添加到父级元素(而不是子元素)来实现。
当事件触发时,事件会向上冒泡到父元素,然后在父元素上调用事件处理函数。
通过事件委托,可以减少添加到DOM元素的事件监听器数量,从而提高性能。
React事件委托,使得在动态创建和销毁元素时,事件处理效率更高。
如果没有事件委托,每次创建一个新元素时,都需要为它添加一个新的事件监听器。同样在销毁元素时,需要手动移除事件监听器,以避免内存泄漏。
而使用事件委托,React可以处理所有这些问题,同时提高应用程序的性能。
React18中的事件委托是通过事件冒泡机制实现的。
当一个子元素上触发事件时,该事件会向上冒泡至其祖先节点,直到到达顶层的父元素。在这个冒泡过程中,如果某个祖先元素上注册了相应的事件处理程序,则该处理程序就会被调用。
受控组件是由React控制的组件,其表单数据被React以state
的形式保存并更新。
用户每次操作表单元素时,React都会处理相应的事件,并将表单数据保存到state
中或者触发其他逻辑处理。当用户提交表单时,React可以从state
中获取最终的表单数据。
相反,非受控组件的表单数据被DOM处理,而不是由React控制。通常,我们使用非受控组件来处理不需要实时处理的表单数据。例如,可以通过直接访问表单DOM元素来收集表单数据。
虽然在某些情况下开发者倾向于使用非受控组件以获得更高的灵活性和性能,但是在大多数情况下建议选择受控组件进行开发,因为受控组件可以提供更好的代码封装性、可读性和可维护性。
非受控组件只能通过defaultValue
去设置初始值,然后通过绑定对应的事件去监听值
在表单组件中,受控和非受控的区分是:受控标签属性的植入
value
checked
import { useState } from "react"
function App() {
const [inputVal, setInputVal] = useState("")
const [checked, setChecked] = useState(false)
const handleInput = (event) => {
console.log('event.value', event.target.value)
}
const handleControllerInput = (event) => {
setInputVal(event.target.value)
console.log('event.value', event.target.value)
}
return (
非受控
受控
受控 { setChecked(event.target.checked)}}>
)
}
export default App;