前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ReactJS实战之组件和Props详解

ReactJS实战之组件和Props详解

作者头像
JavaEdge
发布2021-03-14 20:51:31
9980
发布2021-03-14 20:51:31
举报
文章被收录于专栏:JavaEdge

组件可以将UI切分成一些独立的、可复用的部件,这样就只需专注于构建每一个单独的部件。

组件从概念上看就像是函数,它可以接收任意的输入值(称之为props),并返回一个需要在页面上展示的React元素。

代码语言:javascript
复制
const me = {
	name: 'JavaEdge',
	age: "18",
	gender: 'boy'
}

ReactDOM.render(<div>
	123
	<Hello name={me.name}></Hello>
</div>, document.getElementById('example'));

但是怎么在界面中输出 name 呢,就需要组件接收该属性:

代码语言:javascript
复制
// 创建组件的方式一
function Hello(props) {
	// 如果在一个组件中 return null,则表示该组件空的,什么都不会渲染
	// 在组件中,必须返回一个合法的JSX虚拟DOM元素
	console.log(props)
	return <div>这是Hello组件 - {props.name}</div>
}

补全属性:

代码语言:javascript
复制
function Hello(props) {
	return <div>这是Hello组件 - {props.name} - {props.age} - {props.gender}</div>
}

ES6 中应该这么写:

代码语言:javascript
复制
ReactDOM.render(<div>
	123
	<Hello {...me}></Hello>
</div>, document.getElementById('example'));

注意这些 props 是只读的哦:

代码语言:javascript
复制
function Hello(props) {
	props.name = 'javascript'
	return <div>这是Hello组件 - {props.name} - {props.age} - {props.gender}</div>
}

向外暴露组件,需要配置识别文件后缀名哦

定义组件

函数定义组件

定义一个组件最简单的方式是使用JavaScript函数

该函数是一个有效的React组件,它接收一个单一的“props”对象并返回了一个React元素。 之所以称这种类型的组件为函数定义组件,是因为从代码来看,它就是一个js函数。

类定义组件

也可使用 ES6 的 class 来定义一个组件

上面两个组件在React中是相同的。

组件渲染

  • 在前面,我们遇到的React元素都只是DOM标签
  • React元素也可以是用户自定义的组件

当React遇到的元素是用户自定义的组件,它会将JSX属性作为单个对象传递给该组件,这个对象称之为props

例如,这段代码会在页面上渲染出”Hello,sss”

我们来回顾一下在这个例子中发生了什么:

  • 我们对元素调用了ReactDOM.render()
  • React将{name: 'sss'}作为props传入并调用Welcome组件
  • Welcome组件将Hello, sss元素作为结果返回。
  • React DOM将DOM更新为Hello, sss

警告: 组件名称必须以大写字母开头。 例如, 表示一个DOM标签,但 表示一个组件,并且在使用该组件时你必须定义或引入之

组合组件

组件可以在它的输出中引用其它组件,这就可以让我们用同一组件来抽象出任意层次的细节 在React应用中,按钮、表单、对话框、整个屏幕的内容等,这些通常都被表示为组件

例如,我们可以创建一个App组件,用来多次渲染Welcome组件

通常,一个新的React应用程序的顶部是一个App组件 但是,如果要将React集成到现有应用程序中,则可以从下而上使用像Button这样的小组件作为开始,并逐渐运用到视图层的顶部

警告: 组件的返回值只能有一个根元素 这也是要用一个 来包裹所有元素的原因

提取组件

你可以将组件切分为更小的组件,这没什么好担心的。

例如,来看看这个Comment组件:

这个组件接收author(对象)、text(字符串)、以及date(Date对象)作为props,用来描述一个社交媒体网站上的评论

这个组件由于嵌套,变得难以被修改,可复用的部分也难以被复用 所以让我们从这个组件中提取出一些小组件

  • 首先,我们来提取Avatar组件:

Avatar作为Comment的内部组件,不需要知道是否被渲染 因此我们将author改为一个更通用的名字user

建议从组件自身的角度来命名props,而不是根据使用组件的上下文命名

现在我们可以对Comment组件做一些小小的调整

接下来,我们要提取一个UserInfo组件,用来渲染Avatar旁边的用户名

这可以让我们进一步简化Comment组件

提取组件一开始看起来像是一项单调乏味的工作,但是在大型应用中,构建可复用的组件完全是值得的 当你的UI中有一部分重复使用了好几次(比如,Button、Panel、Avatar),或者其自身就足够复杂(比如,App、FeedStory、Comment),类似这些都是抽象成一个可复用组件的绝佳选择,这也是一个比较好的做法

Props的只读性

无论是使用函数或是类来声明一个组件,它决不能修改它自己的props。

  • 来看这个sum函数

类似于上面的这种函数称为“纯函数”,它没有改变它自己的输入值,当传入的值相同时,总是会返回相同的结果

与之相对的是非纯函数,它会改变它自身的输入值

React是非常灵活的,但它也有一个严格的规则:

所有的React组件必须像纯函数那样使用它们的props

当然,应用的界面是随时间动态变化的,下节介绍一种称为“state”的新概念,State可以在不违反上述规则的情况下,根据用户操作、网络响应、或者其他状态变化,使组件动态的响应并改变组件的输出

  • function形式

