React项目创建以及结构

本文详细介绍了React的基本概念、特点、版本以及如何使用create-react-app创建项目。重点讲解了项目文件结构、组件的DOM样式、数据挂载方式、属性(props)与状态(state)的使用,包括无状态组件与类组件的区别,以及受控组件和非受控组件的概念。此外,还涵盖了React中的数据渲染和状态管理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

react是什么
  • React是一个声明式,高效且灵活的用于构建用户界面的JavaScript组件库,使用react可以将一些简短,独立的代码片段合成复杂的UI界面,这些代码片段被称作组件
react介绍
  • facebook公司的开源项目 2013年5月 开源(Angar2012年开源,vue2016年开源)
  • js框架(MVC框架,专注于V)
  • 能够构建大型应用
  • vue面向中小型应用
  • 市场项目(饿了吗)
react特点
  • 声明式 (虚拟DOM,数据改变,更新视图)
  • 组件化 (component使用js编写,而不是template–使传递数据更轻松,状态与DOM分离)
  • 一次学习,随处编写
当前版本

16.x

脚手架create-react-app
  • react使用到了jsx语法(浏览器不支持,需使用webpack编译成js语法)
创建项目
  • 全局安装create-react-app
    • npm install -g create-react-app
    • 创建项目
      • create-react-app 项目名
  • 非全局安装创建项目
    • npx create-react-app 项目名(临时安装react脚手架)
安装的内容
  • react:react的顶级库
  • react-dom:将jsx编辑的react编译成浏览器能识别的js和标签(jsx:js+xml; react有很多的运行环境,比如app端的react-native)
  • react-script:react应用程序的运行脚本(webpack等)
react的脚本命令
  • yarn start 运行开发环境
  • yarn bulid 运行生产环境
  • yarn test 运行测试环境
  • yarn eject react配置的抽离(不可逆)
    • 从node_modules的react-script文件中抽离配置文件,项目中会多出两个文件 config(脚手架等配置文件)和 scripts(运行环境的配置)
npm安装失败解决
  • 切换npm镜像为淘宝镜像
  • 使用yarn,如果本来使用yarn还要失败,还得把yarn的源切换到国内
  • 如果还没有办法解决,请删除node_modules及package-lock.json然后重新执行npm install命令
  • 再不能解决就删除node_modules及package-lock.json的同时清除npm缓存npm cache clean --force 之后再执行npm install 命令

项目文件分析

build
  • 生产环境文件
public
  • 静态资源文件

  • public>index.html

    • #root–整个项目的容器
    • 设置icon
  • public>manifest.json

    • 一些背景颜色,图标大小,字体颜色等css样式的设置
config(从node_modules抽离时生成,不可逆)
  • 脚手架等配置文件
scripts(从node_modules抽离时生成,不可逆)
  • 运行环境的配置
src
  • 项目开发目录
src>index.js
  • 相当于webpack的入口文件
  • 主要的功能
    • 渲染app组件
      • ReactDOM 把虚拟dom渲染成真实dom,并把真实dom插入到一个容器(dom标签)中
      • ReactDOM.render(组件,document.getElementById(‘root’) (容器))
    • 设置通用样式
src>index.css
  • 全局样式
src>app.js
  • 引入react,样式(index.js),图片
  • 函数式组件(无状态组件(PureComponent))

Function App() {//组件名
    return (
        组件(
            组件名必须大写, 否则报错
            jsx语法(使用jsx语法必须要引入react),
            单大括号 { 函数表达式 },
            根元素唯一,不渲染根元素使用Fragment嵌套
            组件不需要注册,
            注释:{ 多行注释 },注释也是js语法
      )
   )
}

//其他写法

const App = (props) => <h1>欢迎进入{props.name}的世界</h1>

使用:
1App({
    name: 'react'
})//不符合jsx语法
2// React组件的调用方式
<App name="react" />,

  • 类组件(class)
    import React , { Component } from 'react'
    class App extends Component{
    //react之前 React.createClass
        render(){
            <Flagment>app</Flagment>
        }
    }
    export default App
    
    同一个js文件中class组件嵌套
    
    原理:
    被嵌套组件实例化,再在另一个组件中使用
    /*const app = new App({
        name: 'react'
    }).render()*/
    可以不写,可以直接写类名


