创建组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/babel.min.js"></script>
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/babel">
// 知识点
// 什么是组件
// 组件具备以下特点
// 1. 独立显示的页面内容
// 2. 独立维护的组件状态
// 3. 组件被当作标签使用
// 所以,组件是一个具备独立显示内容,独立维护状态,被当作标签使用的可复用模组
// 应用场景
// 可复用的页面内容,就可以考虑封装成组件
// 声明组件
// 类组件
// render函数
// 构造函数和props
// props.children
// 函数组件
// 参数props
// 函数组件没有this
// react 中声明组件有两种方法
// 一种叫 类组件 另一种叫 函数组件
// 两种组件对于 react 来说是等价的
// 声明类组件
// 需要继承 React.Component
class AComponent extends React.Component {
// 可以有组件的属性
label = 'h'
// 构造函数中包含props参数
// props 代表组件的 html 属性
// props 是只读属性
constructor(props) {
// 由于存在父类 React.Component
// 所以构造函数中应先调用super
super(props)
// render 函数中可以使用 this.props 访问此处的 props
console.log(props)
// 可以使用 props.children 代表组件标签体里的内容
console.log(props.children)
}
// 可以有组件方法
getTime() {
return new Date()
}
// 类组件中必须包含 render 方法
render() {
// render 方法必须返回一个 react-dom 对象
// 返回的 react-dom 对象用于描述组件长什么样子的
return (
<div>
{/* 组件中可以调用自己的属性和方法 */}
{this.label}: {this.getTime().getHours()}; m: {this.getTime().getMinutes()};
s: {this.getTime().getSeconds()}
<br/>
{/* 标签体的内容可以插值到 render 中 */}
{this.props.children}
</div>
)
}
}
// 函数组件
// 参数props就是标签的html属性
// props 中也包含 children
function BComponent(props) {
// 此处的this为 undefined
// 之所以为 undefined 是因为函数组件没有实例对象
console.log(this)
console.log(props)
// 可以在组件内声明其他函数和变量
let count = 0
function getCount() {
return count
}
// 函数组件必须返回一个react-dom对象
return (
<div>
<div>我是一个函数组件</div>
<div>{count}: {getCount()}</div>
<div>{props.children}</div>
</div>
)
}
ReactDOM.createRoot(document.querySelector('#root')).render((
<div>
{/* 组件被当作标签使用 */}
{/* 可以使用插值给属性赋值 这样赋值的属性就可以不是字符串 */}
<AComponent name="张三" age={16} isShow={false}>
<div>hello</div>
<div>world</div>
</AComponent>
<AComponent></AComponent>
<BComponent name="张三" age={16} isShow={false}>
<h1>这是BComponent的标签体</h1>
<div>hello</div>
<div>world</div>
</BComponent>
</div>
))
</script>
</html>
事件处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
<script src="../js/babel.min.js"></script>
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/babel">
// 知识点
// 绑定事件的基本
// 1. on+事件名称
// 2. 使用花括号插值一个事件处理程序
// 3. 获取事件对象
// 4. 给事件处理程序传参
// react 中 无法使用 return false 直接屏蔽默认事件
function App() {
// 事件处理程序添加参数ev
// ev代表事件对象
function contextMenuHandler(ev, id) {
// 屏蔽默认事件
ev.preventDefault()
console.log('contextMenuHandler')
console.log(ev)
console.log(id)
}
return (
<div>
{/*<button onContextMenu={contextMenuHandler}>点击</button>*/}
{/* 使用箭头函数在调用事件处理程序的时候传递参数 */}
<button onContextMenu={ev => {
contextMenuHandler(ev, 5)
}}>点击
</button>
{/* react 无法直接通过 return false 屏蔽默认事件 */}
<form onSubmit="return false">
<button>提交</button>
</form>
</div>
)
}
ReactDOM.createRoot(document.querySelector('#root')).render(<App/>)
</script>
</html>
class 组件状态 state
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
<script src="../js/babel.min.js"></script>
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script type="text/babel">
// 文档:https://zh-hans.reactjs.org/docs/state-and-lifecycle.html
// 知识点
// 什么是组件状态?
// 在计算开发领域 怎么理解状态(state)这个英文?
// 假设我们制作一个时钟,时钟每秒钟的时间值都不一样
// 那么我们将描述某个 “时刻” 的时钟的 “数据” 称为该时钟在那个 “时刻” 的 “状态” (state)
// 所以 state 一词,通常指某个时刻用于描述某个对象的数据模型
// 因此 有时会听到上一个状态 下一个状态的说法 这指的就是不同时刻 描述同一个对象的数据模型
// 声明状态
// 组件的状态更新 this.setState 的使用
// 1. 不要直接修改 state 要通过 setState 修改
// 2. setState 的参数不要直接依赖 this.state 或 this.props;应使用 this.setState((state, props)=>{return {}}) 代替
// 3. setState 方法是异步的 可以通过 setState 的第二个回调函数 来执行赋值成功后的代码
// 4. setState 最终会修改 this.state
class App extends React.Component {
// 在属性的地方可以声明一个 state 状态对象
// state = {}
constructor(props) {
super(props);
// 在构造函数中使用 this.state 来声明状态
this.state = {
count: 0
}
setInterval(() => {
// 更新自身状态
// 1. 不要直接修改 state 要通过 setState 修改
// this.state.count++
// 2. setState 的参数不要直接依赖 this.state 或 this.props;应使用 this.setState((state, props)=>{return {}}) 代替
// this.setState({count: this.state.count + 1})
// setState 的参数是一个回调函数
// 回调函数中 state 代表当前状态 props 代表当前属性
// this.setState((state, props) => {
// // 函数中需要返回一个要赋值的对象
// return {count: state.count + 1}
// })
// 3. setState 是异步的
// 当执行第一句setState的时候 this.state.count 的值还是上一次的 0
// this.setState({count: this.state.count + 1})
// // 执行第二局 setState 时 由于第一句 setState 是异步的,当执行第二局 setState 时 第一句还没有生效
// // 所以 此时的 this.state.count 依然为 0
// this.setState({count: this.state.count + 1})
// this.setState({count: this.state.count + 1})
// 若希望依赖state对象来赋值新的state 还是应该使用函数的方法来赋值
// 第二个参数代表赋值完成后的回调函数
this.setState(state => ({count: state.count + 1}), () => {
// console.log('第一次赋值count完成')
})
this.setState(state => ({count: state.count + 1}), () => {
// console.log('第二次赋值count完成')
})
this.setState(state => ({count: state.count + 1}), () => {
// console.log('第三次赋值count完成')
})
// 4. setState 最终会修改 this.state
console.log(this.state.count)
}, 1000)
}
render() {
return (
<div>
{this.state.count}
</div>
)
}
}
let root = ReactDOM.createRoot(document.querySelector('#app'))
// 若不存在组件时 更新数据的办法是 重复调用 root.render 函数
// let count = 0
//
// function render() {
// root.render((
// <div>{count}</div>
// ))
// }
//
// render()
//
// setInterval(() => {
// count++
// render()
// }, 1000)
root.render(<App/>)
</script>
</html>
函数组件状态state
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<script src="../js/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script type="text/babel">
// 文档:https://zh-hans.reactjs.org/docs/hooks-state.html
// 知识点
// useState
// setState 是异步的
// setState 依赖自己状态的时候,使用回调函数
// 状态值若为对象(或数组)时,为了状态能够被修改,需要赋值一个新的对象(或数组)
function App() {
// 在函数组件内使用 React.useState 来声明状态
// useState 参数代表状态的初始值
// 返回值是一个数组
// 0 号成员是 状态的 getter 用来读取状态
// 1 号成员是 状态的 setter 用来赋值状态
// const state = React.useState(0)
// console.log(state)
const [count, setCount] = React.useState(0)
const [obj, setObj] = React.useState({name: '张三'})
function increase() {
// 调用 setCount 修改状态
// setCount(5)
// setCount 也是异步的
// setCount(count + 1)
// setCount(count + 1)
// setCount(count + 1)
setCount(_count => _count + 1)
setCount(_count => _count + 1)
setCount(_count => _count + 1)
}
function updateName() {
// 若修改对象属性 setObj 还使用原来的 obj 对象的话
// 那么 react 会认为该对象没有变化(因为对象是引用传递的数据类型)
// 所以 页面无法跟新
obj.name = '李四'
// setObj(obj)
// 可以使用 扩展语法 克隆原有的obj对象来赋值
setObj({...obj})
}
return (
<div>
<div>count: {count}</div>
<div>obj.name: {obj.name}</div>
<div>
<button onClick={increase}>+</button>
<button onClick={updateName}>修改obj.name</button>
</div>
</div>
)
}
ReactDOM.createRoot(document.querySelector('#app')).render(<App/>)
</script>
</html>