es6形式

  • state属性
    • 用来存储组件自身需要的数据。它是可以改变的,它的每次改变都会引发组件的更新。这也是 ReactJS 中的关键点之一。
    • 即每次数据的更新都是通过修改 state 属性的值,然后 ReactJS 内部会监听 state 属性的变化,一旦发生变化,就会触发组件的 render 方法来更新 DOM 结构。
  • props属性介绍:
    • props 是一个对象,是组件用来接收外面传来的参数的。
    • 组件内部是不允许修改自己的 props 属性,只能通过父组件来修改。上面的 getDefaultProps 方法便是处理 props 的默认值的。

    #组件间通信 父子组件间通信 这种情况下很简单,就是通过 props 属性传递,在父组件给子组件设置 props,然后子组件就可以通过 props 访问到父组件的数据/方法,这样就搭建起了父子组件间通信的桥梁。

代码语言:javascript
复制
import React, { Component } from 'react';
import { render } from 'react-dom';

class GroceryList extends Component {
  handleClick(i) {
    console.log('You clicked: ' + this.props.items[i]);
  }

  render() {
    return (
      <div>
        {this.props.items.map((item, i) => {
          return (
            <div onClick={this.handleClick.bind(this, i)} key={i}>{item}</div>
          );
        })}
      </div>
    );
  }
}

render(
  <GroceryList items={['Apple', 'Banana', 'Cranberry']} />, mountNode
);

div 可以看作一个子组件,指定它的 onClick 事件调用父组件的方法。 父组件访问子组件?用 refs

代码语言:javascript
复制
import React from 'react';
import ReactDOM from 'react-dom';

// 基础组件写法
function Component(){
    return <h1>I am sss</h1>
}

class ES6Component extends React.Component{
    render(){
        return <h1>I am sss in es6</h1>
    }
}

ReactDOM.render(
    <div>
        <Component/>
        <ES6Component/>
    </div>,
    document.getElementById('app')
);

// status && props
class Component extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        setTimeout(()=>{
            this.setState({
                name: 'sss Test'
            })
        },2000)
        return <h1>I am {this.state.name}</h1>
    }
}

ReactDOM.render(
    <div>
        <Component name="sss"/>
    </div>,
    document.getElementById('app')
);


// 事件处理方式1
class Component extends React.Component{
    constructor(props){
        super(props);
        this.state={
            name : 'sss',
            age : 18
        }
        this.handleClick = this.handleClick.bind(this)
    }
    handleClick(){
        this.setState({
            age : this.state.age + 1
        });
    }
    render(){
        return (
        <div>
            <h1>I am {this.state.name}</h1>
            <p>I am {this.state.age} years old!</p>
            <button onClick={this.handleClick}>加一岁</button>
        </div>
        );
    }
}



// 事件处理方式2
class Component extends React.Component{
    constructor(props){
        super(props);
        this.state={
            name : 'sss',
            age : 18
        }
    }
    handleClick(){
        this.setState({
            age : this.state.age + 1
        });
    }
    onValueChange(e){
        this.setState({
            age : e.target.value
        });
    }
    render(){
        return (
        <div>
            <h1>I am {this.state.name}</h1>
            <p>I am {this.state.age} years old!</p>
            <button onClick={(e) => {this.handleClick(e)}}>加一岁</button>
            <input type="text" onChange={(e) => {this.onValueChange(e)}}/>
        </div>
        );
    }
}



// 组件的组合方式
class Component extends React.Component{
    constructor(props){
        super(props);
        this.state={
            name : 'sss',
            age : 18
        }
    }
    handleClick(){
        this.setState({
            age : this.state.age + 1
        });
    }
    onValueChange(e){
        this.setState({
            age : e.target.value
        });
    }
    render(){
        return (
        <div>
            <h1>I am {this.state.name}</h1>
            <p>I am {this.state.age} years old!</p>
            <button onClick={(e) => {this.handleClick(e)}}>加一岁</button>
            <input type="text" onChange={(e) => {this.onValueChange(e)}}/>
        </div>
        );
    }
}

class Title extends React.Component{
    constructor(props){
        super(props);
    }
    render(props){
        return <h1>{this.props.children}</h1>
    }

}
class App extends React.Component{
    render(){
        return (
            <div className="">
                {/* 容器式组件 */}
                <Title>
                    <span>App Span</span>
                    <a href="">link</a>
                </Title>
                <hr/>
                {/* 单纯组件 */}
                <Component/>
            </div>
        );
    }
}


// 数据传递和状态提升
class Child1 extends React.Component{
    constructor(props){
        super(props);
    }
    handleClick(){
        this.props.changeChild2Color('red');
    }
    render(){
        return (
        <div>
            <h1>Child1: {this.props.bgColor}</h1>
            <button onClick={(e) => {this.handleClick(e)}}>改变child2 颜色</button>
        </div>
        );
    }
}
class Child2 extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return (
        <div style={{background:this.props.bgColor}}>
            <h1>Child2背景颜色: {this.props.bgColor}</h1>
        </div>
        );
    }
}

class Father extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            child2BgColor: '#999'
        }
    }
    onChild2BgColorChange(color){
        this.setState({
            child2BgColor : color
        })
    }
    render(props){
        return (
        <div>
            <Child1 changeChild2Color={(color) => {this.onChild2BgColorChange(color)}}/>
            <Child2 bgColor={this.state.child2BgColor}/>
        </div>
        );
    }

}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/03/13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义组件
    • 函数定义组件
      • 类定义组件
      • 组件渲染
      • 组合组件
      • 提取组件
      • Props的只读性
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档