React学习笔记3-漫谈React

2020-06-06  本文已影响0人  波拉拉
这篇七个点:1 事件系统 2 表单 3 样式处理 4 组件间通信 5 组件抽象 6 性能优化 7 动画 8 自动化测试

2.1 事件系统

2.1.1 合成事件的绑定方式

为按钮添加点击事件

render(){
        return (
            <div>
                <button onClick={this.handleClick}>测试</button>
            </div>
        )
    }

注意点使用驼峰书写事件属性名(onClick),{}内可以是任意的值。

2.1.2 合成事件的实现机制
class Event extends Component{
    constructor(props){
        super(props);this.state={
            name:"bolala"
        };
    }
    handleClick() {
        console.log(this.state.name);
    };
    render(){
        return (
            <div>
                <button onClick = {::this.handleClick}>测试2</button>
            </div>
        )
    }
}

方法二:构造器声明
这种方式的好处在于仅需要绑定一次。

class Event extends Component{
    constructor(props){
        super(props);this.state={
            name:"bolala"
        };
        this.handleClick=this.handleClick.bind(this);
    }
    handleClick() {
        console.log(this.state.name);
    };
    render(){
        return (
            <div>
                <button onClick = {this.handleClick}>测试2</button>
            </div>
        )
    }
}

方法三:箭头函数
使用箭头函数会自动绑定定义次函数作用域的this,因此就不需要再绑定了。

class Event extends Component{
    constructor(props){
        super(props);this.state={
            name:"bolala"
        };
    }

    handleClick=()=>{
        console.log(this.state.name);

    };
    render(){
        return (
            <div>
                <button onClick = {this.handleClick}>测试2</button>
            </div>
        )
    }
}

或者

class Event extends Component{
    constructor(props){
        super(props);this.state={
            name:"bolala"
        };
    }

    handleClick(){
        console.log(this.state.name);
    }
    render(){
        return (
            <div>
                <button onClick = {()=>this.handleClick()}>测试2</button>
            </div>
        )
    }
}
2.1.3 在React中使用原生事件

可以componentDidMount中用refs实现原生事件。也要记得componentWillUnmount中手动移除。

class Event extends Component{
    constructor(props){
        super(props);this.state={
            name:"bolala"
        };
    }
    render(){
        return (
            <div>
                <button
                    onClick = {()=>this.handleClick()}
                    ref="button"
                >
                    测试2
                </button>
            </div>
        )
    }
    componentDidMount(){
        this.refs.button.addEventListener('click',()=>{
            this.handleClick();
        },false)
    }
    handleClick(){
        console.log(this.state.name);
    }
    componentWillUnmount(){
        this.refs.button.removeEventListener('click');
    }
}
2.1.3React合成事件与js原生事件的对比
 <button onClick = {()=>this.handleClick()}>测试2 </button>

2.2 表单

2.2.1应用表单组件
class Textbox extends  Component {
    constructor(props) {
        super(props);
        this.inputChange=this.inputChange.bind(this);
        this.textChange=this.textChange.bind(this);
        this.state = {
            inputValue:"",
            textValue:""
        };
    }
    inputChange(e){
        this.setState({inputValue:e.target.value})
    }
    textChange(e){
        this.setState({textValue:e.target.value})
    }
    render(){
        return(
            <div>
                <input type="text" onChange={this.inputChange} value={this.state.inputValue}/>
                <textarea  onChange={this.textChange} value={this.state.textValue}/>
            </div>
        )
    }
}
class Radio extends Component{
    constructor(props){
        super(props);
        this.state={radioValue:""};
        this.handleChange= this.handleChange.bind(this);
    }
    handleChange(e){
        this.setState({
            radioValue:e.target.value
        })
    }
    render(){
        return (
            <div>
                <label htmlFor="male">男:</label>
                <input type="radio" name="sex" value="male" id="male"
                       checked={this.state.radioValue==="male"}
                       onChange={this.handleChange}/>
                <label htmlFor="female">女:</label>
                <input type="radio" name="sex" value="female" id="female"
                       checked={this.state.radioValue==="female"}
                       onChange={this.handleChange}/>
            </div>
        )
    }
}

复选框略
一个选项

class Select extends Component{
    constructor(props){
        super(props);
        this.state={area:""};
        this.handleChange= this.handleChange.bind(this);
    }
    handleChange(e){
        this.setState({
            area:e.target.value
        })
    }
    render(){
        return (
            <div>
               <select value={this.state.area} onChange={this.handleChange}>
                   <option value="beijng">北京</option>
                   <option value="shanghai">上海</option>
                   <option value="hangzhou">杭州</option>
               </select>
            </div>
        )
    }
}

