在React中实现一个组件

本文简单介绍了如何编写一个React 组件。为了快速演示,文章中出现的示例代码均用 react-create-app 官方推荐的脚手架快速搭建的项目中完成,react-create-app 传送门

一、组件的介绍

Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.

组件可以让你把UI切分成独立的、可复用的块去单独的考虑和开发

二、组件的写法

展示型组件(Pure Component 、函数组件)

展示型组件是用来展示样式的,他们不绑定任何东西且没有依赖性,通常被实现为无状态功能组件。

// BlogList.jsimport React from "react";
export const BlogList = bloglist => (  
<ul>   
 {bloglist.map(({ body, author,id }) =>      
        <li key={id}>{body}-{author}</li>    
 )}  
</ul>
)复制代码

使用class定义一个组件

import React from "react";

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}复制代码

三、组件的编写

Demo 1

 以上面的展示型组件为例子,在用 react-create-app 生成的目录中创建components 文件夹用于存放我们的组件(react-create-app 的使用方法 传送们

    

然后在我们的App.js 里面 引入 BlogList.js 


最后在页面中查看




Demo 2 

最近用了Angular Js 和 Vue, 在写表单的时候基于双向数据绑定,写起来是相当的happy,当然,React 的单向数据流也有着自己的优点。基于此我们可以对项目中常用的表单控件进行组件的封装,下面以checkbox 为列。

stap1:

 首先我们在components 文件夹下面创建Checkbox文件夹以及Checkbox.js 文件

stap2:

  按照通常的写页面的方式编写Checkbox.js 文件,并在App.js 中引用

// Checkbox.js
import React,{Component} from 'react';
class CheckBox extends Component {
        render() {
            return (
                <label><input type="checkbox" />点击我</label> 
           )        
}    
}export default  CheckBox;
复制代码

// App.js
import CheckBox from './compoents/CheckTest/CheckTest'
....
return ( 
     <div className="App">       
     .....        
        <div>
            <CheckBox></CheckBox>
        </div>      
    </div>   
 );复制代码


这样我们的Checkbox 组件就被加载到了页面,但是label 被我们写死了‘点击我’,怎么实现动态替换呢?

// Checkbox.js

<span>
     {this.props.children !== undefined ? this.props.children : null}
</span>
复制代码

// App.js

render() {
    return (
      <div className="App">
        ...        
        <div>            
        <CheckBox>新的点击我</CheckBox>        
        </div>      
      </div>    
    );  
}
复制代码

现在查看,页面中的点击我就替换成了新的点击我了,到目前为止,实现了一个无状态的Checkbox,但是在开发中,我们要获取到checkbox 的选中状态,如果有多个checkbox ,我们还要得到选中的是哪几个checkbox。

stap3:

// Checkbox.js
import React from "react"import "./CheckBox.less"
class CheckBox extends React.Component {
    constructor(props) { 
       super(props)
       this.checkCheckBox = this.checkCheckBox.bind(this); 
       this.state = {
            value: props.value || ''        
        }    
    }    
    checkCheckBox() {
            const onChange = this.props.onChange;
            const value = this.props.value;
            if (onChange) {
                onChange(value);
            }    
    }
    render() {
        let {value} = this.state;
        return (
            <label>
                 <input value={value} type="checkbox" onClick={this.checkCheckBox}/>
                 {this.props.children !== undefined ? this.props.children : null}
            </label>
        )
    }}export default  CheckBox;复制代码

上述代码,我们的Checkbox接收父组件传下来的value 和 onChange 方法,在点击的时候,把组件的value 值传上去,然后在父组件中获取

class App extends Component {
  onChange=(value)=>{
    console.log('当前点击',value)
  }
  render() {
    return (
      <div className="App">
        ...
        <div>
            <CheckBox value='checkbox1' onChange={this.onChange}>checkbox1</CheckBox>
            <CheckBox value='checkbox2' onChange={this.onChange}>checkbox2</CheckBox>
        </div>
      </div>
    );
 }}复制代码

这样在每次点击的时候可以在控制台看到


stap4

现在有个新的需求,在checkbox 加载的时候有的checkbox 是默认选中的,怎么样在父组件控制选中状态呢。

class CheckBox extends React.Component {
    constructor(props) {
        super(props)
        this.checkCheckBox = this.checkCheckBox.bind(this);
        this.state = {
            is_checked: props.checked || false,
            value: props.value || ''
        }
    }
     render() {
        let {is_checked,value} = this.state;
        return (
            <label>
                    <input value={value} type="checkbox" onClick={this.checkCheckBox}
                    checked={is_checked}/>

                    {this.props.children !== undefined ? this.props.children : null}
            </label>
        )
    }}复制代码

这样,我们的Checkbox 组件就是受控的了,也就是说它的选中状态是与父组件传下来的checked 属性相关连的,现在在次点击按钮,发现无论怎么点也选不上了。

stap5:

我们的Checkbox 组件一般都不会单独的加载,尤其是在选择项很多的业务场景中,checkbox 组件都是分组出现的,我们希望在点击的时候能在父组件拿到选中的Checkbox 的数组,并且改变checkbox 的选中状态。

首先我们再在components 文件夹下面创建一个CheckboxGroup文件夹,同样在下面新建CheckboxGroup.js 。首先贴出来代码,然后再来分析

import React from "react"
import "./CheckboxGroup.less"
import PropTypes from 'prop-types';
class CheckboxGroup extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            value: props.value || props.defaultValue || [],
        };
        this.toggleOption = this.toggleOption.bind(this);
    }
    componentWillReceiveProps(nextProps) {
        if ('value' in nextProps) {
            this.setState({
                value: nextProps.value || [],
            });
        }
    }
    getChildContext() {
        return {
            checkboxGroup: { 
               toggleOption: this.toggleOption,
                value: this.state.value,
            },
        };
    }
    toggleOption(option) {
        const optionIndex = this.state.value.indexOf(option.value);
        const value = [...this.state.value];
        if (optionIndex === -1) {
            value.push(option.value);
        } else {
            value.splice(optionIndex, 1);
        }
        if (!('value' in this.props)) { 
           this.setState({value});
        }
        const onChange = this.props.onChange; 
       if (onChange) {
            onChange(value);
        }
    }
    render() {
        const {children, className} = this.props
        return (
            <div className={className}>
                {children}
            </div>
        )
    }}
