React入门 Part2

组件

组件是React的核心概念,是React应用程序的基石。组件将应用的UI拆分成独立的、可复用的模块,React应用程序正是由一个个组件搭建而成的。

定义一个组件有两种方法:

  • 使用ES6 class (类组件)
  • 使用函数(函数组件)

组件定义

使用class定义组件

使用class定义组件需要满足的两个条件:

  • class继承自React.Component;
  • class内部必须定义render方法,render方法返回代表该组件UI的React元素;

在使用class定义类组件后,需要使用export将类组件导出,以便在其他文件中使用。

在使用时,需要导入react-dom库,并使用ReactDOM.render()显示,该方法有两个参数:

  • 第一个参数:要显示的组件;
  • 第二个参数:组件要显示的位置;

使用class定义组件:

import React from 'react'

class PostList extends React.Component {
    render() {
        return (
            <div>
                帖子列表:
                <ul>
                    <li>帖子1</li>
                    <li>帖子2</li>
                    <li>帖子3</li>
                    <li>帖子4</li>
                    <li>帖子5</li>
                    <li>帖子6</li>
                </ul>
            </div>
        );
    }
}

export default PostList;

使用:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import reportWebVitals from './reportWebVitals';

import PostList from './p2/PostList';

ReactDOM.render(
  <React.StrictMode>
    <PostList></PostList>
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();

组件的props

组件的props属性用于把父组件中的数据或者方法传递给子组件,供子组件使用。

props属性是不可变的。

创建子组件:

import React from 'react'

class PostItem extends React.Component {
    render() {
        const {title, author, date} = this.props;
        return(
            <li>
                <div>{title}</div>
                <div>创建人:<span>{author}</span></div>
                <div>创建时间:<span>{date}</span></div>
            </li>
        );
    }
}

export default PostItem;

在父组件中使用:

import React from 'react'
import PostItem from './PostItem'

//声明数据
const data = [
    { title: "帖子1", author: "张三", date: "2021-02-15 11:11:11"},
    { title: "帖子2", author: "李四", date: "2021-02-15 12:11:11"},
    { title: "帖子3", author: "王五", date: "2021-02-15 13:11:11"},
    { title: "帖子4", author: "赵六", date: "2021-02-15 14:11:11"}
];

class PostList extends React.Component {
    render() {
        return (
            <div>
                帖子列表:
                <ul>
                    {
                        //循环显示
                        data.map(item => 
                            <PostItem 
                                title={item.title}
                                author={item.author}
                                date={item.date}/>   
                    )}
                </ul>
            </div>
        );
    }
}

export default PostList;

组件的state

组件的state是组件内部的状态,state的变化最终将反映到组件UI的变化上。

可以在组件的构造方法(constructor)中通过this.state定义组件的初始状态,并通过this.setState方法改变组件的状态,进而组件的UI也会随之重新渲染。

注意点:

  • 在组件的构造方法constructor中,首先要调用super(props),这一步实际是调用React.Component中的构造方法,用于完成React组件的初始化工作;
  • 在constructor中,通过this.state定义了组件的状态;

添加点击事件:

import React from 'react'

class PostItem extends React.Component {

    constructor(props) {
        super(props);
        //定义初始状态
        this.state = {
            vote: 0
        }
    }
    
    //定义点击事件
    handleClick() {
        let newVote = this.state.vote;
        newVote++;
        this.setState({
            vote: newVote
        });
    }

    render() {
        const {title, author, date} = this.props;
        return(
            <li>
                <div>{title}</div>
                <div>创建人:<span>{author}</span></div>
                <div>创建时间:<span>{date}</span></div>
                <div>
                    <button onClick={() => this.handleClick()}>
                        点赞
                    </button>
                    &nbsp;
                    <span>
                        {this.state.vote}
                    </span>
                </div>
            </li>
        );
    }
}

export default PostItem;

React组件正是由props和state两种类型的数据驱动渲染出组件UI。props是组件对外的接口,组件通过props接受外部传入的数据;state是组件对内的接口,组件内部状态的改变通过state来反映。props是只读的,不能从内部修改props;state是可变的,组件状态的变化通过修改state来实现。

更改之后的PostList:

import React from 'react'
import PostItem from './PostItem'

class PostList extends React.Component {

    constructor(props) {
        super(props);
        //数据
        this.state = {
            posts:[]
        };
        //定时器
        this.timer = null;
        //指定点击事件
        this.handleVote = this.handleVote.bind(this);
    }

    //初次渲染结束
    componentDidMount() {
        //异步模拟从服务端请求数据
        this.timer = setTimeout(() => {
            this.setState({
                posts: [
                    {id: 1, title: "帖子1", author: "张三", date: "2021-02-15 11:11:11", vote: 0},
                    {id: 2, title: "帖子2", author: "李四", date: "2021-02-15 12:11:11", vote: 0},
                    {id: 3, title: "帖子3", author: "王五", date: "2021-02-15 13:11:11", vote: 0},
                    {id: 4, title: "帖子4", author: "赵六", date: "2021-02-15 14:11:11", vote: 0},
                ]});
        }, 1000);
    }

    //组件卸载之前
    componentWillUnmount() {
        if(this.timer) {
            //清除计时器
            clearTimeout(this.timer);
        }
    }

    //处理点击
    handleVote(id) {
        //找到目标item
        const newPosts = this.state.posts.map(item => {
            const newItem = item.id === id ? {...item, vote: ++item.vote} : item;
            return newItem;
        });
        //更新state中数据
        this.setState({
            posts: newPosts
        });
    }

    render() {
        return (
            <div>
                帖子列表:
                <ul>
                    {
                        this.state.posts.map(item => 
                            <PostItem post = {item} onVote= {this.handleVote} key ={item.id}/>
                        )
                    }
                </ul>
            </div>
        );
    }
}

export default PostList;

升级之后的PostItme:

import React from 'react'

function PostItem(props) {

    const handleClick = () => {
        props.onVote(props.post.id);
    };

    const { post } = props;

    return(
        <li>
            <div>{post.title}</div>
            <div>创建人:<span>{post.author}</span></div>
            <div>创建时间:<span>{post.date}</span></div>
            <div>
                <button onClick={handleClick}>点赞</button>
                &nbsp;
                <span>{post.vote}</span>
            </div>
        </li>
    );
}

export default PostItem;

属性校验

React提供了PropTypes这个对象,用于校验组件属性的类型。

PropTypes包含组件属性所有可能的类型,可以通过定义一个对象实现组件属性类型的校验。

使用PropTypes进行属性校验:

import React from 'react'
import PropTypes from 'prop-types'

class PostItem extends React.Component {

    constructor(props) {
        super(props);
        console.log(JSON.stringify(props.post));
    }

    //定义点击事件
    handleClick() {
        this.props.onVote(this.props.post.id);
    }

    render() {
        return(
            <li>
                <div>{this.props.post.title}</div>
                <div>创建人:<span>{this.props.post.author}</span></div>
                <div>创建时间:<span>{this.props.post.date}</span></div>
                <div>
                    <button onClick={() => this.handleClick()}>
                        点赞
                    </button>
                    &nbsp;
                    <span>
                        {this.props.post.vote}
                    </span>
                </div>
            </li>
        );
    }
}

//声明属性类型
PostItem.protoType = {
    post: PropTypes.object,
    onVote: PropTypes.func
}

export default PostItem;

也可对对象的属性进行校验,需要用到shape方法:

//声明属性类型
PostItem.protoType = {
    //对象内属性校验
    post: PropTypes.shape({
        id: PropTypes.number,
        title: PropTypes.string,
        author: PropTypes.string,
        date: PropTypes.string,
        vote: PropTypes.number
    }).isRequired,
    //属性类型.是否必须
    onVote: PropTypes.func.isRequired
}

组件样式

使用组件样式有两种方式:一种是外部css样式表,另一种是内联样式。

外部CSS样式表

此方式与开发Web应用时的方式相同,css样式表根据HTML标签类型、ID、class等选择器定义元素的样式。

唯一的区别是,React元素要使用className来作为class的选择器。

在src下创建style.css:

.testDiv {
    width: 100%;
    height: 50px;
    background-color: blue;
}

使用该css:

import React from 'react';

import '../style.css'

function MyDiv(props) {
    console.log("my div");
    return <div className='testDiv'>Test</div>;
}

export default MyDiv;

内联样式

内联样式实际上是CSS in JS的写法:将CSS样式写到JS文件中,用JS对象表示CSS样式,然后通过DOM类型节点的sytle属性引用相应样式对象。

当使用内联样式的时候,样式的属性名必须使用驼峰格式的命名。例如,background-color要写成backgroundColor。

示例代码:

import React from 'react';

//声明样式
const style = {
    width: "100%",
    height: "50px",
    backgroundColor: "red"
}

function AnthorMyDiv(props) {
    return <div style={style}>Test</div>;
}

export default AnthorMyDiv;

组件和元素

React元素是一个普通的JS对象,这个对象通过DOM节点或React组件描述界面是什么样子。

JSX语法就是用来创建React元素的。

React组件是一个class或者函数,它接收一些属性作为输入,返回一个React元素。

React组件是由若干React元素组建而成的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值