React进阶(四)

一. JSX防踩坑的几个地方

1.1 JSX代码注释

JSX中的代码注释是非常有讲究的,这个书上介绍的也非常少。

我第一次写JSX注释,是直接这样写的,当然这样写是完全不对的。

<Fragment>
    //第一次写注释,这个是错误的
    <div>
        <input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
        <button onClick={this.addList.bind(this)}> 增加服务 </button>
    </div>
</Fragment>

那写JSX的注释,可以有下面两种写法:

<Fragment>
    {/* 正确注释的写法 */}
    <div>
        <input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
        <button onClick={this.addList.bind(this)}> 增加服务 </button>
    </div>
</Fragment>

你可以把这个理解为,在jsx中写javascript代码。所以外出我们套入了{},然后里边就是一个多行的javascript注释。

如果你要使用单行注释//,你需要把代码写成下面这样。


<Fragment>
    {
        //正确注释的写法 
    }
    <div>
        <input value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
        <button onClick={this.addList.bind(this)}> 增加服务 </button>
    </div>
</Fragment>

也就是你要进行换行,所以个人认为这种方法不太优雅,所以推荐第一种注释方法。

1.2 JSX中的class陷阱

比如要给朴素单纯的界面,加入黄色成分,让我们的文本框又粗又黄。我们先来错误演示。

第一步:先写一个CSS样式文件,在src目录下,新建一个style.css的样式文件。

