React基础

技术胖的前端路线图

红色:精通,且要有对应的实战经验
蓝色:熟练,达到基础练习量
灰色:了解,课程听完即可
黑色:视频学习地址
开源地址:http://gitee.com/jishupang/web_tlas
Simple React Snippets插件:react代码的快速生成器
科学上网?在谷歌浏览器中安装React Developer Tools插件
Easy Mock:如果没有后端数据,可以使用Easy Mock给自己造一个数据

一、npm安装项目依赖
// 安装node
// 判断node与npm有没有安装成功和版本号
node -v
npm -v
// 安装react脚手架
npm install -g create-react-app
// 创建react项目
// 方法一:使用cmd,先使用mkdir创建文件夹,在里面运行下面这条命令
// 方法二:使用vscode里面的terminal运行以下命令
create-react-app 项目名
// 运行react项目
npm run start
// 安装axios
npm install axios   // 安装到项目目录中,且不添加任何依赖
npm install -g axios  // 安装到全局,npm安装目录下的perfix
npm install -save axios  // 安装到项目目录中,并在package.json中的dependencies(生产环境:已发布)中添加依赖(相应的版本)
npm install -save-dev axios  // 安装到项目目录中,并在package.json中的dev-dependencies(开发环境中:测试,项目管理)中添加依赖(相应的版本)
npm install react-transition-group --save  // 安装动画库
二、项目目录
// 项目目录
src/index.js   // 项目的入口文件
src/App.js :   // 使用模块化编程进行的一个方法模块
src/serviceWorker.js  // 移动端开发的,PWA使用这个文件会离线浏览的功能。
三、特殊写法
// {Component}是一种解构赋值的的写法,相当于 Component = React.Componment
import React,{Component} from 'react'
// 相当于
import React from 'react'
const Component = React.Component()
// 虚拟DOM:快速反应动作,不会占用页面的渲染机制
// jsx语法,在一个 js 组件中,遇到 < > 就当成html来解析,遇到  {} 就当做js来解析
// 使用ReactDOM方式创建元素并挂载到页面中
var child1 = React.createElement('li',null,'JSPang.com')
var child2 = React.createElement('li',null,'I love React')
var root = React.createElement('ul',{className:'my-list',child1,child2})

// 使用jsx方式创建类组件并挂载到对应的位置
class App extends Component{
  // 类组件渲染到页面的内容
  render() {
    return (
      // jsx的语法:遇到 < > 就当成html来解析,遇到  {} 就当做js来解析
      <ul className='my-list'>
        <li>JS1</li>
        <li>JS2</li>
      </ul>
    )
  }
}
四、生命周期

定义:在某一时刻可以自动执行的函数

在这里插入图片描述

// 初始周期
构造函数constructor(set props&state)
// 挂载周期
// componentWillMount 是组件挂载前执行的(可用于 打印日志 和 查询数据库 操作)
// render 是state和props发生改变时会进行的渲染
// componentDidMount 是组件挂载完成后执行的(也可用于 打印日志 和 查询数据库 操作)
componentWillMount --> render --> componentDidMount
// 组件更新周期
// componentWillReceiveProps : 当子组件接受props时执行,当在顶层组件时是不会执行的(组件第一次存在于dom中,函数不会被执行,如果已经存在于dom中,函数才会被执行)
// shouldComponentUpdate : 组件(props或state)更新之前进行执行的,必须返回一个boolean值,返回true会继续向下执行其他生命周期,返回false则不会向下执行了
// componentWillUpdate : 在shouldComponentUpdate后执行,render前执行
// render : state和props发生改变时会进行的渲染
// componentDidUpdate : 改变完成后执行
props : componentWillReceiveProps -- shouldComponentUpdate -- componentWillUpdate -- render -- componentDidUpdate
states : shouldComponentUpdate -- componentWillUpdate -- render -- componentDidUpdate
// 组件删除周期
componentWillUnmount : 组件被删除时执行
五、在实践中学一些注意事项
5.1.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>React App</title>
  </head>
  <body>
    <noscript>如果js代码受到阻止或没有跑成功会显示的内容</noscript>
    <!-- react中的src/index.js只对root这一块内容进行渲染,其他部分并没有控制,所在在这里使用jquery是完全可以的 -->
    <div id="root"></div>
    <div>knb dmb d d</div>
  </body>
</html>
5.2.src/index.js

