书接上回,是不是感觉已经有点入门了。不过别急,码哥我准备了很多干货,等我们把这些基本几个章节的学完,码哥带着你一起装逼一起飞。我不大可能只是带着你们入门,那不是我的风格。码哥会教你如何开发一个完整中后台。前端后端如何匹配,什么安全什么策略都会教给你。如果你还有其它兴趣,我还可以教你许多网络知识,Android开发、IOS开发,Mac开发、
c#开发等等。总之,一年的时间你肯定学不完。根本学不完。
条件渲染
一句话,根据某种条件做出不同的渲染元素。所谓的条件就是各种判断,if
也好 三目运算符
也好。都行
比如,下面的两个用户组件:
为了美观,下面所有的示例中我统一用MUI的样式组件,关于MUI的安装我在第一节课就已经讲过了,如果你是从第一节学过来的,应该没什么问题。
// Users.jsx
import Typography from '@mui/material/Typography';
function UserGreeting(props) {
return <Typography variant="h1" gutterBottom> 欢迎回来!</Typography>;
}
function GuestGreeting(props) {
return <Typography variant="h1" gutterBottom>请登录.</Typography>;
}
export { UserGreeting, GuestGreeting };
现在我们要创建一个新的组件,这个组件的功能是根据用户登录的条件来显示其中一个组件。 我们来创建Greeging
组件如下:
//Greeting.jsx
import { UserGreeting, GuestGreeting } from "./Users";
export default function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
你看,这个最基本的条件渲染组件就完成了。很简单是不是,当然,我们还可以把条件弄的复杂一点:
元素变量
所谓元素变量就是把一个组件元素存储在一个变量中,渲染时直接渲染这个变量就可以了
比如有下面两个组件,一个是登录组件 LoginButton
,一个是登出组件 LogoutButton
// logButtons.jsx
import Button from "@mui/material/Button";
function LoginButton(props) {
return (
<Button variant="outlined" onClick={props.onClick}>
登录
</Button>
);
}
function LogoutButton(props) {
return (
<Button variant="outlined" onClick={props.onClick}>
退出
</Button>
);
}
export { LoginButton, LogoutButton };
接下来我们创建一个有状态的组件,根据上面两个按钮点击的结果显示不同的界面。
// LoginControl.jsx
import React from 'react';
import { LoginButton, LogoutButton } from './LogButtons';
import Greeting from './Greeting';
import Box from '@mui/material/Box';
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.state = { isLoggedIn: false };
//在构造函数中我们采用先绑定this的方法与事件绑定
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
}
handleLoginClick() {
this.setState({ isLoggedIn: true });
}
handleLogoutClick() {
this.setState({ isLoggedIn: false });
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={ this.handleLogoutClick } />;
} else {
button = <LoginButton onClick={ this.handleLoginClick } />;
}
return (
<Box>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</Box>
);
}
}
export default LoginControl;
至于为什么我这里不用函数组件的方式写这个 LoginControl 组件呢,因为我们还有很多Hook没有学习。当我们学习了所有的相关知识后,你就可以想怎么写就怎么写了。
上面的逻辑已经很清晰了,不用多讲什么了吧。
下面我们在App.jsx中调用这个组件就OK了,是不是很Nice,有点小激动不。
//App.jsx
import './App.css'
import "./styles.css";
// import Profile from './Profile'
// import ButtonClickTest from './buttonClickTest';
// import MyCompButton from './Test03/MyButtons';
// import Counter from './Test03/ClassComponentTest';
// import Clock from './Test03/Clock';
// import ClockFunc from './Test03/ClockFunc';
import LoginControl from './Test04/LoginControl';
function App() {
return (
<LoginControl />
)
}
export default App
关于 && 及 || 的渲染应用示例。
先看下面的示例
// Mailbox.jsx
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
export default function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<Box>
<Typography variant="h1">你好!</Typography>
{
unreadMessages.length > 0 &&
<Typography variant="h2">
你有 {unreadMessages.length} 条未读消息。
</Typography>
}
</Box>
);
}
这个时候如果我们直接在App.jsx中调用这个组件,什么也不会显示。但我们给 unreadMessages
传递两条信息就不一样了
//App.jsx
import './App.css'
import "./styles.css";
// import Profile from './Profile'
// import ButtonClickTest from './buttonClickTest';
// import MyCompButton from './Test03/MyButtons';
// import Counter from './Test03/ClassComponentTest';
// import Clock from './Test03/Clock';
// import ClockFunc from './Test03/ClockFunc';
// import LoginControl from './Test04/LoginControl';
import Mailbox from './Test04/Mailbox';
function App() {
return (
<Mailbox unreadMessages={["message1", "message2"]} />
)
}
export default App
是不是有点意思。
其实 条件 && 组件
的意思是 当条件为真时才渲染组件
, 这就是 && 的用法。类似的 || 的用法是这样的:
变量 || 组件
表示当变量不为null时,就显示 变量,当变量为 null 时,就显示 组件。我们也常常用 || 变量提供一个备选值。
不有三目运算符的用法:
我们把上面 组件 Greeting 修改一下:
import { UserGreeting, GuestGreeting } from "./Users";
export default function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
return (
<Box>
{
isLoggedIn
? <UserGreeting />
: <GuestGreeting />
}
</Box>
)
}
这样更直观一点。
阻止组件渲染
有时候我们希望在某种情况下我们的组件不要渲染出来。我们在 html
中用 css
可以设置隐藏组件,但它还是在文档流中,只是被隐藏了。但在我们的React中可以让它真正的消失,要达到这种效果,我们只要在组件中返回 null
即可。
//Page.jsx
import { Component } from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
function WarningBanner(props) {
return (
props.warn
? <Box className="warning"> 警告! </Box>
: null
);
}
class Page extends Component {
constructor(props) {
super(props);
this.state = { showWarning: true };
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(state => ({
showWarning: !state.showWarning
}));
}
render() {
return (
<Box>
<WarningBanner warn={this.state.showWarning} />
<Button variant="contained" onClick={this.handleToggleClick}>
{this.state.showWarning ? '隐藏' : '显示'}
</Button>
</Box>
);
}
}
export default Page;
上面我们定义了两个组件 WarningBanner
和 Page
, Page
组件中根据按钮点击后的的状态显示 WarningBanner
在 App.jsx中调用一下查看结果
import './App.css'
import "./styles.css";
// import Profile from './Profile'
// import ButtonClickTest from './buttonClickTest';
// import MyCompButton from './Test03/MyButtons';
// import Counter from './Test03/ClassComponentTest';
// import Clock from './Test03/Clock';
// import ClockFunc from './Test03/ClockFunc';
// import LoginControl from './Test04/LoginControl';
// import Mailbox from './Test04/Mailbox';
import Page from './Test04/Page';
function App() {
return (
<Page />
)
}
export default App
列表
我们来看看 JavaScript 中的数组遍历, 在控制台查看结果。
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);
在 React 中有时显示多个元素时也是用这个方法,如
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li> { number } </li>
);
基本列表
如下示例:
// NumberList.jsx
export default function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul> { listItems } </ul>
);
}
如果用的是VSCode,那么这时候应该有一个语法警告提示,我们先不管它。
我们在App.jsx中调用并传入props参数
import './App.css'
import "./styles.css";
import NumberList from './Test04/Numbers';
function App() {
return (
<NumberList numbers = {[1, 2, 3, 4, 5, 6]} />
)
}
export default App
此时运行,你会发现在控制台会有一条警告提示信息:
意思是列表元素少了 key
这个属性。React
要求,所有列表元素都必须要用 key
属性,它可以帮助 React
识别哪些项目已更改、添加或删除。应该为数组中的元素提供 key
,以使元素具有稳定的标识, 我们修改如下:
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
或
const todoItems = todos.map((todo, index) =>
<li key={index}>
{todo.text}
</li>
);
确保每个列表项的key
为唯一即可。 还有一点要注意的是我们不应该把 key 直接写入组件,比如下面的做法是错误的。
function ListItem(props) {
const value = props.value;
return (
// 错误,这里直接把key写到元素上了,li 原始元素并没有这个属性。
<li key={value.toString()}>
{value}
</li>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 错误。我们应该在这里为React组件指定key
<ListItem value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
正确的做法是这样的:
function ListItem(props) {
// 相当OK, 这里不需要指定 key,
return <li>{props.value}</li>;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 完全OK, 在这里我们为React组件指定了Key。 key是React内部使用,跟我们如何定义组件并没有多大的关联。数组列表我们额外加上就行了。
<ListItem key={number.toString()} value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
还有一点要注意,这个key
只要在同级之前是唯一的就行。如果列表内嵌套列表,子列表的 key
和外层的key即使相同也不冲突。像下面的示例
// Blog.jsx
export default function Blog(props) {
const sidebar = (
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) =>
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar}
<hr />
{content}
</div>
);
}
调用并运行它,我们会发现一切正常
import './App.css'
import "./styles.css";
import Blog from './Test04/Blog';
const posts = [
{ id: 1, title: 'Hello World', content: 'Welcome to learning React!' },
{ id: 2, title: 'Installation', content: 'You can install React from npm.' }
];
function App() {
return (
<Blog posts={posts} />
)
}
export default App
当前也可以直接在JSX中嵌入map
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
是不是感觉清爽多了。