多个选项

class Select extends Component {
    constructor(props) {
        super(props);
        this.state = {area: []};
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(e) {
        var newArea=[];
        console.log(e.target.options);
        for (let i=0;i<e.target.options.length;i++){
            if (e.target.options[i].selected){
                newArea.push(e.target.options[i]);
            }
        } 
        this.setState({
            area: newArea
        })
    }

    render() {
        return (
            <select multiple={true} onChange={this.handleChange}>
                <option value="beijng">北京</option>
                <option value="shanghai">上海</option>
                <option value="hangzhou">杭州</option>
            </select>
        )
    }
}
2.2.2 受控组件

每当表单的状态发生变化,都会被写入组件的state中,这种组件被称为受控组件,通过这种方式消除了组件的局部状态,让整个状态更加可控。
React受控组件更新state的流程:

 inputChange(e) {
        this.setState({inputValue: e.target.value.toUpperCase()})
    }
2.2.3 非受控组件

如果一个表单组件没有value/checked时就可以称为非受控组件,可以使用defaultValue和defaultChecked表示组件的默认状态。

class Textbox extends Component {
    constructor(props) {
        super(props);
        this.button=this.button.bind(this);
        this.state = {};
    }
    button(){
        console.log(this.refs.name);
    }
    render() {
        return (
            <div>
                <input ref="name"  type="text"  defaultValue="bolala"/>
                <button onClick={this.button}>显示</button>
            </div>
        )
    }
}
//始终显示<input type="text" value="bolala">
2.2.4 对比受控组件和非受控组件

非受控组件的状态不会受应用状态的控制应用中也多了局部组件状态,而受控组件的值来自于组件的state。

2.2.5 表单组件几个重要属性

1 状态属性:

2 事件属性:
React一般用onChange事件,同时也支持DOM3中定义的所有表单事件。

2.3 样式处理

2.3.1 基本样式设置
class BasicCss extends Component{
    constructor(props){
        super(props);
        this.state = {};
    }
    render(){
        var css={
            box:{background:'blue',color:"white"}
        };
        return (
            <div>
                <div style={{border:'1px solid red'}}>haha</div>
                <h1 style={css.box}>BOLALA</h1>
            </div>
        )
    }
}

使用classnames库
当要使用多个class时,官方推荐使用这个库。

class ClassNames extends  Component {
    constructor(props){
        super(props);
        this.state={isPressed:false,isHovered:true};
    }