项目入口文件

import React from 'react'
import ReactDOM from 'react-dom'
import XiaoJieJie from './XiaoJieJie'

// 将<App/>组件挂载到public/index.html 下面id="root"的div
ReactDOM.render(<XiaoJieJie/>,document.getElementById('root'))
5.3.src/XiaoJieJie.js

类组件:XiaoJieJie父组件

// {Component}是一种解构赋值的的写法,相当于 Component = React.Componment
import React,{Component,Fragment} from 'react'
import XiaoJieJieItem from './XiaoJieJieItem'    // 引入新的组件
import axios from 'axios'
import './index.css'

// 在js中写html的写法(类组件和函数组件)
// 类组件
class XiaoJieJie extends Component{

    // 初始周期:构造函数(set props&state)
    constructor(props){
        super(props)    // props调用的是父类Component的
        this.state = {
            inputValue : '',
            // react只能遍历数组类型的数据,不能遍历对象类型的数据
            servicelist : ['指甲油','种睫毛']
        }
    }

    // 挂载周期:componentWillMount --> render --> componentDidMount
    // componentWillMount : 组件挂载前执行的(可用于 打印日志 和 查询数据库 操作)
    // render : state和props发生改变时会进行的渲染
    // componentDidMount : 组件挂载完成后执行的(也可用于 打印日志 和 查询数据库 操作)
    // componentWillMount(){
    //     console.log("componentWillMount -- 组件将要挂载到页面时执行")
    // }
    // 用于请求远程数据,使用componentDidMount生命周期比较合适,只加载一次,后续不再进行请求
    componentDidMount(){
        // axios请求远程数据
        // https://web-api.junjin.im/v3/web/wbbr/bgeda是要访问的后台接口
        axios.post('https://baidu.com')
            .then((res)=>{  
                console.log('axios获取数据成功'+JSON.stringify(res))
            })
            .catch((error)=>{
                console.log('axios获取数据失败'+error)
            })
        // console.log("componentDidMount -- 组件挂载到页面后执行")
    }
    // 组件更新周期
    // props : componentWillReceiveProps -- shouldComponentUpdate -- componentWillUpdate -- render -- componentDidUpdate
    // states : shouldComponentUpdate -- componentWillUpdate -- render -- componentDidUpdate
    // componentWillReceiveProps : 当子组件接受props时执行,当在顶层组件时是不会执行的(组件第一次存在于dom中,函数不会被执行,如果已经存在于dom中,函数才会被执行)
    // shouldComponentUpdate : 组件(props或state)更新之前进行执行的,必须返回一个boolean值,返回true会继续向下执行其他生命周期,返回false则不会向下执行了
    // componentWillUpdate : 在shouldComponentUpdate后执行,render前执行
    // render : state和props发生改变时会进行的渲染
    // componentDidUpdate : 改变完成后执行
    // componentWillReceiveProps(){
    //     console.log("componentWillReceiveProps")
    // }
    // shouldComponentUpdate(){
    //     // 必须返回一个boolean值
    //     // 如果return true 就会继续往下执行componentWillUpdate和render了
    //     // 如果return false 就不会往下执行componentWillUpdate和render
    //     return false 
    // }
    // componentWillUpdate(){
    //     console.log("2 -- componentWillUpdate")
    // }
    // componentDidUpdate(){
    //     console.log("4 -- componentDidUpdate")
    // }
    // 组件删除周期
    // componentWillUnmount : 组件被删除时执行
    // 类组件渲染到页面的内容
    // jsx的语法:遇到 < > 就当成html来解析,遇到  {} 就当做js来解析
    render(){
        console.log("3 -- render -- state和props发生改变时会进行的渲染")
        return (
        	// 虚拟DOM只能由一个根标签,且标签必须闭合
            // 可以使用Fragment,也可以使用<>空标签
            <Fragment>
                <div>
                    {/* onChange事件绑定,当向输入框中输入内容时,会调用his.inputChange方法 */}
                    {/* react事件要绑定this(指针+时间绑定问题),bind(this),这样inputChange方法中的this就会指向当前XiaoJieJie组件了,使用箭头函数就不需要考虑绑定问题了 */}
                    <label htmlFor="servicelabel">增加服务:</label>  
                    <input 
                        id="servicelabel"           // label中的htmlFor用来绑定点击被激活的id,点击label就会激活输入框 
                        className="serviceinputCss"    // 引入css,需要使用className="serviceinputCss",不能直接使用class,以免跟类组件的class重名
                        value={this.state.inputValue} 
                        onChange={this.inputChange.bind(this)} 
                        ref = {(input) => {    // 使用ref箭头函数对输入框中的值进行绑定,input相当于输入的内容
                            this.input = input  
                        }}
                    /> 
                    &nbsp;&nbsp;
                    <button onClick={this.addService.bind(this)}>增加服务</button>
                </div>
                {/* 给ul进行ref绑定,这样就可以获取ul这个对象 */}
                <ul ref={(ul) => {this.ul = ul}}>   
                    {
                        // 使用map来进行循环遍历数组
                        // map函数内部使用的是一个箭头函数,前面一个括号是参数,后面一个大括号是执行的函数
                        // item是数组中的每一项,index是每一项的索引值(索引是从0开始的)
                        this.state.servicelist.map((item,index) => {
                            // map循环遍历需要有一个key值,不能只使用索引值,因为index索引值会重复,可以加上item项来减少重复的可能
                            return (  // 只有return加一个小括号,才支持html标签换行
                                // <li 
                                //     key={index+item}
                                //     onClick={this.deleteItem.bind(this,index)}  // 删除单个服务项,要传递一个index索引项
                                //     dangerouslySetInnerHTML={{__html:item}}   // 将每一项都使用dangerouslySetInnerHTML来解析,这样可以将输入html代码解析,显示成对应的样式,如<h1>烫睫毛</h1>,会显示成一个黑体加粗的烫睫毛
                                // > 
                                // </li>  
                                <XiaoJieJieItem 
                                    key = {index+item}   // 用来循环时有一个唯一的key值
                                    serviceitem = {item}  // 父组件给子组件传值:属性={值}的方式
                                    index = {index}
                                    deleteItem = {this.deleteItem.bind(this)}   // 父组件给子组件传方法:属性={this.方法名.bind(this)}的方式
                                />   
                            )
                        })
                    }
                </ul>
            </Fragment>
        )
    }
    // 改变输入框中的值
    inputChange(e){
        // this.state.inputValue = e.target.value 在react框架中这是一个错误的方法
        // 需要使用setState的方法赋值
        this.setState({
            inputValue : this.input.value    // 使用ref箭头函数对输入框中的值进行绑定
            // inputValue : e.target.value   // e.target.value 获取输入框的内容
        })
    }
    // 添加服务按钮
    addService(){
        // 需要使用setState的方法赋值
        if(this.state.inputValue === ''){
            alert('您还没有输入任何服务')
        }else{
            // 虚拟DOM,渲染是需要时间的
            // this.setState是一个异步的方法,是浏览器在空闲的时候才会执行的内容
            this.setState({
                // ... :表示扩展运算符,相当于将数组中的每一个值都放到新数组中
                // servicelist:['指甲油','种睫毛',this.state.inputValue],用中括号括住表示在数组中再添加一个值
                servicelist:[...this.state.servicelist,this.state.inputValue],
                inputValue:''
            },() => {   // 如果遇到ref绑定错误或获取数据不准确,填setState的坑,在setState后面提供了一个回调函数,在这里面来进行后续的一些操作
                console.log(this.ul.querySelectorAll('li').length)   // 使用ref获取ul对象,使用querySelectorAll来获取所有li的子节点
            })
        }
    }
    // 删除单个服务项
    deleteItem(index){
        // 一个超级大的坑
        // 正确写法是获取一个局部的newservicelist,将其赋值给声明的变量中,然后再操作局部数组的值,最后再使用setState来提交赋值
        // 错误写法:不能直接操作 this.state.servicelist 中的值,因为后期做性能优化的时候比较麻烦
        let newservicelist = this.state.servicelist
        newservicelist.splice(index,1)   // splice方法代表从index索引项开始删除一个值
        this.setState({
            servicelist:newservicelist
        })
    }
}
// ES6导出语法
export default XiaoJieJie
5.4.src/XiaoJieJieItem.js