无状态组件 vs class组件
  • 函数式组件是直接调用(调用函数),类组件其实就是一个构造器,每次使用组件都相当于在实例化组件
  • jsx语法中的回避,
    组件可以写html,css和js
    但会出现冲突
    css的class会被识别为js中的关键字或保留字
    解决:css的class=》className
    css的value=》defaultValue
  • 导出组件(es6)

DOM编译

import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
    render () {
    return (
        <div className='app' id='appRoot'>
            <h1 className='title'>欢迎进入React的世界</h1>
            <p>
                React.js 是一个构建页面 UI 的库
            </p>
        </div>
        )
    }
}
ReactDOM.render(
    <App />,
    document.getElementById('root')
)

编译之后将得到这样的代码:

import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
    render () {
    return (
        React.createElement(
        "div",
        {
            className: 'app',
            id: 'appRoot'
        },
        React.createElement(
        "h1",
        { className: 'title' },
        "欢迎进入React的世界"
        ),
        React.createElement(
        "p",
        null,
        "React.js 是一个构建页面 UI 的库"
        )
     )
    )
    }
}
ReactDOM.render(
    React.createElement(App),
    document.getElementById('root')
)

组件中的dom样式(4种,style,className,第三方插件classnames和css-in-js)

  • 单标签在组件中需要加 /
行内样式(style 推荐)
const styleBox = { color : 'red' , fontSize : '14px' }//实例属性
render(){
const styleObj = { color : 'red' , fontSize : '14px' }
//注意这里的两个括号,第一个表示我们在要JSX里插入JS了,第二个是对象的括号
<p style = { { color : 'red' , fontSize : '14px' } } > Hello world </p>

<p style = { styleObj } > Hello world </p>

<p style = { this.styleBox } > Hello world </p>
}
className
className = "类型"
第三方插件classnames(常用于类名切换)

yarn classNames

import classnames from 'classnames' 
const names = classnames({
    //类名:布尔值
    content:true
})

使用:
<p className = { names } ></p>
css-in-js (在js中写css样式,第三方包(styled-components))

样式组件

import styled from 'styled-components'
const Container = styled.div`
    width : 200px ;
    height : 300px ;
`
//会解析成div
使用: <Container></Container>//可以组件嵌套,组件内文字不会覆盖,自动取类名,推荐使用

组件的数据挂载方式

react中数据分为两个部分

  • props 属性(一开始就具备的)
  • state 状态(频繁变化的数据 )

属性(props)

  • 外部传入
  • 内部设置

在类组件中的使用

外部传入
<propsCom name = "zhangsan"></propsCom>

获取 this.props.属性名
默认属性设置设置
//class组件
static defaultProps = {//该定义为16版本以上
    name : "lisi"
}
getDefaultProps(){//15版本用法,钩子函数
    return {
        name : "wangwu"
    }
}
获取 this.props.属性名

//函数式组件

// 使用箭头函数创建的组件,需要在这个组件上直接写defaultProps属性
组件名.defaultProps = {
    name: 'React.js'
}


在函数式组件中使用

外部传入

const item = ( props ) => {
    return (
        <div>
            { props } //props为外部传入的值
        </div>
    )
}

-props.children //获取父组件中放在子组件中的值

子组件:
const Content = ( props ) => {
    return (
        <p> { props.children }</p>
    )
}
props属性验证(prop-types第三方插件)

npm i prop-types -S

import React from 'react'
import PropTypes from 'prop-types'

class MyComponent extends React.Component{
    render() {
        
    }
}

MyComponent.propTypes = {
    //属性名:数据类型
    optionalArray:PropTypes.array/bool/func/number/object/string/symbol/node/element
}

props.children

props.children类似于vuejs中的插槽

<Content><i>React.js</i>是一个构建UI的库</Content>
上面的代码中,组件Content中的html内容其实也是一个组件(静态的)
一般在使用不会显示,这是因为没有在Content中渲染,可以通过props.children来获取到这个组件,并通过jsx语法使用


const Content = (props) => {
    return (
        <p>{props.children}</p>
    )
}

