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,这是因为 classJavaScript 中是一个保留字,所以不能使用。

第 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 去除即可

📖 参考文档