React进阶练习-JSX踩坑、组件拆分、父子组件传、单向数据流与函数式编程

JSX防踩坑

JSX代码注释

这样写注释是错误的,如果放在Fragment标签外面还算正常,放在里面就不是注释


// 这样写注释是错误的

JSX的注释,有两种写法

{/* 正确注释的写法 */}
增加服务
```

如果记不住,直接VSCode快捷键,Ctrl + /

可以这样理解,在jsx中写JavaScript代码,因此外面套入了{}

然后里边就是一个多行的JavaScript注释

如果要使用单行注释,需要使用第二种写法

  • 
      {
          //正确注释的写法 
      }
      

就是需要进行换行,有些麻烦而且不优雅,推荐第一种注释方法

JSX class陷阱

要添加样式,比如给文本框添加一个粗黄的边框,错误的步骤

  1. 先写一个CSS样式文件,在src目录下,新建一个style.css样式文件

.input {border: 3px solid #ae7000;}

  1. Xiaojiejie.js里引入,先用import进行引入,能用import引入,都是webpack的功劳

import './style.css'

  1. JSX加入class,这是错误的写法

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

index.js:1 Warning: Invalid DOM property `class`. Did you mean `className`?
    at input
    at div
    at Xiaojiejie (http://localhost:3000/main.39b7f7cef4fa3aada48a.hot-update.js:51:5)

意思是要把class换成className,它是防止和js中的class类名冲突,因此要求换掉

JSX html解析

如果想在文本框里输入一个

标签,并进行渲染

默认是不会生效的,只会把

标签打印到页面上

如果项目中有这种需求,可以使用dangerouslySetInnerHtml属性来解决

    { this.state.list.map((item,index)=>{ return (
  • ) }) }

JSX 标签

label是HTML中一个辅助标签
我们在文本框前面加入一个

 

这时我们想点击"加入服务"直接可以激活文本框,方便输入

按照html原本的思路,直接加个ID就可以

这时浏览器效果虽然正常,但是控制台里会有Warning警告

Warning: Invalid DOM property `for`. Did you mean `htmlFor`?
    at label
    at div
    at Xiaojiejie (http://localhost:3000/static/js/main.chunk.js:193:5)

意思是不能使用for,它容易和JavaScript里的for循环混淆,会提示你使用htmlfor
这时候就能实现点击后,激活标签了

Simple React Snippets

工作中经常会看到程序老司机写代码是非常快的,他们使用了vscode中快速生成插件-Simple React Snippets

新建一个test.js来体验下代码快手

快速引入import

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

import React, { Component } from 'react';

快速生成class

在写组件的时候,都需要写一个固定的基本格式

直接输入cc,就会快速生成如下代码

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

还有很多快捷键,可以再插件里的说明文件中查看

这个插件建议熟练掌握,因为在老板眼里,代码编写速度的快慢直接跟我们的薪资有关,就算没什么关系,我们自己把时间剩下,去玩4399不香吗?

Component 组件的拆分

现在小姐姐服务菜单已经制作好了,但从头到尾只用了一个组件

在实际工作中肯定是团队开发,我们会把一个大功能分成不同的组件,

  • 比如把文本框和按钮单独一个组件
  • 把下面的服务列表单独一个组件

这就涉及了组件拆分的能力和知识

新建服务菜单组件

在src目录下,新建一个文件,XiaojiejieItem.js

然后先把最基础的结构写好,使用imrc cc快捷键生成

import React, { Component } from 'react';

class XiaojiejieItem extends Component {
    render() { 
        return (  
            
小姐姐
); } } export default XiaojiejieItem;

写好后,就可以在Xiaojiejie.js文件中用import进行引入
import XiaojiejieItem from './XiaojiejieItem'

修改Xiaojiejie组件

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

  • 先把原来的代码注释掉,或者删除掉

  • 然后再最外层加入包裹元素

    ,为了防止两个以上的标签,产生错误信息

  • 最后直接写入

现阶段整体Code

import React, { Component, Fragment } from 'react';
import XiaojiejieItem from './XiaojiejieItem';
import './style.css'
class Xiaojiejie extends Component {
    // js的构造函数,由其他任何函数执行
    constructor(props) {
        super(props) // 调用父类的构造函数,固定写法
        this.state = {
            inputValue: '', // input中的值
            list:['基础按摩','精油推背']  // 服务列表
        }
    }
    render() {
        return (
            
            
                  {/* js的构造函数,由其他任何函数执行 */}
                
    { this.state.list.map((item,index)=>{ return ( //
  • //
  • ) }) }
) } inputChange(e){ // console.log(e.target.value); // this.state.inputValue = e.target.value this.setState({ inputValue:e.target.value }) } // 增加服务的按钮响应方法 addList(){ this.setState({ list:[...this.state.list,this.state.inputValue], inputValue:'' }) } // 删除单项服务 deleteItem(index){ console.log(index) let list = this.state.list list.splice(index,1) this.setState({ list:list }) } } export default Xiaojiejie

现在已经把组件进行了拆分,但还没有实现传值

父子组件的传值

上面我们把组件做了一个基本的拆分

但还是不能实现随着输入,显示输入得内容,这涉及到父组件向子组件传值

然后点击删除,相当于子组件向父组件传值

父组件向子组件传值

我们使用组件属性的形式,实现父组件给子组件传值

现在,Xiaojiejie是父组件,XiaojiejieItem是子组件

我们在XiaojiejieItem组件中加入content属性,然后给属性传递{item},这样就完成了父组件向子组件传值

 return (                                
      
      //关键代码-------------------end
                                      
)

现在值已经传递过去了,接下来通过this.props.xxx的形式进行接收

import React, { Component } from 'react';

class XiaojiejieItem extends Component {
    render() { 
        return (  
            
{this.props.content}
); } } export default XiaojiejieItem;

父组件向子组件传递内容,靠属性的形式传递

子组件向父组件传递数据

要实现点击组件中的菜单项,删除菜单项,这里就涉及了子组件向父组件传递数据

首先绑定点击事件,这时候当然是在XiaojiejieItem组件中绑定了

import React, { Component } from 'react';

class XiaojiejieItem extends Component {
    render() { 
        return (  
            
{this.props.content}
); } handleClick(){ console.log('哈哈哈') } } export default XiaojiejieItem;

打开F12进行预览,会发现console里显示了"哈哈哈"字样

但console里还有一个warning警告,这是要求循环时必须设置key值,我们需要修改Xiaojiejie组件的render代码

    { this.state.list.map((item,index)=>{ return (
    ) }) }

组件外还有层div,还会有warning警告,去掉外面的div

    { this.state.list.map((item,index)=>{ return ( ) }) }

绑定成功后,就要通过操作子组件删除父组件里的数据了

但React有明确规定,子组件不能操作父组件里的数据

所以要借助父组件的方法,来修改父组件的内容

  • 就是子组件调用之前在父组件中写的deleteItem删除方法

获取数组索引下标

要删除就要知道索引值

所以还是需要通过父组件传递给子组件,还是通过props属性的形式进行传递

this.state.list.map((item,index)=>{
    return (                                
                                            
    )
})

然后修改XiaojiejieItem组件中的handleClick方法

handleClick(){
    // console.log('哈哈哈')
    console.log(this.props.index)
}

这时预览点击后会报错
TypeError: Cannot read property 'props' of undefined

这个错误是之前的老朋友,没有绑定bind(this)

我们可以用之前的老方法绑定this

return (  
    
{this.props.content}
);

还有一种方法,是在构造函数里绑定(构造函数中绑定性能会高一些,特别是在高级组件开发中,会有很大的作用)

constructor绑定this方法

import React, { Component } from 'react'; //imrc

class XiaojiejieItem extends Component { //cc
    //--------------主要代码--------start
    constructor(props){
        super(props)
        this.handleClick=this.handleClick.bind(this)
    }
    //--------------主要代码--------end
    render() { 
        return (  
            
{this.props.content}
); } handleClick(){ console.log(this.props.index) } } export default XiaojiejieItem;

子组件调用父组件方法

子组件要调用父组件方法,和传递数据差不多

只要在组件调用时,把方法传递给子组件就可以了

  • 这里也要进行this绑定,如果不绑定子组件是没办法找到这个父组件的方法的
return (                                
                               
)

传递后,在XiaojiejieItem组件里直接使用就行

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

到此为止,我们就算实现了子组件向父组件传值

这是React体系中非常重要的,真正的React开发工作,每天写的就是各种组件,传值是组件之间产生联系的必要一环!

单向数据流与函数式编程

单向数据流

React的特性中有个概念叫“单项数据流”

依旧使用服务菜单的Demo,我们在父组件中可以直接把this.state.list传递过来

return (                                
                                    
)

父组件给子组件这样传值是没有问题的,但子组件只能使用这个值,而不能修改这个值

如果修改了,在子组件里这样写

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

就会报错TypeError: Cannot assign to read only property 'list' of object '#'

意思是list是只读的,单向数据流
如果要改变这里面的值,就是通过传递父组件的方法

和其他框架配合使用

ReactJquery也能一起使用

React可以模块化和组件化开发,在/public/index.html中我们可以看到

DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
	
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

    <title>Leon zhaotitle>
  head>
  <body>
    <noscript>You need to enable JavaScript to run this app.noscript>
    
    <div id="root">div>
    
  
  body>
html>

React只针对这一个

,外部的其他DOM并不受任何影响,我们在它的下方再写一个

今天过的好开心,服务很满意!

我们可以在其他的div里加入任何内容,但是这种情况很少,希望大家还是统一技术栈

函数式编程

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

  1. 函数式编程让我们的代码更清晰,每个功能都是一个函数
  2. 函数式编程为我们的代码测试代理了极大的方便,更容易实现前端自动化测试

React框架也是函数式编程,优势在大型多人开发的项目中会更加明显,让配合和交流都得心应手

你可能感兴趣的:(React,javascript,react)