React学习笔记(二) 组件

简介: 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) {
        // 将 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')
);



目录
相关文章
|
7月前
|
设计模式 前端开发 数据可视化
【第4期】一文了解React UI 组件库
【第4期】一文了解React UI 组件库
382 0
|
7月前
|
存储 前端开发 JavaScript
【第34期】一文学会React组件传值
【第34期】一文学会React组件传值
80 0
|
7月前
|
前端开发
【第31期】一文学会用React Hooks组件编写组件
【第31期】一文学会用React Hooks组件编写组件
83 0
|
7月前
|
资源调度 前端开发 JavaScript
React 的antd-mobile 组件库,嵌套路由
React 的antd-mobile 组件库,嵌套路由
132 0
|
2月前
|
XML 前端开发 JavaScript
react学习笔记一:入门级小白到脚手架(create-react-app)开发项目
这篇文章是React的学习笔记,覆盖了从React的基础用法到高级特性,包括组件化、状态管理、生命周期、虚拟DOM等主题,适合React初学者参考。
111 0
react学习笔记一:入门级小白到脚手架(create-react-app)开发项目
|
6月前
|
移动开发 前端开发 Java
技术笔记:ReactNative学习笔记(一)————(RN)快速入门
技术笔记:ReactNative学习笔记(一)————(RN)快速入门
77 0
|
7月前
|
存储 前端开发 中间件
React组件间的通信
React组件间的通信
57 1
|
7月前
|
前端开发 JavaScript API
React组件生命周期
React组件生命周期
130 1
|
7月前
|
存储 前端开发 JavaScript
探索 React Hooks 的世界:如何构建出色的组件(下)
探索 React Hooks 的世界:如何构建出色的组件(下)
探索 React Hooks 的世界:如何构建出色的组件(下)
|
7月前
|
缓存 前端开发 API
探索 React Hooks 的世界:如何构建出色的组件(上)
探索 React Hooks 的世界:如何构建出色的组件(上)
探索 React Hooks 的世界:如何构建出色的组件(上)