# 一、react 简介
# 1、特点
- 声明式编程(vue3)
- 组件化开发(vue)
- 跨平台开发
可以使用 React Native 编写移动端程序、使用 React VR 开发虚拟 web 应用
# 3、简单上手
react 开发中,必须要有的三个包:
- react
- react-dom
- babel(将 jsx 转换为 React.createElement)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<!-- 必须加上type:让babel解析jsx语法 -->
<script type="text/babel">
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<h1>Hello, world!</h1>)
</script>
</body>
</html>
# 二、JSX 语法
# 1、标签使用
React 组件必须以大写字母开头,而 HTML 标签则必须是小写字母
<script type="text/babel">
function MyApp() {
return <h1>Hello, world!</h1>
}
// jsx -> React.createElement
root.render(<MyApp />)
</script>
JSX 比 HTML 更加严格,必须闭合标签
<script type="text/babel">
root.render(
<>
<h1>今日新闻</h1>
<p>lencamo正在学习React</p>
</>
)
</script>
# 2、class 属性
使用
className
来指定一个 CSS 的 class
更多写法 ✨
<script type="text/babel">
const isShow = true
// 方式1:使用字符串
// const classList = `one two ${isShow ? 'avatar' : ''}`
// 方式2:使用数组
const classList = ['one', 'two']
if (isShow) classList.push('avatar')
root.render(
<>
<h1>今日新闻</h1>
{/* 方式1 */}
<img className={classList} />
{/* 方式2 */}
<img className={classList.join(' ')} />
</>
)
</script>
提示
在项目开发中,我们还可以使用第三方库:classnames (opens new window)
<script type="text/babel">
const isShow = true
root.render(
<>
<h1>今日新闻</h1>
{/* 单个class */}
<img className="avatar" />
{/* 多个class */}
<img className={`one two ${isShow ? 'avatar' : ''}`} />
</>
)
</script>
<style>
.avatar {
border-radius: 50%;
}
</style>
# 3、内容渲染
上面使用""
传递的是字符串,而下面的{}
传递的是 js 内容
这意味着 react 和 vue 应用,在 jsx 中是可以嵌入:表达式、运算符、待执行函数等
- 普通数据
值为
undefined
、null
、Boolean
显示为 空值
Object 类型不能直接作为内容在元素中显示(可以使用其中的具体值)
<script type="text/babel">
let message = 'lencamo正在学习React'
root.render(
// 本质上讲就是后面要将的 <React.Fragment></React.Fragment>
<>
<h1>今日新闻</h1>
<p>{message}</p>
</>
)
</script>
- 使用对象
如下
# 3、style 属性
style={{}}
并不是一个特殊的语法,而是style={ }
JSX 大括号内的一个普通 {} 对象
<script type="text/babel">
const user = {
name: 'Hedy Lamarr',
imageUrl: 'https://picsum.photos/200/',
imageSize: 200
}
root.render(
<>
<h1>{user.name}</h1>
<img
src={user.imageUrl}
alt={'Photo of ' + user.name}
style={{
width: user.imageSize,
height: user.imageSize
}}
/>
</>
)
</script>
# 三、更新界面
# 1、响应事件
不同场景下的 click 事件使用方式
<!-- 原生 -->
<button onclick="myFunction()">Click me</button>
<!-- 小程序中 -->
<button bindtap="myFunction">Click me</button>
<!-- vue事件 -->
<button @click="myFunction">Click me</button>
<!-- react事件 -->
<!--
<button onClick={myFunction}>Click me</button>
-->
<script type="text/babel">
let count = 1
function myFunction() {
console.log('你点击了按钮')
// count++ // 更改失败
}
root.render(
<>
<div>{count}</div>
<button onClick={myFunction}>点击我.</button>
</>
)
</script>
# 2、数据更新 ✨
上面的案例中,我们要更新 count 其实最暴力的方法就是重新渲染界面:
代码实现
function myFunction() {
count++
// 重新渲染
root.render(
<>
<div>{count}</div>
<button onClick={myFunction}>点击我.</button>
</>
)
}
在后面的 react 类组件中,我们可以直接使用 this.setState()
进行数据更新
提示
在修改多层次数据(对象)时,通常不会直接修改它而是先进行浅拷贝,然后对浅拷贝对象进行修改,最后使用this.setState()
进行全局替换
increment(index) {
const newBooks = [...this.state.books]
newBooks[index].count += 1
this.setState({book: newBooks})
}
原因是实际开发中,我们更多的是继承于 PureComponent
,而不是 Component
# 3、参数传递
事件传参本就没什么好讲的,想想还是简单的记录一下吧
<script type="text/babel">
let numb = 1
function myFunction1(event) {
console.log(event)
}
function myFunction2(event, a, b) {
console.log(a + b)
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<>
{/* 传递event对象 */}
<button onClick={myFunction1}>点击我.</button>
<button onClick={(event) => myFunction1(event)}>点击我.</button>
{/* 传递自定义参数 */}
<button onClick={(event) => myFunction2(event, 1, numb)}>点击我.</button>
</>
)
</script>
# 四、逻辑渲染
react 中的条件渲染、列表渲染和写 js 没什么区别:
# 1、类组件 ✨
类组件需要 Component (opens new window) 的支持,其被定义为 React 组件的基类,类式组件仍然被 React 支持,但我们不建议在新代码中使用它们
react 类组件中的
this.setState()
和 小程序中的this.setData()
功能相似
this 指向问题
默认调用,其 this 默认为 window
;但在 babel 严格模式下,其 this 指向undefined
- 代码体验
<script type="text/babel">
const obj = {
foo: function () {
console.log('foo:', this)
}
}
obj.foo()
const config = {
onClick: obj.foo
// onClick: obj.foo.bind(obj)
}
const click = config.onClick
click()
</script>
类组件使用详情
在类组件中使用 this 时,我们要注意对 this 是否做了绑定,防止出现 undefined 的情况。
class Demo extends React.Component {
// 参与数据流
constructor(props) {
super(props)
this.state = {
count: 1
}
// this绑定方式1
// this.myFunction = this.myFunction.bind(this)
}
myFunction() {
// console.log(this)
// 更新界面🤔
this.setState({
count: this.state.count + 1
})
}
// this绑定方式2
// myFunction = () => {
// // console.log(this)
// // 更新界面🤔
// this.setState({
// count: this.state.count + 1
// })
// }
render() {
const { count } = this.state
return (
<>
<div>{count}</div>
{/* <button onClick={this.myFunction}>点击我.</button> */}
{/* this绑定方式1 */}
<button onClick={this.myFunction.bind(this)}>点击我.</button>
{/* this绑定方式2 */}
<button onClick={() => this.myFunction()}>点击我.</button>
</>
)
}
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<Demo />)
# 2、条件渲染
在 react 中,并没有想 vue 中的 v-if、v-show 等指令,而是让开发者自由发挥,自己编写判断逻辑。
class Demo extends React.Component {
// 使用if
render() {
let content
if (isLoggedIn) {
content = <AdminPanel />
} else {
content = <LoginForm />
}
return <div>{content}</div>
}
// 使用 三目运算
render() {
return <div>{isLoggedIn ? <AdminPanel /> : <LoginForm />}</div>
}
// 使用 &&
render() {
return <div>{isLoggedIn && <AdminPanel />}</div>
}
}
用户登录案例
class Demo extends React.Component {
constructor(props) {
super(props)
}
render() {
const { isLoggedIn } = this.props
if (isLoggedIn) {
return <UserGreeting />
}
return <GuestGreeting />
}
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<Greeting isLoggedIn={false} />)
显示与隐藏案例 ✨
前面我们已经知道了,在内容渲染时:如果值为 undefined
、null
、Boolean
显示的空值
class Demo extends React.Component {
// 参与数据流
constructor(props) {
super(props)
this.state = {
isShow: false,
message: '内容显示成功!'
}
}
changeShow() {
this.setState({ isShow: !this.state.isShow })
}
render() {
const { isShow, message } = this.state
return (
<>
<button onClick={() => this.changeShow()}>显示/隐藏</button>
{/* 类似于 vue 中的 `v-if` */}
{isShow && <h2>{message}</h2>}
{/* 类似于 vue 中的 `v-show` */}
{<h2 style={{ display: isShow ? 'block' : 'none' }}>{message}</h2>}
</>
)
}
}
# 3、列表渲染
和 vue 一样,在 react 中进行列表渲染时同样也需要 key 属性。
不同的是,需要自己采用数组方法进行进行元素的迭代创建。
<script type="text/babel">
function Demo() {
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 }
]
// 使用map函数
const listItems = products.map((product) => {
return <li key={product.id}>{product.title}</li>
})
// 支持放数组🤔
return <ul>{listItems}</ul>
}
</script>
电影列表案例
class Movies extends React.Component {
// 参与数据流
constructor(props) {
super(props)
this.state = {
movies: ['西虹市首富', '红海行动', '星际穿越', '战狼', '我不是药神'],
currentIndex: 0
}
}
itemClick(index) {
this.setState({ currentIndex: index })
}
render() {
const { movies, currentIndex } = this.state
return (
<div>
{/* 这部分可以根据个人喜好是否封装 */}
<ul>
{movies.map((item, index) => {
return (
<li
className={currentIndex === index ? 'active' : ''}
key={item}
onClick={() => this.itemClick(index)}
>
{item}
</li>
)
})}
</ul>
</div>
)
}
}
← 脚手架CRA react组件(上) →