类组件:XiaoJieJieItem子组件

// 拆分组件

// 单向数据流:子组件只能接受父组件传的值,但是不能直接干预父组件,就是不能给父组件直接传值
// 父组件可以给子组件传值:<XiaoJieJieItem serviceitem={item}/>    
// 子组件调用父组件传的值:{this.props.serviceitem}

// 解决单向数据流的问题:父组件给子组件传递一个方法,通过子组件调用父组件的方法来解决
// 父组件给子组件传方法:<XiaoJieJieItem deleteItem = {this.deleteItem.bind(this)}/>
// 子组件调用父组件传的方法:{this.props.deleteItem}
import React, { Component } from 'react'

// 父组件对子组件传值进行数据校验:PropTypes
import PropTypes from 'prop-types'
class XiaoJieJieItem extends Component {

    constructor(props){
        super(props)
        // 在构造函数中给函数名进行绑定,方便以后的性能优化,在下面就只需要使用this.handleClick,就不需要再写bind(this)
        this.handleClick = this.handleClick.bind(this)   
    }

    // 进行性能优化
    // 如果输入框中的值不等于父组件传的值,就继续执行后续的render等生命周期
    // 如果相等,就说明没有在操作输入框了,就不继续执行后续的生命周期了
    shouldComponentUpdate(nextProps,nextState){
        if( nextProps.serviceitem != this.props.serviceitem){
            return true
        }else{
            return false
        }
    }