.input {border:3px solid #ae7000}

第二步:在Xiaojiejie.js里引入,先用import进行引入,能用import引入,都是webpack的功劳。

import './style.css'

第三部:给JSX加入`class,注意下面的代码是错误的。

<input class="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />

虽然现在页面是可以正常显示结果的,但是你代开浏览器控制台会发现Warning警告。

index.js:1437 Warning: Invalid DOM property `class`. Did you mean `className`?
    in input (at Xiaojiejie.js:19)
    in div (at Xiaojiejie.js:18)
    in Xiaojiejie (at src/index.js:5)

意思就是要把class换成className,它是防止和js中的class类名 冲突,所以要求换掉。这也算是一个小坑吧。

1.3 JSX中的html解析问题

如果想在文本框里输入一个<h1>标签,并进行渲染。默认是不会生效的,只会把<h1>标签打印到页面上,这并不是我想要的。如果工作中有这种需求,可以使用dangerouslySetInnerHTML属性解决。具体代码如下:

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <li 
                    key={index+item}
                    onClick={this.deleteItem.bind(this,index)}
                    dangerouslySetInnerHTML={{__html:item}}
                >
                </li>
            )
        })
    }
</ul> 

上面的代码就可以实现html格式的输出。

1.4 JSX中for陷阱

JSX中<label>的坑,也算是比较大的一个坑,label是html中的一个辅助标签,也是非常有用的一个标签。

先看下面的代码,我们在文本框前面加入一个<label>。

<div>
    <label>加入服务:</label>
    <input className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
    <button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>

这时候想点击“加入服务”直接可以激活文本框,方便输入。按照html的原思想,是直接加ID就可以了。代码如下:

<div>
    <label for="jspang">加入服务:</label>
    <input id="jspang" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
    <button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>

这时候你浏览效果虽然可以正常,但console里还是有红色警告提示的。大概意思是不能使用for。它容易和javascript里的for循环混淆,会提示你使用htmlFor。

<div>
    <label htmlFor="jspang">加入服务:</label>
    <input id="jspang" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
    <button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>

这时候代码就正确了,可以实现点击<label>后,激活<input>标签了。

二. 关于React中的代码快速生成插件 Simple React Snippets

2.1 安装Simple React Snippets

打开VSCode的插件查单,然后在输入框中输入Simple React Snippets,然后点击进行安装就可以了。

2.2 快速导入文件

直接在vscode中输入imrc,就会快速生成最常用的import代码。

import React, { Component } from 'react';
2.3 快速生成class

在写组件的时候,都需要写一个固定的基本格式,这时候你就可以使用快捷键cc。插件就会快速帮我们生成如下代码:

class  extends Component {
    state = {  }
    render() { 
        return (  );
    }
}
 
export default ;

当然,还有很多快捷键,我就没必要再这里唠叨了,如果你需要理解,打开插件的说明文件看一下就可以了。这个插件建议小伙伴们要熟练掌握。
在这里插入图片描述

三. 组件的拆分

3.1 新建服务菜单组件

在src目录下,新建一个文件,这里就叫做XiaojiejieItem.js,然后先把最基础的结构写好。

import React, { Component } from 'react'; //imrc
class XiaojiejieItem  extends Component { //cc
   
    render() { 
        return ( 
            <li>小姐姐</li>
         );
    }
}
export default XiaojiejieItem;

写好这些代码后,就可以到以前写的Xiaojiejie.js文件中用import进行引入,代码如下:

import XiaojijieItem from './XiaojiejiItem'
3.2 修改Xiaojiejie组件

已经引入了新写的组件,这时候原来的代码要如何修改才能把新组件加入?

把原来的代码注释掉,当然你也可以删除掉,我这里就注释掉了,注释方法如下:

{/*
<li 
    key={index+item}
    onClick={this.deleteItem.bind(this,index)}
    dangerouslySetInnerHTML={{__html:item}}
>

</li>
*/ }

然后替换掉就OK了。

四. 组件间传值

4.1 父组件向子组件传值

我们可以通过使用组件属性的形式来让父组件向子组件传值。比如:我们在<XiaojiejieItem>组件中加入content属性,然后给属性传递{item}内容,这样就完成了父组件向子组件传值。

<XiaojiejieItem content={item} />

现在值已经顺利的传递了过去,这时候可以通过this.props.xxx的形式进行接受,比如传递过来的值,可以用如下代码进行接收。

import React, { Component } from 'react'; //imrc
class XiaojiejieItem  extends Component { //cc
   
    render() { 
        return ( 
            <div>{this.props.content}</div>
         );
    }
}
 
export default XiaojiejieItem;

学到这里你要记住一点:父组件向子组件传递内容,靠属性的形式传递。

4.2 子组件向父组件传递数据

现在要做这样一个功能:点击组件中的菜单项后,删除菜单项。在前已经实现了这个功能,只是现在组件拆分了,就涉及了一个子组件向父组件传递数据的知识需要掌握。

先来绑定点击事件,这时候当然是要在XiaojiejieItem组件中绑定了,代码如下:

class XiaojiejieItem extends React.Component {
    render() { 
        return (
            <li onClick={this.handleClick.bind(this)}>{this.props.content}</li>
        );
    }
    handleClick() {
        console.log(this.props.index)
    }
}
 
export default XiaojiejieIte

其实这里对于this的绑定有一个优化,就是最好在构造函数中去绑定,而不是像上面的代码那样,具体原因还不知道

有言曰:构造函数中绑定性能会高一些,特别是在高级组件开发中,会有很大的作用

import React from 'react';
class XiaojiejieItem extends React.Component {
    constructor(props) {
        super(props)
        this.handleClick = this.handleClick.bind(this)

    }
    render() { 
        return (
            <li onClick={this.handleClick}>{this.props.content}</li>
        );
    }
    handleClick() {
        console.log(this.props.index)
    }
}
 
export default XiaojiejieItem

现在就要通过操作子组件来删除父组件里的数据了。但是React有明确规定,子组件是不能操作父组件里的数据的,所以需要借助一个父组件的方法,来修改父组件的内容。其实在以前已经写了一个删除方法deleteItem,现在要做的就是子组件调用这个方法。

//删除单项服务
deleteItem(index){
    let list = this.state.list
    list.splice(index,1)
    this.setState({
        list:list
    })
}

获取数组索引下标:

那现在问题来了,要删除就要知道索引值,还是需要通过父组件传递给子组件。这里还是通过props属性的形式进行传递。

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <XiaojiejieItem 
                key={index+item}  
                content={item}
                index={index} />
            )
        })
    }
</ul>  

然后修改XiaojiejieItem组件,在handleClick方法里,写入下面代码:

handleClick(){
    console.log(this.props.index)
}

在获取到索引后,就可以通过在子组件里调用父组件的方法来实现删除某一项了。

子组件调用父组件方法:
如果子组件要调用父组件方法,其实和传递数据差不多,只要在组件调用时,把方法传递给子组件就可以了,记得这里也要进行this的绑定,如果不绑定子组件是没办法找到这个父组件的方法的。

<ul>
      {
          this.state.list.map((item,index) => {
              return (
                  <XiaojiejieItem 
                  key={index} 
                  content={item} 
                  index={index}
                  delItem={this.delItem.bind(this)}
                  >
                  </XiaojiejieItem>
                  // <li key={index}
                  //     onClick={this.delItem.bind(this, index)}>
                  //     {item}
                  // </li>
              )
          })
      }
</ul>

五. 单项数据流和其他

5.1 单项数据流

React的特性中有一个概念叫做“单项数据流”,可能刚刚接触React的小伙伴不太明白这个概念,还是拿出《小姐姐服务菜单》的Demo,来给大家讲解。比如我们在父组件中可以直接把this.state.list传递过来。例如下面代码:

<ul>
    {
        this.state.list.map((item,index)=>{
            return (
                <XiaojiejieItem 
                key={index+item}  
                content={item}
                index={index}
                list={this.state.list}
                deleteItem={this.deleteItem.bind(this)}
                />
            )
        })
    }
</ul> 

其实这样传是没有问题的,问题是你只能使用这个值,而不能修改这个值,如果你修改了,比如我们把代码写成这样:

handleClick(){
    //关键代码——---------start
    this.props.list=[]
    //关键代码-----------end
    this.props.deleteItem(this.props.index)
}

就会报下面的错误:

TypeError: Cannot assign to read only property 'list' of object '#<Object>'

意思就是list是只读的,即单项数据流。那如果要改变这里边的值怎么办?我们可以通过向子组件传递父组件的方法。

5.2 和其他框架配合使用

有小伙伴问我,React和jquery能一起使用吗?

答案:是可以的,React其实可以模块化和组件化开发。看/public/index.html文件,代码如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
   
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <!--关键代码start-->
    <div id="root"></div>
     <!--关键代码end-->
   
  </body>
</html>

其实React只对这一个<div>,外边的其他DOM并不受任何影响,比如我们在它的下方再写一个<div>,然后查看效果。

<div id="root"></div>
<div style="color:red">今天过的好开心!</div>

你可以在其他的div里加入任何内容,但是这种情况很少,我也不建议这么使用。希望小伙伴们还是统一技术栈。

5.3 函数式编程

在面试React时,经常会问道的一个问题是:函数式编程的好处是什么?

  • 函数式编程让我们的代码更清晰,每个功能都是一个函数。
  • 函数式编程为我们的代码测试带来了极大的方便,更容易实现前端自动化测试。
  • React框架也是函数式编程,所以说优势在大型多人开发的项目中会更加明显,让配合和交流都得心应手。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

. . . . .

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值