状态(state)

  • 组件自己的状态只能自己更改
class App extends Component {
    //第一种形式
    state = {
        price:1000
    }
    render(){
        return (
            { this.state.price }
        )
    }
}
第二种形式(推荐),与第一种形式不能一起使用
class App extends Component {
    constructor(){
        super()//修正this指向,让App继承Component
        this.state = {
            name : 'zhangsan'
        }
    }
    
    render(){
        return {
            { this.state.name }
        }
    }
}
数据修改

this.props和this.state是纯js对象,在vue中,data属性是利用Object.defineProperty处理过的,更改data的数据的时候会触发数据的getter和setter,但react没有做这样的处理,需要通过使用特殊的更改状态的方法setState


change () {
    this.setState({
        name:“lisi"
    })
}//使用这种写法时在render函数中使用时是this.setState,会出现this丢失,需要写成this.setState.bind(this)

或者把使用setState方法的函改成箭头函数
change = () => {
    this.setState ({
        name:"wangwu"
    })
}change = () => {
    this.setState( ()=> {
        修改操作//数据修改了,但视图未更新
        return {//再次覆盖,为了触发视图更新
            name: this.state.name
        }
    })
}
setState参数
  • setState函数是异步
  • 第一个参数可以是对象,也可以是方法**(return 一个对象,它有两个参数,第一个参数表示改变之前的state,第二个参数是this上的属性(props))**
  • 第二个参数是一个回调函数

属性vs状态

相似点

  • 是纯js对象,都会触发render更新,都具有 确定性(状态/属性相同,结果相同)

不同点
1.属性能从父组件获取,状态不能
2.属性可以有父组件修改,状态不能
3.属性能在内部设置默认值,状态也可以
4.属性不在组件内部修改,状态要改
5.属性能设置子组件初始值,状态不可以
6.属性可以修改子组件的值,状态不可以

  • 没有state的组件叫做无状态组件,有state的组件叫做有状态组件

属性与状态总结

state 的主要作用是用于组件保存、控制、修改自己的可变状态。state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState方法进行更新,setState 会导致组件的重新渲染。
props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props,否则组件的 props 永远保持不变。
如果搞不清 stateprops 的使用场景,记住一个简单的规则:尽量少地用 state,多用 props
没有 state 的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。

个人见解
  • state在组件传递的时候,因为state和props都用this.props接收,所以state不可能出现在子组件中(转变成了属性),当this.props接收的是一个函数时,可以在组件中定义箭头函数,在内部不修改函数指向的情况下运行
  • 父组件通过ref获取子组件数据时,要把state修改的逻辑在子组件中写成函数,才能在父组件中不修改this的情况下实现state的修改
  • 在以函数的创建组件的时候,函数的参数为props,所以可以用es6解构
状态提升

如果有多个组件共享一个数据,把这个数据放到共同的父级组件中来管理

受控组件与非受控组件

react组件的数据渲染是否被调用,是通过传递过来的props完全控制,控制则为受控组件,否则非受控组件
(就是父组件传值给子组件,子组件中使用三元表达式之类的方法控制内容的显示)

渲染数据

  • 条件渲染
{ condition ? 'A' : 'B'}

{ condition && 'A' || 'S' }
  • 列表渲染
方法1 初级写法
this.state.name.map(( item,index ) => {
        return (
            { item.firname }
        )
    }
)
方法二 推荐 组件拆分
const Item = ( prop ) => {
    return <p>{ prop.name.firname } </p>
}
class
render () {
    return ( 
        <div>
        {
         this.state.name.map(( item,index ) => <Item item = { item } key = { item.id } ></Item>
)}</div>)}
第三种 更进一步的组件拆分
const Item = ( prop ) => {
    return <p>{ prop.name.firname } </p>
}
class
renderItem = ( ) => {
    return this.state.name.map(( item,index ) => <Item item = { Item } ></item>
)}

render () {
    return (
        <div>
            { this.renderItem() }
        </div>
    )
  }
}
数据中的html标签转义(富文本)

dangerouslySetInnerHTML = {{ __html:this.state.content }} 在属性中使用
this.state.content为有html标签的文本(不使用富文本编辑,标签会被转义)

reactjs笔记至1100

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值