React - 组件
接 使用 Vite 创建一个 React 项目 这篇文章,以下是目前搭建好的页面效果
从图中可以看到,整体的一个布局元素:
- 顶部导航栏
- 左侧
- logo
- navList
- 右侧
- 暗黑主题切换开关
- login 按钮
- 左侧
- 内容部分(路由嵌套,跳转时局部显示内容)
目录
一个项目中,我们肯定会有需要用到组件封装的地方,然后会用到组件通信,获取数据等等,所以这里我们简单的看下 React 中组件的使用和组件通信。
- 类组件
- 函数组件
- 组件通信
以下的介绍,无论是 类组件
和 函数组件
,我都会使用同一个例子,这个例子也在项目中实际使用,具体的代码可以在项目中查找对应组件看到。
类组件
第 1 步 - 创建一个 NavBar
组件
使用类组件,需要继承
React.Component
,以及写一个render
函数,在这个函数中去return
你需要返回的页面结构。
在 src/components/NavBar
下新建一个 NavBar.jsx
文件,代码如下:
class NavBar extends React.Component {
render() {
return (
<div className=""></div>
)
}
}
export default NavBar
需要注意的是,在 React
中,我们一般使用 className
而不是 class
,这是因为 class
在 JavaScript
中是一个保留字,所以不能使用。
第 2 步 - 在 Layout
页面中使用 NavBar
组件
在 src/containers/layout
下新建一个 layout.jsx
文件,代码如下:
import Navbar from "@/components/NavBar/NavBar";
class Layout extends React.Component {
render() {
return (
<div className="layout">
<NavBar />
</div>
)
}
}
export default Layout
函数组件
在 函数组件
中,我们只需使用 function
关键字定义一个函数,然后在这个函数中 return
你需要返回的页面结构即可。
export default function NavBar() {
return (
<div className=""></div>
)
}
组件通信
类组件通信
- 父传子
在 Layout
页面中,引用 NavBar
组件,并向它传递 NavList
数组。
父组件 - Layout.jsx
class Layout extends React.Component {
render() {
const navList = [
{
title: 'Home',
path: '/home'
},
{
title: 'Record',
path: '/record'
},
];
return (
<div className="layout">
<NavBar navList={navList} />
</div>
)
}
}
export default Layout
接收 父组件
传来的参数,我们使用 this.props.navList
来接收。
由于 navList
是一个数组, 我们需要使用 map
方法把它遍历出来。
props 是父组件传给子组件的一个对象,里面包含了要传的所有值
子组件 - NavBar.jsx
class NavBar extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="home-nav-list">
{
this.props.navList.map((item, index) => {
return (
<NavLink
className={({ isActive }) => isActive ? "home-nav-list-item active" : "home-nav-list-item"}
to={item.path}
key={index}
onClick={}
>
{item.title}
</NavLink>
)
})
}
</div>
)
}
}
export default NavBar
- 子传父
在 NavBar
组件中,引用了 ThemeToogle
组件,来控制 主题切换。当子组件点击时,会向父组件传递当前是否为暗黑主题,由这个参数来作为 NavBar
组件中,左侧 logo
不同主题下的内容显示。
首先,我们在
constructor
中,定义一个this.state
对象,来存储当前状态值isDarkTheme
。写一个方法
getThemeState
用于接收子组件传递来的值,并且通过this.setState
,来修改state
中的isDarkTheme
值。在
NavBar
组件中,给ThemeToggle
组件,传递定义好的getThemeState
方法在
return
中,使用时,通过this.state.xxx
来使用变量
父组件 - NavBar.jsx
class NavBar extends React.Component {
constructor(props) {
super(props);
this.state = {
isDarkTheme: false // 是否为暗黑主题
};
}
// 更改主题状态值
getThemeState = (data) => {
this.setState({ isDarkTheme: data });
}
render() {
return (
<div className="home-nav">
<div className="home-nav-lt flex-al">
{/* logo */}
<Link to="/">
<img src={this.state.isDarkTheme ? logoDark : logo} className="logo"></img>
</Link>
{/* navList */}
<div className="home-nav-list flex-al"></div>
</div>
<div className="home-nav-rt flex-al">
{/* ThemeToggle */}
<ThemeToggle getThemeState={this.getThemeState} />
</div>
</div>
)
}
}
export default NavBar
在子组件中,通过获取输入框的值,向父组件传递当前 e.target.checked
所获取到的值。
子组件通过 this.props.getThemeState
来调用父组件中的 getThemeState
方法,并把值传递给父组件。
子组件 - ThemeToogle.jsx
class ThemeToogle extends React.Component {
// 获取输入框的值
handleGetInputValue = (e) => {
// 从input点击事件获取的是值
let isDark = e.target.checked;
// 把值传递给 NavBar 父组件
this.props.getThemeState(isDark);
// 切换主题
if (isDark) {
...
} else {
...
}
}
render() {
return (
<>
<input type="checkbox" id="darkmode-toggle"
onChange={this.handleGetInputValue}
/>
<label htmlFor="darkmode-toggle">
<svg className="sun"></svg>
<svg className="moon"></svg>
</label>
</>
)
}
}
export default NavBar
函数组件通信
与 类组件
的区别,大概就是:
通过
useState
来初始化状态值且通过
useState
中,定义好的setXXX
,来更改状态值在
return
中使用时,直接使用变量,不用再另外加this
- 父传子
layout
父页面,这里跟上面一样,我就不写了,主要写一下,子组件 NavBar
接收参数
因为是 函数组件 ,所以我们直接在 函数组件 中添加 props
参数。 使用时,直接使用 props.xxx
即可,不用再加 this
。
子组件 - NavBar.jsx
export default function NavBar(props) {
return (
<div className="home-nav-list">
{
props.navList.map((item, index) => {
return (
<NavLink
className={({ isActive }) => isActive ? "home-nav-list-item active" : "home-nav-list-item"}
to={item.path}
key={index}
onClick={}
>
{item.title}
</NavLink>
)
})
}
</div>
)
}
- 子传父
在
NavBar
父组件中,通过useState
来初始化状态值,这里我们初始化为false
。以及定义好setXXX
方法,来更改状态值。定一个
getThemeState
方法,给ThemeToggle
组件传递 ,这个方法会接收子组件传递过来的值,然后调用setIsDarkTheme
方法,来更新状态值。定义变量 和 方法 时,别忘了加上
const
在
return
中使用的时候,不用加上this
父组件 - NavBar.jsx
export default function NavBar(props) {
// 主题切换 状态初始化
const [isDarkTheme, setIsDarkTheme] = useState(false);
// 更改主题状态值
const getThemeState = (data) => {
setIsDarkTheme(data);
}
return (
<div className="home-nav">
<div className="home-nav-lt flex-al">
{/* logo */}
<Link to="/">
<img src={isDarkTheme ? logoDark : logo} className="logo"></img>
</Link>
{/* navList */}
<div className="home-nav-list flex-al"></div>
</div>
<div className="home-nav-rt flex-al">
{/* ThemeToggle */}
<ThemeToggle getThemeState={getThemeState} />
</div>
</div>
)
}
子组件中,别忘了添加参数 props,以及给方法加上 const
子组件 - ThemeToogle.jsx
export default function ThemeToogle(props) {
// 获取输入框的值
const handleGetInputValue = (e) => {
// 从input点击事件获取的是值
let isDark = e.target.checked;
// 把值传递给 NavBar 父组件
props.getThemeState(isDark);
// 切换主题
if (isDark) {
...
} else {
...
}
}
render() {
return (
<>
<input type="checkbox" id="darkmode-toggle"
onChange={handleGetInputValue}
/>
<label htmlFor="darkmode-toggle">
<svg className="sun"></svg>
<svg className="moon"></svg>
</label>
</>
)
}
}
插槽 - slot
在 React 中,我们怎么实现 Vue 里的,<slot></slot>
?
默认插槽
- 类组件
父组件 - NavBar.jsx
class NavBar extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<>
<Container className="container">
<div className="home-nav-list"></div>
</Container>
</>
)
}
}
export default NavBar
子组件 - Containerr.jsx
class Container extends React.Component {
render() {
// this.props.children; 通过props.children 可以打印出来看出组件的信息
return (
<div className="container">
{this.props.children}
</div>
)
}
}
export default Container
- 函数组件
与 类组件
类似,就是在 子组件 中,把 this
去除即可