    // 在接受父组件传来的props时执行
    // componentWillReceiveProps(){
    //     console.log("componentWillReceiveProps")
    // }
    // componentWillUnmount : 组件被删除时执行
    // componentWillUnmount(){
    //     console.log("组件被删除时执行")
    // }

    // 函数式编程:在类组件中写方法
    // 好处:代码清晰,前端自动化测试更加方便
    render() { 
        return (
            // 使用 “{this.props.调用子组件时传值的属性}” 来获取父组件给子组件传的值
            <li onClick={this.handleClick}>
                {this.props.avname}为你服务--{this.props.serviceitem}
            </li>
        );
    } 
    handleClick(){
        // 调用父组件的删除方法
        this.props.deleteItem(this.props.index)
    }
}

// PropTypes用来对传递的数据进行校验
// isRequired代表这个数据必须由父组件传递,不传递就会报错
XiaoJieJieItem.propTypes = {   // 上面的p是小写 propTypes ,下面的P是大写 PropTypes
    avname:PropTypes.string.isRequired,   
    serviceitem:PropTypes.string,  // serviceitem是string类型的
    index:PropTypes.number,        // index是number类型的
    deleteItem:PropTypes.func      // deleteItem是func方法
}
// 如果使用了isRequired又不想传值,就需要在子组件中设置一个默认的值
XiaoJieJieItem.defaultProps = {
    avname:'小敏'
}

export default XiaoJieJieItem;
5.4.src/Hello.jsx
import React, { Component } from 'react'
import './index.css'

class HelloComponent extends Component {
    // 构造器调用一次
    constructor(props) {
        // 在super前不能调用this
        super(props);
        // 解决updateWeather中this的指向问题
        this.updateWeather = this.updateWeather.bind(this)
        this.state={
            content:'前端js框架列表',
            // isHot:true,
            // react只能遍历数组类型的数据,不能遍历对象类型的数据
            list:['Angular','React','Vue'],
        }
    }
    // 可以将state中的值直接写到类组件中
    state={isHot:true}
    // render调用1+n次,第一次调用是初始化调用,n是状态更新的次数 
    render() { 
        // 使用解构赋值的方式先取到isHot
        // const {isHot} = this.state.isHot
        return (
            // 虚拟DOM只能由一个根标签,且标签必须闭合
            <>
                {/* 
                    给html标签加样式
                    方式一:className,要引入对应的css文件
                    方式二:内联样式,style={{'key':'value'}} 
                */}
                <h2 id='atguigu' className='title' style={{'color':'green'}}>
                    <span>{this.state.content}</span>
                    {/* onClick={this.updateWeather} 不能写成 onClick={this.updateWeather()} 等被点击的时候才调用函数,而不是直接调用函数然后进行赋值*/}
                    <span>今天天气很{this.state.isHot?'炎热':'凉爽'}</span><button onClick={this.updateWeather}>点击</button>
                </h2>
                <ul>
                    {/* 大括号里面不能写js语句【if,for,switch】,只能写js表达式【表达式都会有一个只,如a,a+b,demo(1),arr.map(),function test(){}】 */}
                    {
                        this.state.list.map((item,index) => {
                            return <li key={item+index}>{item}</li>
                        })
                    }
                </ul>
            </>
        );
    }
    // updateWeather放在HelloComponent原型上,通过实例调用
    // 由于updateWeather是onCLick的回调,不是通过实例调用的,是直接调用
    // 类中的方法默认开启了局部的严格模式,所以updateWeather中的this为undefined
    // 但当调用时采用bind(this),绑定了this,this就指向HelloComponent组件实例了
    updateWeather(){
        const isHot = this.state.isHot
        // 状态不能直接更改,需要借助setState来修改状态,且更新是一种替换,而不是更新
        this.setState({
            isHot:!isHot
        })
    }
}
 
