zoukankan      html  css  js  c++  java
  • React学习笔记(二) 组件

    组件允许我们将代码拆分为独立可复用的代码片段,这是一个十分重要的概念

    1、函数组件

    我们可以通过编写 JavaScript 函数定义组件

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
        <script src="https://unpkg.com/babel-standalone"></script>
    </head>
    
    <body>
        <div id="app"></div>
    
        <script type="text/babel">
            // 通过 function 定义组件,函数返回一个 React 元素
            // 需要注意的是,组件名称必须以大写字母开头
            // 因为 React 会将以小写字母开头的组件视为原生 DOM 标签
            function SayHello() {
                return <h1>Hello World</h1>;
            };
    
            // React 元素不仅仅是 DOM 标签,也可以是自定义组件
            const element = <SayHello />;
    
            ReactDOM.render(
                element,
                document.getElementById('app')
            );
        </script>
    </body>
    
    </html>
    

    2、class 组件

    我们也可以通过使用 class 定义组件,并且推荐使用这种方式

    因为使用 class 定义组件允许我们为组件添加一些额外的方法和属性,使得组件具有更好的拓展性

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
        <script src="https://unpkg.com/babel-standalone"></script>
    </head>
    
    <body>
        <div id="app"></div>
    
        <script type="text/babel">
            // class 组件必须继承 React.Component
            class SayHello extends React.Component {
                // 使用 render() 函数返回一个 React 元素
                // 注意,该元素必须只能具有一个顶层标签
                render() {
                    return <h1>Hello World</h1>;
                }
            };
    
            // 使用组件的方法是一样的
            const element = <SayHello />;
    
            ReactDOM.render(
                element,
                document.getElementById('app')
            );
        </script>
    </body>
    
    </html>
    

    3、props

    当 React 元素为自定义组件时,JSX 接收的属性会转换为单个对象传递给组件,我们将这个对象称之为 props

    通过这种方式,我们可以给组件传递数据

    class SayHello extends React.Component {
        constructor(props) {
            // 为什么要调用 super?
            // 如果不调用 super,那就无法在构造函数中访问 this
            // 为什么要传入 props?
            // 如果不传入 props,那就无法在构造函数中访问 this.props
            super(props);
            console.log(this);
            console.log(this.props);
        }
        
        render() {
            // 在组件中通过 this.props 访问 props
            // 注意,props 应该是只读的,也就是说我们不应该修改它的取值
            return <h1>Hello { this.props.name }</h1>;
        }
    };
    
    // 这里将属性转换为 props 对象并传入组件
    const element = <SayHello name='Alice' />;
    
    ReactDOM.render(
        element,
        document.getElementById('app')
    );
    

    4、自定义函数

    通过自定义函数,我们可以在 class 组件中添加额外的方法

    class SayHello extends React.Component {
        // 构造函数
    	constructor(props) {
    		super(props);
    	}
        
        // 自定义函数
        format(name) {
            return name.substring(0,1).toUpperCase() + name.substring(1);
        }
        
        render() {
            // 通过 this.functionName() 调用自定义函数
            let formatedName = this.format(this.props.name);
        	return <h1>Hello { formatedName }</h1>;
        }
    };
    
    const element = <SayHello name='alice'/>;
    
    ReactDOM.render(
        element,
        document.getElementById('app')
    );
    

    5、state

    通过 state,我们可以在 class 组件中添加额外的数据

    state 与 props 都是组件的数据,不同之处在于 props 是从父组件传入的数据,而 state 是本组件私有的数据

    class Timer extends React.Component {
    	constructor(props) {
    		super(props);
            // 初始化 state
    		this.state = { date: new Date() };
    	}
    
        render() {
            // 通过 this.state 访问 state
            return (
                <div>
            	    <h1>Hello</h1>
                    <p>现在是{ this.state.date.toLocaleTimeString() }</p>
                </div>
            )
        }
    };
    
    const element = <Timer />;
    
    ReactDOM.render(
        element,
        document.getElementById('app')
    );
    

    使用 state 有几个需要特别注意的地方:

    • 不要直接修改 state

    我们可以直接访问 state,但是不能直接修改 state,例如

    this.state.date = new Date()
    // 这样的语句并不会重新渲染组件
    

    要想修改 state 并重新渲染组件,我们可以使用 this.setState(),例如

    this.setState({date: new Date()})
    

    但是构造函数是唯一特别的地方,我们可以直接在构造函数里面给 this.state 赋值,例如

    this.state = { date: new Date() }
    
    • state 的更新是异步的

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

    因此,this.propsthis.state 可能会异步更新,所以不要依赖它们的值来更新 state

    this.setState({
    	counter: this.state.counter + this.props.increment
    })
    // 这样的代码可能不会正常更新 counter
    

    要解决这个问题,可以让 setState() 接收一个函数作为参数,而不是一个对象

    这个函数的第一个参数为上一个 state,第二个参数为此次更新被应用时的 props,返回一个对象

    this.setState((state, props) => ({
    	counter: state.counter + props.increment
    }));
    
    • state 的更新会被合并

    setState() 调用会把提供的对象合并到当前 state,而非替换

    也就是说,假如我们在构造函数中初始化 state 如下:

    constructor(props) {
        super(props);
        this.state = {
            name: 'Alice',
            phone: '12345679810'
        };
    }
    

    然后调用 setState() 方法更新 state 如下:

    this.setState({
    	phone: '10987654321'
    })
    

    此时,state 中的数据应该是 { name: 'Alice', phone: '10987654321'},而不是 { phone: '10987654321' }

    6、生命周期

    每个组件都有生命周期,都会包含生命周期方法,我们可以通过重写这些方法,使得组件在特定阶段完成特定操作

    组件的生命周期大体可以分为三个阶段,每个阶段调用生命周期方法的顺序如下:

    挂载:当组件插入到 DOM 中时触发

    • constructor():在组件挂载前调用,主要用于初始化 state 或为事件处理函数绑定实例

      这里不要使用 setState() 方法,如果需要初始化 state,可以直接给 this.state 赋值

    • render():class 组件中唯一必须实现的方法,该函数应该为纯函数

      也就是说在不修改 state 的情况下,每次调用返回相同的结果,并且它不与浏览器进行交互

    • componentDidMount():在组件挂载后调用,主要进行依赖于 DOM 结点的初始化操作

      例如实例化请求或添加订阅,这里可以使用 setState() 方法

    更新:当组件的 props 或 state 发生改变时触发

    • render()

    • componentDidUpdate():在更新之后调用,但是首次渲染不会执行

      这里可以进行 DOM 操作,并且可以使用 setState() 方法,但必须包含在一个条件语句里面

    卸载:当组件从 DOM 中移除时触发

    • componentWillUnmount():在组件卸载之前调用

      这里不应使用 setState() 方法,因为组件卸载之后,将永远不会重新渲染,也不会重新挂载

    class Timer extends React.Component {
        // 生命周期方法,在挂载前调用
    	constructor(props) {
    		super(props);
            // 初始化 state
    		this.state = { date: new Date() };
    	}
        
        // 自定义方法
        tick() {
            // 通过 this.setState() 修改 state
            this.setState({
                date: new Date()
            })
        }
        
        // 生命周期方法,在挂载后调用
        componentDidMount() {
            this.timerID = setInterval(() => this.tick(), 1000)
        }
        
        // 生命周期方法,在卸载前调用
        componentWillUnmount() {
            clearInterval(this.timerID)
        }
    
        // 生命周期方法,在挂载或更新时调用
        render() {
            // 通过 this.state 访问 state
            return (
                <div>
            	    <h1>Hello</h1>
                    <p>现在是{ this.state.date.toLocaleTimeString() }</p>
                </div>
            )
        }
    };
    
    const element = <Timer />;
    
    ReactDOM.render(
        element,
        document.getElementById('app')
    );
    

    【 阅读更多 React 系列文章,请看 React学习笔记

    版权声明:本博客属于个人维护博客,未经博主允许不得转载其中文章。
  • 相关阅读:
    JS设置Cookie过期时间
    linq to xml
    ToDictionary的用法
    为程序使用内存缓存(MemoryCache)
    NuGet的几个小技巧
    IIS 的几个小技巧
    在Visual Studio中使用NuGet管理项目库
    在ASP.NET MVC中,使用Bundle来打包压缩js和css
    在C#中使用WMI查询进程的用户信息
    WMI测试器
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/11314566.html
Copyright © 2011-2022 走看看