CheckboxGroup.childContextTypes = {    checkboxGroup: PropTypes.any,};export default CheckboxGroup复制代码

代码分析:从render 开始看

render() {
        const {children, className} = this.props
        return (
            <div className={className}> 
               {children}
            </div>
        )
    }复制代码

这段代码很熟悉,和上面的Checkbox组件一样,会加载组件包裹的元素,也就是说,CheckboxGroup 组件包裹了Checkbox,那是怎样接管Checkbox的状态的呢?

getChildContext() {
        return {
            checkboxGroup: {
                toggleOption: this.toggleOption,
                value: this.state.value,
            },
        };
    }复制代码

getChildContext可以传递给自组件属性,需要主意的是,getChildContext 指定的传递给子组件的属性需要先通过 childContextTypes 来指定,不然会产生错误。

CheckboxGroup.childContextTypes = {
    checkboxGroup: PropTypes.any,
};复制代码

然后他会getChildContent中返回子组件需要的属性,同时在componentWillReceiveProps 生命周期中监听props 的改变从而更新CheckBox 的 选中状态。

同时,CheckBox.js 里面也要做相应的修改

import React from "react"
import "./CheckBox.less"
import PropTypes from 'prop-types';
import CheckboxGroup from '../CheckboxGroup/CheckboxGroup.js'
class CheckBox extends React.Component {
    constructor(props) {
        super(props)
        this.checkCheckBox = this.checkCheckBox.bind(this);
        this.state = {
            is_checked: props.checked || false,
            value: props.value || ''
        }
    }
    checkCheckBox() {
        const {checkboxGroup} = this.context;
        if (checkboxGroup) {
            checkboxGroup.toggleOption({label: this.props.children, value: this.props.value})
        } else {
            const onChange = this.props.onChange;
            const value = this.props.value;
            if (onChange) {
                onChange(value);
            }
        }
    }
    render() {
        let {is_checked, value} = this.state;
        const {checkboxGroup} = this.context;
        if (checkboxGroup) {
            is_checked = checkboxGroup.value.indexOf(this.props.value) !== -1;
        } 
       return (
            <label> 
                    <input value={value} type="checkbox"  checked={is_checked}
                           onClick={this.checkCheckBox}/>
             {this.props.children !== undefined ? this.props.children : null} 
            </label>
        )
    }}
CheckBox.Group = CheckboxGroup;
CheckBox.contextTypes = {
    checkboxGroup: PropTypes.any,
}export default  CheckBox;
复制代码

这样,在点击的时候会先判断 this.context 中是否有 checkboxGroup属性,如果有,就调用checkboxGroup属性 中的toggleOption方法,并把当前的value 传上去,由 CheckboxGroup组件去控制,同时在渲染的时候也会判断,从而决定选中状态是由谁来决定。然后去App.js 中引用。

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import CheckBox from './compoents/CheckBox/CheckBox'
const CheckboxGroup = CheckBox.Group;
class App extends Component {
  state={
    checkList:[]
  }
  selectCheckBtn=(values)=>{
    console.log(values)
    this.setState({
      checkList:values
    })
  }
    render() {
    const {checkList} = this.state
    return (
      <div className="App">
        <header className="App-header"> 
         <img src={logo} className="App-logo" alt="logo" />  
         <h1 className="App-title">Welcome to React</h1>
        </header> 
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <CheckboxGroup value={checkList} onChange={this.selectCheckBtn}> 
          <CheckBox value={'1'}>按钮1</CheckBox>
          <CheckBox value={'2'}>按钮2</CheckBox>
          <CheckBox value={'3'}>按钮3</CheckBox>
          <CheckBox value={'4'}>按钮4</CheckBox>
        </CheckboxGroup>
      </div>
    );
  }}
export default App;
复制代码

最后,打开控制台,点击按钮。


这里,我们便完成了一个简单的checkBox 组件。


总结

写一个组件很容易,但是写好一个组件就不是那么容易的事了,React 也有一些现在比较成熟的UI组件库,比如蚂蚁金服的Antd Design,可以打开看看里面的源码。学习下他们的设计思想。


转载于:https://juejin.im/post/5a9a30f1518825556533f0b9

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值