export default HelloComponent;

六、动画效果
import React, { Component } from 'react'
import {CSSTransition,TransitionGroup} from 'react-transition-group'
import './index.css'

class Boss extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isShow : true
        }
        this.toToggole=this.toToggole.bind(this)   // 让this指向正确
    }
    render() { 
        return (  
            <>
                <CSSTransition
                    in={this.state.isShow}   // 开关打开:显示文字
                    timeout={2000}    // 显示出来的时间2s
                    classNames="boss-text"   // 这里是index.css中的样式前缀
                    unmountOnExit    // DOM元素退场时直接给元素删除
                >
                    {/* <div className={this.state.isShow?'show':'hide'}>Boss级任务 -- 孙悟空</div> */}
                    <div>Boss级任务 -- 孙悟空</div>
                </CSSTransition>
                
                <div>
                    <button onClick={this.toToggole}>召唤Boss</button>
                </div>
            </>
        );
    }
    toToggole(){
        this.setState({
            isShow : this.state.isShow ? false : true
        })
    }
}
 
export default Boss;
.serviceinputCss{
  border: 3px solid #ae7000;
}
.show{
  /* 
    opacity: 1;
    transition: all 1.5s ease-in;  // 动画形式消出现
  */
  animation: show-item 2s ease-out forwards;
}
.hide{
  animation: hide-item 2s ease-out forwards;   /* forwards 可以在动画运行到最后一帧时停止,否则会跳到第一帧 */
}

/* 使用@keyframes创建动画 */
@keyframes show-item{
  /* 添加关键帧 */
  0%{
    opacity: 0;
    color: yellow;
  }
  50%{
    opacity: 0.5;
    color: red;
  }
  100%{
    opacity: 1;
    color: green;
  }
}
@keyframes hide-item{
  /* 添加关键帧 */
  0%{
    opacity: 1;
    color: yellow;
  }
  50%{
    opacity: 0.5;
    color: red;
  }
  100%{
    opacity: 0;
    color: green;
  }
}

/* enter是指动画入场的样式 */
boss-text-enter{
  opacity: 0;
}
/* enter-active是指动画入场到结束之前的样式 */
boss-text-enter-active{
  opacity: 1;
  transition: opacity 2000ms;
}
/* enter-done是指动画入场结束后的样式 */
boss-text-enter-done{
  opacity: 1;
}
/* exit是指动画出场的样式 */
boss-exit-enter{
  opacity: 1;
}
/* exit-active是指动画出场到结束之前的样式 */
boss-text-exit-active{
  opacity: 0;
  transition: opacity 2000ms;
}
/* exit-done是指动画出场结束后的样式 */
boss-text-exit-done{
  opacity: 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React基础面试题通常包括以下几个方面: 1. React中函数组件和类组件的区别是什么? 函数组件是一个简单的JavaScript函数,接受props作为参数并返回一个React元素。它通常用于展示静态内容或处理简单的交互逻辑。类组件是通过ES6的class语法创建的,继承自React.Component,可以使用state来管理内部状态以及使用生命周期方法,适用于复杂的逻辑和状态管理。 2. 在React中,keys的作用是什么? 键(keys)是React中用于识别和跟踪组件列表中每个元素的特殊属性。它们帮助React准确地更新和重排组件,提高性能。在遍历生成列表的时候,为每个元素添加唯一的键,可以帮助React更好地识别元素的变化,避免不必要的重新渲染。 以上回答参考了引用和引用中的内容。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [2022必备react面试题 附答案](https://blog.csdn.net/It_kc/article/details/121773566)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [【前端面试题】—30道常见React基础面试题(附答案)](https://blog.csdn.net/snsHL9db69ccu1aIKl9r/article/details/115339484)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [面试题-基础.doc](https://download.csdn.net/download/Sheng_zhenzhen/12576734)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值