美文网首页
React组件的二三事

React组件的二三事

作者: 奔跑的大橙子 | 来源:发表于2023-09-25 11:49 被阅读0次

    一、起步

    创建一个React项目

    1.创建项目:npx create-react-app my-app

    2.打开项目:cd  my-app

    3.启动项目:npm  start 

    4.暴露配置项:npm  run  eject

    二、组件

    组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回⽤于描述⻚面展示内容的 React 元素。

    组件有两种形式:class组件和function组件。

    class组件

    class组件通常拥有状态生命周期继承于Component实现render⽅法

    用class组件创建一个 Clock:

    import React, { Component } from "react"

    export default class ClassComponent extends Component {

        constructor(props) {

            super(props);

            // 存储状态,在构造函数中初始化状态

            this.state = {

                date: new Date()

            };

        }

        // 组件挂载完成后执行:启动定时器每秒更新状态

        componentDidMount() {

            this.timer = setInterval(() => {

                // 更新state,不能用this.state

                this.setState({

                    date: new Date()

                })

            }, 1000);

        }

        // 组件卸载之前执行:停止定时器

        componentWillUnmount() {

            clearInterval(this.timer);

        }

        componentDidUpdate() { // 每次有值更新都会执行

            console.log("componentDidUpdate")

        }

        render() {

            const { date } = this.state;

            return (

                <div>

                    <h3>ClassComponent</h3>

                    <p>{date.toLocaleTimeString()}</p>

                </div>

            )

        }

    }

    function组件

    函数组件通常无状态,仅关注内容展示,返回渲染结果即可。

    从React16.8开始引入了hooks,函数组件也能够拥有状态

    用function组件创建一个 Clock: 

    import React, { useState, useEffect} from "react";

    export function FunctionComponent(props) {

        const [date, setDate] = useState(new Date())

        useEffect(() => { // 副作用

            // 相当于componentDidMount、componentDidUpdate、componentWillUnmount的集合

            const timer = setInterval(() => {

                setDate(new Date())

            }, 1000)

            return () => clearInterval(timer) // 组件卸载的时候执行

        },[])

        return (

            <div>

                <h3>FunctionComponent</h3>

                <p>{date.toLocaleTimeString()}</p>

            </div>

        )

    }

    三、正确使用setState

    setState(partialState, callback)

    1. partialState:object|function

    ⽤于产生与当前state合并的子集。

    2. callback:function

    state更新之后被调⽤。 

    关于 setState() 你应该了解三件事:

    1.不要直接修改 State

    例如,此代码不会重新渲染组件:

    // 错误示范

    this.state.comment = 'Hello';

    而是应该使用 setState() :

    // 正确使⽤

    this.setState({

      comment: 'Hello'

    });

    2.State 的更新可能是异步的

    出于性能考虑,React 可能会把多个 setState() 调⽤合并成⼀个调用。

    观察以下例子中log的值和button显示的counter。

    setState在合成事件和生命周期中是异步的:

    import React, { Component } from "react"

    export default class SetStatePage extends Component {

        constructor(props) {

            super(props);

            this.state = {

                counter: 0

            }

        }

        componentDidMount() {

            this.changeValue(1);

        }

        changeValue = (v) => {

            // setState在合成事件和生命周期中是异步的,这里说的异步其实是批量更新,达到优化性能的目的

            this.setState({

                counter: this.state.counter + v

            })

            console.log("counter", this.state.counter);

        }

        setCounter = () => {

            this.changeValue(1);

        }

        render() {

            const { counter } = this.state;

            return (

                <div>

                    <h3>SetStatePage</h3>

                    <button onClick={this.setCounter}>{counter}</button>

                </div>

            )

        }

    }

    使用定时器:setState在setTimeout中是同步的:

    import React, { Component } from "react"

    export default class SetStatePage extends Component {

        constructor(props) {

            super(props);

            this.state = {

                counter: 0

            }

        }

        changeValue = (v) => {

            this.setState({

                counter: this.state.counter + v

            })

            console.log("counter", this.state.counter);

        }

        setCounter = () => {

            // setState在setTimeout中是同步的

            setTimeout(() => {

                this.changeValue(1);

            }, 0);

        }

        render() {

            const { counter } = this.state;

            return (

                <div>

                    <h3>SetStatePage</h3>

                    <button onClick={this.setCounter}>{counter}</button>

                </div>

            )

        }

    }

    原生事件中修改状态:setState在原生事件中是同步的:

    import React, { Component } from "react"

    export default class SetStatePage extends Component {

        constructor(props) {

            super(props);

            this.state = {

                counter: 0

            }

        }

        componentDidMount() {

            document.getElementById('test').addEventListener('click', this.changeValue);

        }

        changeValue = () => {

            // setState在原生事件中是同步的

            this.setState({

                counter: this.state.counter + 1

            })

            console.log("counter", this.state.counter);

        }

        render() {

            const { counter } = this.state;

            return (

                <div>

                    <h3>SetStatePage</h3>

                    <button id="test">原生事件*{counter}</button>

                </div>

            )

        }

    }

    在回调中获取状态值:setState在回调中是同步的:

    import React, { Component } from "react"

    export default class SetStatePage extends Component {

        constructor(props) {

            super(props);

            this.state = {

                counter: 0

            }

        }

        changeValue = (v) => {

            this.setState({

                counter: this.state.counter + v

            },() => {

                // callback就是在state更新完成之后执行

                console.log("counter", this.state.counter);

            })

        }

        setCounter = () => {

            this.changeValue(1)

        }

        render() {

            const { counter } = this.state;

            return (

                <div>

                    <h3>SetStatePage</h3>

                    <button onClick={this.setCounter}>{counter}</button>

                </div>

            )

        }

    }

    总结: setState只有在合成事件和生命周期函数中是异步的,在原⽣事件和setTimeout中都是同步的,这⾥的异步其实是批量更新。

    3.State 的更新会被合并

    import React, { Component } from "react"

    export default class SetStatePage extends Component {

        constructor(props) {

            super(props);

            this.state = {

                counter: 0

            }

        }

        changeValue = (v) => {

          this.setState({

                counter: this.state.counter + v

            },() => {

                console.log("counter", this.state.counter);

            })

        }

        setCounter = () => {

            this.changeValue(1); // 不会执行

            this.changeValue(2); // 不会执行

            this.changeValue(3); // 会执行

        }

        render() {

            const { counter } = this.state;

            return (

                <div>

                    <h3>SetStatePage</h3>

                    <button onClick={this.setCounter}>{counter}</button>

                </div>

            )

        }

    }

    如果想要链式更新state:

    import React, { Component } from "react"

    export default class SetStatePage extends Component {

        constructor(props) {

            super(props);

            this.state = {

                counter: 0

            }

        }

        changeValue = (v) => {

            // setState函数

            this.setState(state => {

                return {

                    counter: state.counter + v

                }

            })

        }

        setCounter = () => {

            this.changeValue(1); // 会执行

            this.changeValue(2); // 会执行

            this.changeValue(3); // 会执行

        }

        render() {

            const { counter } = this.state;

            return (

                <div>

                    <h3>SetStatePage</h3>

                    <button onClick={this.setCounter}>{counter}</button>

                </div>

            )

        }

    }

    四、组件复合

    复合组件给与你足够的敏捷去定义自定义组件的外观和行为,这种方式更明确和安全。如果组件间有公⽤用的⾮UI逻辑,将它们抽取为JS模块导入使⽤而不是继承它。

    不具名:

    HomePage.js文件内容如下:

    import React, { Component } from "react";

    import Layout from './Layout'

    export default class HomePage extends Component {

        render() {

            return (

                <Layout showTopBar={false} showBottomBar={true} title="首页">

                    <div>

                        <h3>HomePage</h3>

                    </div>

                </Layout>

            )

        }

    }

    Layout.js文件内容如下:

    import React, { Component } from "react";

    import TopBar from '../components/TopBar'

    import BottomBar from '../components/BottomBar'

    export default class Layout extends Component {

        componentDidMount() {

            const { title = "商城" } = this.props;

            document.title = title;

        }

        render() {

            const { children, showTopBar, showBottomBar } = this.props;

            console.log('children', children)

            return (

                <div>

                    {showTopBar && <TopBar />}

                    {children}

                    <h3>Layout</h3>

                    {showBottomBar && <BottomBar />}

                </div>

            )

        }

    }

    TopBar.js文件内容如下:

    import React, { Component } from "react";

    export default class TopBar extends Component {

        render() {

            return (

                <div>

                    <h3>TopBar</h3>

                </div>

            )

        }

    }

    BottomBar.js文件内容如下:

    import React, { Component } from "react";

    export default class BottomBar extends Component {

        render() {

            return (

                <div>

                    <h3>BottomBar</h3>

                </div>

            )

        }

    }

    具名:传个对象进去

    userPage.js文件内容如下:

    import React, { Component } from "react";

    import Layout from './Layout'

    export default class UserPage extends Component {

        render() {

            return (

                <Layout showTopBar={true} showBottomBar={true} title="用户中心">

                    {

                        {

                            content: (

                                <div>

                                    <h3>UserPage</h3>

                                </div>

                            ),

                            text: "这是一个文本",

                            btnClick: () => {

                                console.log("btnClick")

                            }

                        }

                    }

                </Layout>

            )

        }

    }

    Layout.js文件内容如下:

    import React, { Component } from "react";

    import TopBar from '../components/TopBar'

    import BottomBar from '../components/BottomBar'

    export default class Layout extends Component {

        componentDidMount() {

            const { title = "商城" } = this.props;

            document.title = title;

        }

        render() {

            const { children, showTopBar, showBottomBar } = this.props;

            console.log('children', children)

            return (

                <div>

                    {showTopBar && <TopBar />}

                    {children.content}

                    {children.text}

                    <button onClick={children.btnClick}>button</button>

                    <h3>Layout</h3>

                    {showBottomBar && <BottomBar />}

                </div>

            )

        }

    }

    相关文章

      网友评论

          本文标题:React组件的二三事

          本文链接:https://www.haomeiwen.com/subject/tuzqbdtx.html