联系作者
联系作者

# 2.1 搭建React环境

安装nodejs+vscode,用nvm去管理node版本

# 2.1.1 create-react-app

文档地址:create-react-app

创建一个项目:npx create-react-app my-app

建一个ts项目:npx create-react-app my-app --typescript

终端输入:yarn eject (慎用,会把潜藏的react-script弹射到应用层,此操作不可逆)

文档目录

my-app/
  README.md
  node_modules/
  package.json
  public/
    index.html    # 入口
    favicon.ico
    robots.txt    # 搜索引擎爬取配置信息
    manifest.json # 配置页面需要的meta信息
  src/            # 项目主目录
    App.css
    App.js
    App.test.js
    index.css
    index.js
    logo.svg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2.1.2 开始前的配置

# 安装第三方插件

在vscode商店里下载

  • simple react 快速生成react模版,可以看插件具体文档

    编辑器中输入cc生成类组件,sfc生成函数示组件

  • prettier 格式化代码

  module.exports = {
  // 一行最多 100 字符
  printWidth: 100,
  // 使用 2 个空格缩进
  tabWidth: 2,
  // 不使用缩进符,而使用空格
  useTabs: false,
  // 行尾需不要有分号
  semi: false,
  // 使用单引号
  singleQuote: true,
  // 对象的 key 仅在必要时用引号
  quoteProps: 'as-needed',
  // jsx 不使用单引号,而使用双引号
  jsxSingleQuote: true,
  // 末尾不需要逗号
  trailingComma: 'none',
  // 大括号内的首尾需要空格
  bracketSpacing: true,
  // jsx 标签的反尖括号需要换行
  jsxBracketSameLine: false,
  // 箭头函数,只有一个参数的时候,也需要括号
  arrowParens: 'always',
  // 每个文件格式化的范围是文件的全部内容
  rangeStart: 0,
  rangeEnd: Infinity,
  // 不需要写文件开头的 @prettier
  requirePragma: false,
  // 不需要自动在文件开头插入 @prettier
  insertPragma: false,
  // 使用默认的折行标准
  proseWrap: 'preserve',
  // 根据显示样式决定 html 要不要折行
  htmlWhitespaceSensitivity: 'css',
  // 换行符使用 lf
  // endOfLine: 'lf',
  // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
  bracketSpacing: true
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  • 配置vscode编辑配置文件

可以配置针对该项目的配置文件,在根目录创建.vscode/settings.json

settings.json配置信息

{
  "eslint.autoFixOnSave": true, //eslint保存格式化
  "prettier.eslintIntegration": true, // 让prettier遵循eslint格式美化
  "eslint.enable": true, //是否开启vscode的eslint
  "files.eol": "\n",
  "editor.tabSize": 2,
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "eslint.validate": ["javascript", "javascriptreact", "html", "typescript", "typescriptreact"], //确定校验准则
  "files.associations": {
    "*.jsx": "javascriptreact"
  },

  "typescript.tsdk": "node_modules/typescript/lib",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 2.1.3 线上项目编辑器

codesandbox

# 2.2 组件和JSX

# 2.2.1 编写react元素

react 元素就是一个javascript对象


 












const element=<h1>hello react</h1>
console.log(element);
// render方法将react元素渲染到页面上
ReactDOM.render(element, document.getElementById('root'));

// 打印结果
{
$$typeof: Symbol(react.element)
key: null
props:{children: "hello react"}
ref: null
type: "h1"
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2.2.2 jsx

jsx是javascript的语法扩展,使用xml标记的方式直接声明界面

# jsx是什么

  • 不是模版引擎语言

模版引擎语言Angular和vue中template的语法,js模版的作用就是输入模版的字符串+数据,经过渲染得到渲染过的字符串;jsx不是这样的模版引擎,它是带语法糖的ATX,其实是抽象的语法树,语法糖放到了构建阶段,所以运行的时候不需要解析。

  • 声明示方式创建UI,处理UI逻辑

  • 遵循javascript语法,无学习门槛

# react通过babel将jsx转换浏览器识别的语言

bable

const ele=<div className="root">
         <p>hello</p>
      </div>

  // 转换后
var ele = /*#__PURE__*/React.createElement("div", {
  className: "root"
}, /*#__PURE__*/React.createElement("p", null, "hello"));
// 通过createElement创建元素
1
2
3
4
5
6
7
8
9

react通过层层嵌套的方法,把我们输入的语句转换成浏览器识别的代码,这就是jsx背后的原理

# jsx 规则

  • 在jsx中潜入表达式,用{}包裹
  • 大写开头作为定义组件,小写tag作为原生的dom节点
  • jsx标签可以有特定属性和子元素
  • jsx只能有一个根元素

# jsx 实践

  class main extends Components {
    constructor(props){
      super(props)
       this.state={
        name:"zs",
        age:12
      }
    }
    addage(){
      return this.state.age+12
    }
    render(){
      const flag=true
      const list = [1, 2, 3]
      return (
        // jsx需要一个根元素
        <div className="main">
          <p>{this.state.name}</p>
          <p>{this.state.age>18?'成年':'未成年'}</p>
          <p>{this.addage.call(this)}</p>
            {/* 三元表达式判断显示元素 */}
          {
            flag?
          <p>元素1</p>
             :
          <p>元素1</p>
          }
          {/* 只能用map循环 */}
          {list.map((item) => {
            return <div key='item'>{item}</div>
          })}
        </div>
      )
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

jsx需要一个根元素包裹,因为jsx是通过babel进行转译,其实就是通过React.createElement(),它的第一个参数需要一个元素,如果出现2个就无法识别了

# Fragments

用Fragments替换根元素,而且此标签不渲染到页面中

  class main extends Components {
    render(){
      return (
        <React.Fragment>
          <p>{this.state.name}</p>
          <p>{this.state.age>18?'成年':'未成年'}</p>
          <p>{this.addage()}</p>
       </React.Fragment>
      )
    }
  }
  // 或者用react提供的简洁方法
    class main extends Components {
    render(){
      return (
        <>
          <p>{this.state.name}</p>
          <p>{this.state.age>18?'成年':'未成年'}</p>
          <p>{this.addage()}</p>
       </>
      )
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

为什么使用Fragments

  • 可以包含并列的子元素
  • 编写表格组件,包裹子元素让html生效

# 2.2.3 拓展学习资料

Babel和ATS 抽象语法树1

Babel和ATS 抽象语法树2

# 2.3 props、列表渲染、条件渲染

什么是props?

当react元素作为自定义组件,将jsx所接受的属性转换成单个对象传递给组件,这个对象被称为“props”(就是父组件传递给子组件的对象)

  • props是组件的固有属性
  • 不可在组件内部对props进行修改
  • 更新props:需要通过父组件重新传入新的props,更新子组件(单向数据流)

# 2.3.1 示例

const listData={name:'react'}
  // 父组件
  funtion App (){
    return (
      <div>
        {/* 传递数据listData*/}
        <ListItem data={listData}></ListItem> 
      <div>
    )
  }
1
2
3
4
5
6
7
8
9
10
  // 子组件
  class ListItem extends Component {
   constructor(props){
     super(props) //子类中调用父类构造函数
   }
    render() { 
        return ( 
            <div>
             <div>
             {/* 通过props拿到值 */}
              {this.props.data.name}  
            <div>
          <div>
         );
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 函数示组件

  • 函数组件也叫无状态组件
  • 组件内部没有this
  • 没有声明周期

改写如下

  // 子组件
  funtion ListItem (props){
    return (
      <div>
        <div>
          {/* 通过props拿到值 */}
         {props.data.name}  
        <div>
      <div>
    )
  }
1
2
3
4
5
6
7
8
9
10
11

当前组件如果是纯展示组件,可以用函数组件,函数组件是一个纯函数,用函数组件可以得到性能的提升

# 2.3.2 列表渲染

const listData=[{name:'react',id:1},{name:'vue',id:2}]
  // 父组件
  funtion App (){
    return (
      <div>
        {/* 传递数据listData*/}
       {
         listData.map(item=>{
           return <ListItem data={item} key={item.id}/>
         })
       }
      <div>
    )
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2.3.3 条件渲染

条件渲染的主要方法

  • 使用三目运算符
  • 使用函数做条件判断
  • 使用与运算符 && 判断

  class ListItem extends Component {
   constructor(props){
     super(props) //子类中调用父类构造函数
   }
   renderList(){
     if(this.props.data.name==='react'){
       return <div>jsx</div>
     }else {
       return <div>template</div>
     }
   }s
   render(){
    return (
      <div className='listItem'>
        {/* 使用三目运算符*/}
        <div className={`thend-grid`${this.props.data.name==='react'?'-blue':'-green'}}>
         {this.props.data.name==='react'?'jsx':'template'}  
        <div>
          {/*使用函数做条件判断*/}
        {this.renderList.call(this)}
          {/*使用与运算符 && 判断*/}
        {this.props.data.name==='react' && <div>jsx</div>}
      <div>
    )
   }
  }
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 2.3.4 拓展学习资料

列表渲染进阶知识

更多的条件渲染的方式

# 2.4 CSS in React

# 2.4.1 行内样式

  <div style={{fontSize:18;color:red}}></div>
1

# 2.4.2 引入css样式表

     src/   
        components/
          ListItem/
            index.jsx
            index.css //也可以用scss,文件命名index.css
  // 我们在index.css 定义样式
    .title{
      color:red;
    }

 //在ListItem导入
    import './index.css' 
    class ListItem extends Component {
     constructor(props){
     super(props) //子类中调用父类构造函数
   }
 
   render(){
    return (
      <div className='listItem'>
        <span className='title'>header<span>
      <div>
    )
   }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

上面的在index.css写法,里面的样式是全局样式,会造成全局污染,可以用css module解决

# css module

  • 不使用选择器,使用class名定义样式
  • 不层叠class,使用一个class定义样式
  • 用过compose来组合
       src/   
        components/
          ListItem/
            index.jsx
            index.module.css //命名方式加入module
  // 我们在index.css 定义样式
    .title{
      color:red;
    }

 //在ListItem导入对象
    import style from 'index.module.css' 
    class ListItem extends Component {
     constructor(props){
     super(props) //子类中调用父类构造函数
   }
 
   render(){
    return (
      <div className='listItem'>
        <span className={style.title}>header<span>
      <div>
    )
   }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 2.4.3 css管理进阶

css管理工具

  • Styled-component
  • Classnames
       src/   
        components/
          ListItem/
            index.jsx
            index.module.css //命名方式加入module
  // 我们在index.css 定义样式
    .title{
      color:red;
    }
    .themd {
      background:'red'
    }

 //在ListItem导入对象
    import style from 'index.module.css' 
    import classnames from 'classnames/bind'
    const cls=classnames.bind(style)

    import cn from 'classnames'
    class ListItem extends Component {
     constructor(props){
     super(props) //子类中调用父类构造函数
   }
 
   render(){
     const flag=true
     const _cn=cn({
       'themd':flag
     })
    return (
      <div className='listItem'>
        {/* css Module+classnames/bind */}
        {/* css module 结合 classnames 可以添加2个类名 */}
        <span className={cls('title','themd')}>header<span>
        {{/* classnames */}
        <span className={_cn}></span>
      <div>
    )
   }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 2.4.4 扩展

css module

styled component

在React中使用css预编译

最新更新时间: 1/14/2024, 1:54:31 PM