    render(){
        var classNames = require('classnames');
        return(
            <div>
                <h1 className={classNames({btn:true,bolala:true})}>ha</h1>
                <h2 className={classNames({
                    "btn":true,
                    "btn-pressed":this.state.isPressed,
                    "btn-over":!this.state.isPressed&&this.state.isHovered
                })}>
                    bhbh</h2>
            </div>
        )
    }
}
2.3.2 CSS Modules

https://segmentfault.com/q/1010000018891784
https://www.cnblogs.com/suihang/p/10417755.html
http://www.ruanyifeng.com/blog/2016/06/css_modules.html
略。以后如果遇到,看最后一个链接,讲得清楚又简单。

2.4 组件间通信

2.4.1 父组件向子组件通信

在React中,数据流是单向的,通过props从父节点传递到子节点,如果props发生改变,会遍历整个组件树,从而渲染用到这个props的所有组件。

class Child extends Component{
    constructor(props){
        super(props);
        this.state={};
    }
    render(){
        return(
            <h1>{this.props.text}</h1>

        )
    }
}
class Transmit extends Component{
    constructor(props){
        super(props);
        this.state={};
        this.handleClick=this.handleClick.bind(this);
    }
    handleClick(){
        this.setState({
            text:"传入props"
        })
    }
    render(){
        return(
            <div>
                <Child text={this.state.text||"没有传入值"}/>
                <button onClick={this.handleClick}>改变</button>
            </div>
        )
    }
}
2.4.2 子组件向父组件通信

子组件更新父组件,需要父组件传一个回调函数给子组件,然后子组件调用,就可以出发父组件更新了。

class Transmit3 extends Component{
    constructor(props){
        super(props);
        this.state={};
    }
    handleClick(){
        this.setState({
            text:"传入参数"
        })
    }
    render(){
        return(
            <div>
                <h1>{this.state.text||"未传参数"}</h1>
                <Child handleClick={this.handleClick.bind(this)}/>
            </div>
        )
    }
}
class Child extends Component{
    constructor(props){
        super(props);
    }
    render(){
        return(
            <button onClick={this.props.handleClick}>改变</button>
        )
    }
}
2.4.3 跨级组件通信
class Transmit1 extends Component{
    constructor(props){
        super(props);
        this.state={};
    }
    handleClick(){
        this.setState({
            text:"传入新值"
        })
    }
    render(){
        return(
            <div>
                <Child1 text={this.state.text||"没有传值"}/>
                <Child2 handleClick={this.handleClick.bind(this)}/>
            </div>
        )
    }
}
class Child1 extends Component{
    constructor(props){
        super(props)
    }
    render(){
        return(
            <h1>{this.props.text}</h1>
        )
    }
}
class Child2 extends Component{
    constructor(props){
        super(props)
    }
    render(){
        return(
            <button onClick={this.props.handleClick}>改变</button>
        )
    }
}
2.4 4 没有嵌套关系的组件通信

2.5 组件间抽象

2.6 组件性能优化

2.6.1 纯函数

三大原则:

2.6.2 PureRender
2.6.3 Immutable
2.6.4 key
class KeyWorld extends Component{
    constructor(props){
        super(props);
        this.state={
            list:[{id:1,name:"bolala"},{id:2,name:"bolala2"},{id:3,name:"bolala3"}]
        }
    }
    render(){
        return(
            <ul>
                {this.state.list.map((value,index)=>(
                    <li key={value.id}>{value.name}</li>
                ))}
            </ul>
        )
    }
}

原则:key值要独一无二,并且能不用遍历或随机值就不用,除非列表内容也并不是唯一的标识,且没有可以相匹配的属性。

2.6.5 react-addons-perf

是为了量化性能优化的效果的官方提供的插件。

2.7 动画

https://blog.csdn.net/sd19871122/article/details/98624902

class Progress extends Component {
    constructor(props) {
        super(props);
        this.state = {percent:10}
    }
    increase=()=>{
        const percent=this.state.percent;
        const target=(percent>=90)?100:(percent+10);
        const speed=(target-percent)/100;
        let start=null;
        const animate=(timestamp)=>{
            if (!start) start = timestamp;
            const progress = timestamp - start;
            const currentProgress=parseInt(speed * progress + percent, 10);
            this.setState({percent:currentProgress});
            if (currentProgress<target){
                window.requestAnimationFrame(animate);
            }
        };
        window.requestAnimationFrame(animate);
    };
    decrease=()=>{
        const percent=this.state.percent;
        const target=(percent<=10)?0:(percent-10);
        const speed=(target-percent)/400;
        let start=null;
        const animate=(timestamp)=>{
            if (!start) start = timestamp;
            const progress = timestamp - start;
            const currentProgress=parseInt(speed * progress + percent, 10);
            this.setState({percent:currentProgress});
            if (currentProgress>target){
                window.requestAnimationFrame(animate);
            }
        };
        window.requestAnimationFrame(animate);
    };
    render() {
        return (
            <div style={{width:"600px"}}>
                <div className="progress">
                    <div className="wrap" style={{background:"#ededed",borderRadius:"10px"}}>
                        <div className="inner" style={{width:`${this.state.percent}%`,background:"rgba(255, 0, 0, 0.6)",height:'10px',borderRadius:"10px"}}></div>
                    </div>
                </div>
                <span>{`${this.state.percent}%`}</span>
                <div className="btns">
                    <button onClick={this.decrease}>-</button>
                    <button onClick={this.increase}>+</button>
                </div>
            </div>
        )

    }
}
import './index.css';
class Css3 extends Component {
    constructor(props) {
        super(props);
        this.state = {show:true};
        this.handleClick=this.handleClick.bind(this);
    }
    handleClick(){
        this.setState({
            show:!this.state.show
        })
    }
    render() {
        return (
            <div>
                <div className={this.state.show ? "show" : "hide"}>Hello</div>
                <button onClick={this.handleClick}>切换</button>
            </div>
        );

    }
}

.show{
    animation:show-item 1s ease-in ;
}
.hide{
    animation:hide-item 1s ease-in ;

}
@keyframes show-item {
    0%{
        opacity: 0;
        color: red;
    }
    100%{
        opacity: 1;
        color: blue;
    }
}
@keyframes hide-item {
    0%{
        opacity: 1;
        color: red;
    }
    100%{
        opacity: 0;
        color: blue;
    }
}

https://www.jianshu.com/p/a38439337058
https://blog.csdn.net/Sophie_U/article/details/80093876?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

2.8 自动化测试

2.8.1 Jest
2.8.2 Enzyme
2.8.3 自动化测试
上一篇下一篇

猜你喜欢

热点阅读