Skip to content
On this page
🎨 作者:Jacinda 📔 阅读量:

React - 组件 ​

接 使用 Vite 创建一个 React 项目 这篇文章,以下是目前搭建好的页面效果

图 0

从图中可以看到,整体的一个布局元素:

  • 顶部导航栏
    • 左侧
      • logo
      • navList
    • 右侧
      • 暗黑主题切换开关
      • login 按钮
  • 内容部分(路由嵌套,跳转时局部显示内容)

目录 ​

一个项目中,我们肯定会有需要用到组件封装的地方,然后会用到组件通信,获取数据等等,所以这里我们简单的看下 React 中组件的使用和组件通信。

  • 类组件
  • 函数组件
  • 组件通信

以下的介绍,无论是 类组件 和 函数组件,我都会使用同一个例子,这个例子也在项目中实际使用,具体的代码可以在项目中查找对应组件看到。

类组件 ​

第 1 步 - 创建一个 NavBar 组件 ​

使用类组件,需要继承 React.Component,以及写一个 render 函数,在这个函数中去 return 你需要返回的页面结构。

在 src/components/NavBar 下新建一个 NavBar.jsx 文件,代码如下:

javascript
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 文件,代码如下:

javascript
import Navbar from "@/components/NavBar/NavBar";

class Layout extends React.Component {
    render() {
        return (
            <div className="layout">
                <NavBar />
            </div>
        )
    }
}

export default Layout

函数组件 ​

在 函数组件 中,我们只需使用 function 关键字定义一个函数,然后在这个函数中 return 你需要返回的页面结构即可。

javascript
export default function NavBar() {
    return (
        <div className=""></div>
    )
}

组件通信 ​

类组件通信 ​

  • 父传子

在 Layout 页面中,引用 NavBar 组件,并向它传递 NavList 数组。

父组件 - Layout.jsx

javascript
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

javascript
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 不同主题下的内容显示。

  1. 首先,我们在 constructor 中,定义一个 this.state 对象,来存储当前状态值 isDarkTheme。

  2. 写一个方法 getThemeState 用于接收子组件传递来的值,并且通过 this.setState,来修改 state 中的isDarkTheme 值。

  3. 在 NavBar 组件中,给 ThemeToggle 组件,传递定义好的 getThemeState 方法

  4. 在 return 中,使用时,通过 this.state.xxx 来使用变量

父组件 - NavBar.jsx

javascript
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

javascript
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

函数组件通信 ​

与 类组件 的区别,大概就是:

  1. 通过 useState 来初始化状态值

  2. 且通过 useState 中,定义好的 setXXX,来更改状态值

  3. 在 return 中使用时,直接使用变量,不用再另外加 this

  • 父传子

layout 父页面,这里跟上面一样,我就不写了,主要写一下,子组件 NavBar 接收参数

因为是 函数组件 ,所以我们直接在 函数组件 中添加 props 参数。 使用时,直接使用 props.xxx 即可,不用再加 this。

子组件 - NavBar.jsx

javascript
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>
    )
}
  • 子传父
  1. 在 NavBar 父组件中,通过 useState 来初始化状态值,这里我们初始化为 false。以及定义好setXXX 方法,来更改状态值。

  2. 定一个 getThemeState 方法,给 ThemeToggle 组件传递 ,这个方法会接收子组件传递过来的值,然后调用 setIsDarkTheme 方法,来更新状态值。

  3. 定义变量 和 方法 时,别忘了加上 const

  4. 在 return 中使用的时候,不用加上 this

父组件 - NavBar.jsx

javascript
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

javascript
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

javascript
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

javascript
class Container extends React.Component {
    render() {
        // this.props.children; 通过props.children 可以打印出来看出组件的信息
        return (
            <div className="container">
                {this.props.children}
            </div>
        )
    }
}
export default Container
  • 函数组件

与 类组件 类似,就是在 子组件 中,把 this 去除即可

📖 参考文档 ​