react基础超详细知识点总结(生命周期、todolist案例)

1、什么是CPU

中央处理器(central processing unit,简称CPU)作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元

2、reduce

(1)定义和用法

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值;

reduce() 可以作为一个高阶函数,用于函数的 compose;

注意: reduce() 对于空数组是不会执行回调函数的;

(2)语法

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

(3)参数

参数描述
function(total,currentValue, index,arr)必需;用于执行每个数组元素的函数。 函数参数:参数描述total必需。初始值, 或者计算结束后的返回值。currentValue必需。当前元素currentIndex可选。当前元素的索引arr可选。当前元素所属的数组对象。
initialValue可选,传递给函数的初始值

3、生命周期回调函数—生命周期钩子函数—生命周期函数—生命周期钩子

(1)生命周期什么时候开始调用和写代码的顺序是没有关系的;

在代码的书写过程中,一般将构造器放在最上面,这是书写顺序的问题;

当setState()这个函数更新的时候,则会触发shouldComponentUpdate()钩子函数---此钩子函数相当于组件更新的”阀门“,在不写这个钩子函数的时候,则默认返回true,当写了这个钩子函数的时候,则需要返回一个Boolean值,若是不写返回值的话,则就是unfined;

forceUpdate()强制更新:不更改任何状态中的数据,强制更新一下

父组件通过自定义属性向子组件传递参数;

组件将要接收新的props的钩子函数
componentWillReceiveProps(props){
console.log(props);
}

总结:

1.初始化阶段:由ReactDOM.render()触发---初次渲染
            constructor();
            componentWillMount();
            render();
            componentDidMount()=====》常用,一般在这个钩子中做一些初始化的事情,例如:开启定时器、发送网络请求、订阅消息
2.更新阶段:由组件内部this.setState()或父组件render触发
           1.shouldComponentUpdate();
           2.componentWillUpdate();
           3.render()=====》必须使用
           4.componentDidUpdate();
3.卸载组件:由ReactDOM.unmountComponentAtNode()触发
           componentWillUnmount()=====》常用,一般在这个钩子中做一些收尾的事情,例如:关闭定时器、取消订阅消息

(2)新生命周期知识点总结:

//若state的值在任何时候都取决于props,那么可以使用getDerivedStateFormProps,不过这个函数的意义几乎不大,具体的说法参考官网
static getDerivedStateFormProps(props,state){
console.log('getDerivedStateFormProps',props,state);
return null;
}

getSnapshotBeforeUpdate(){
return 'shangguigu'
}
//组件更新完毕的钩子函数
componentDidUpdate(preProps,preState,snapshotValue){
  console.log(preProps,preState,snapshotValue)
}

小案例主要代码:

getSnapshotBeforeUpdate(){
   return this.refs.list.scrollHeight;
}

componentDidUpdate(preProps,preState,height){
   this.refs.list.scrollTop += this.refs.list.scrollHeight - height;
}

总结:

1.初始化阶段:由ReactDOM.render()触发---初次渲染
            constructor();
            getDerivedStateFormProps();
            render();
            componentDidMount()=====》常用,一般在这个钩子中做一些初始化的事情,例如:开启定时器、发送网络请求、订阅消息
2.更新阶段:由组件内部this.setState()或父组件冲重新render触发
           1.getDerivedStateFormProps();
           2.shoulComponentUpdate();
           3.render()=====》必须使用;
           4.getSnapshotBeforeUpdate();
           5.componentDidUpdate();
3.卸载组件:由ReactDOM.unmountComponentAtNode()触发
           componentWillUnmount()=====》常用,一般在这个钩子中做一些收尾的事情,例如:关闭定时器、取消订阅消息

(3)即将废除的钩子函数:

componentWillMount;

componentWillReceiveProps;

componentWillUpdate;

现在使用会出现警告,下一个大版本需要加上USEAFE前缀才能使用,以后可能会被彻底废弃,不建议使用

4、react应用(基于react脚手架)

(1)使用create-react-app创建react应用

A、react脚手架

B、创建项目并启动

第一步:全局安装:npm i create-react-app -g
第二部:切换到想创建项目的目录,使用命令:create-react-app hello_react
第三步:进入项目文件夹:cd hello-react
第四步:启动项目:npm start

C、index.html

<!--%PUBLIC_URL%代表Public文件夹的路径 -->
<link rel="icon" href="%PUBLIC_URL%/favicon.ico">
<!--开启理想视口,用于做移动端网页的适配-->
<meta name = 'viewport' content = "width=device-width,initial-scale=1" />
<!--用于配置浏览器页签+地址栏的颜色(仅支持安卓手机浏览器) -->
<meta name='theme-color' content='red'>
<!--用于指定网页添加到手机主屏幕后的图标 -->
<link rel="app-touch-icon" href="%PUBLIC_URL%/logo192.png">
<!--应用加壳时的配置文件 -->
<link rel="mainfest" href="%PUBLIC_URL%/mainfest.json">
<!--若浏览器不支持js,则展示标签中的内容-->
<noscript>您好,你不支持</noscript>

(2)react脚手架项目解构

public-----静态资源文件夹

​ favicon.icon --------网站页签图标

​ index.html-----主页面

​ logo192.png ------ logo图

​ logo512.png ------logo图

​ mainfest.json ------ 应用加壳的配置文件

​ robots.txt -------爬虫协议文件

src----源码文件夹

​ App.css -------App组件的样式

​ App.js -------- App组件

​ App.test.js -----样式

​ index.css ----- 入口文件

​ index.js ----- 入口文件

​ logo.svg ----- logo图

​ reportWebVitals.js ------页面性能分析文件(需要web-vitals库的支持)

​ setupTests.js ----- 组件单元测试的文件(需要jest-dom库的支持)

5、经典面试题目

(1)react/vue中的key有什么作用?(key的内部原理是什么?)

简单的说:KEY是虚拟DOM对象的标识,在更新显示时key起着极其中重要的作用;

详细的说:当状态中的数据发生变化时,react会根据新数据生成新的虚拟DOM,随后React进行新虚拟DOM与旧虚拟DOM的diff比较,比较规则如下:

旧虚拟DOM找到了与新虚拟DOM相同的KEY:若虚拟DOM中内容没变,直接使用之前的真实DOM;若虚拟DOM中内容变化了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM;

旧虚拟DOM中未找到与新虚拟DOM相同的key:根据数据创建新的真实DOM,随后渲染到页面

(2)为什么遍历列表时,KEY最好不要使用index?

用index作为key可能会引发的问题:若对数据进行逆序添加、逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新===》界面效果没问题,但效率低;

如果结果中还包括输入类的DOM:会产生错误虚拟DOM更新===》界面有问题;

注意:如果不存在对数据的逆序添加、逆序删除等破坏的操作,仅用于渲染列表用于展示,使用index作为key是没有问题的;

(3)开发中如何选择KEY?

最好使用每条数据的唯一标识作为key,比如:id、手机号、身份证号码、学号等唯一值;

如果确定只是简单的展示数据,用index也是可以的;

6、defaultChecked是一个刚上来是否是选中的状态,它只在第一次起作用,后期将不再起作用

7、nanoid是一个库,它里面分别暴露,其中有一个就是nanoid。nanoid是一个函数,这个函数可以随机的生成一个字符串,并且可以保证这个字符串是唯一的

8、子组件向父组件传递数据,通过父组件定义一个事件传递给子组件,子组件在合适的时间去触发,同时将数据传递给父组件,在父组件中做相应的操作

子组件:

import React, { Component } from 'react';
import { nanoid } from 'nanoid'
import './index.css'

export default class Header extends Component {
    handleKeyUP = (e) => {
        // 事件对象将需要的属性解构
        const { target, keyCode } = e;
        if (keyCode !== 13) return;
        if (target.value.trim() === '') {
            alert('输入的内容不能为空');
            return
        }
        let data = {
            id: nanoid(),
            name: target.value,
            status: false
        }
        this.props.updateList(data);
    }
    render() {
        return (
            <div className='header'>
                <input type="text" placeholder="请输入需要做的事情" onKeyUp={this.handleKeyUP} />
            </div>
        )
    }
}

父组件:

import Header from './components/Header'
import List from './components/List'
import Footer from './components/Footer';
import './App.css';
import React, { Component } from 'react'

export default class App extends Component {
  state={
    todolist:[
      {
        id:1,
        name:'吃饭',
        status:true
      },
      {
        id:2,
        name:'睡觉',
        status:true
      },
      {
        id:3,
        name:'打游戏',
        status:false
      },
      {
        id:4,
        name:'追剧',
        status:true
      },
    ]
  }
  updateList = (data) =>{
    // 将原来的数据进行一个解构
    const {todolist} = this.state;
    // 新老数据的拼接
    const newTodolist = [data,...todolist];
    // 页面的更新
    this.setState({
      todolist:newTodolist
    })
  }
  render() {
    const {todolist} =this.state
    return (
      <div className="wrap">
      <Header updateList = {this.updateList}/>
      <List  todolist={todolist}/>
      <Footer />
    </div>
    )
  }
}

9、状态在哪里,操作状态的方法就在哪里

10、想要拿到复选框以及单选框中的值,需要使用checked

11、todoList案例相关知识点

(1)拆分组件、实现静态组件,注意:className、style的写法

(2)动态初始化列表,如何确定将数据放在哪个组件的state中?

某个组件使用:放在其自身的state中;

某些组件使用:放在他们共同的父组件state中(官放称此操作为:状态提升)

(3)关于父子之间通信:

父组件给子组件传递数据:通过props传递;

子组件给父组件传递数据:通过props传递,要求父组件提前给子传递一个函数;

(4)注意defaultChecked和checked的区别,类似的还有:defaultValue和value;

(5)状态在哪里,操作状态的方法就在哪里

App.js

import Header from './components/Header'
import List from './components/List'
import Footer from './components/Footer';
import './App.css';
import React, { Component } from 'react'

export default class App extends Component {
  state = {
    todolist: [
      {
        id: 1,
        name: '吃饭',
        status: true
      },
      {
        id: 2,
        name: '睡觉',
        status: true
      },
      {
        id: 3,
        name: '打游戏',
        status: false
      },
      {
        id: 4,
        name: '追剧',
        status: true
      },
    ]
  }
  // 数据的一个添加操作
  updateList = (data) => {
    // 将原来的数据进行一个解构
    let { todolist } = this.state;
    // 新老数据的拼接
    let newTodolist = [data, ...todolist];
    // 页面的更新
    this.setState({
      todolist: newTodolist
    })
  }

  //更改其中一个数据的状态
  changeStatus = (id, status) => {
    let { todolist } = this.state;
    //将id相同的一项进行改变,其余的数据都不变
    let newTodolist = todolist.map(todo => {
      if (todo.id === id) {
        return { ...todo, status }
      } else {
        //  不相同的时候,则直接返回即可,无需做其它的操作
        return todo
      }
    })
    // 更新数据
    this.setState({
      todolist: newTodolist
    })
  }
  // 将选中的一条数据进行删除删除
  delete = (id) => {
    let { todolist } = this.state;
    // let index = todolist.findIndex((todo)=>{
    //     return todo.id === id;
    // })
    //  let newTodolist = [];
    //  //数据遍历
    //  for(let i = 0 ; i < todolist.length ; i++){
    //    if( i !== index){
    //      newTodolist.push(todolist[i])
    //    }
    //  }
    //  //数据更新
    //  this.setState({
    //   todolist:newTodolist
    // })
    // 还可以利用数组中提供的filter方法进行以上的操作
    let newTodolist = todolist.filter(item => {
      return item.id !== id
    })
    // 将数据更新到页面上面
    this.setState({
      todolist: newTodolist
    })
  }
  allCheck = (status) => {
    let { todolist } = this.state;
    let newTodolist = todolist.map(item => {
      return { ...item, status }
    });
    this.setState({
      todolist: newTodolist
    })
  }
  //将数据中已经完成的数据删除
  clearDone = () => {
    let { todolist } = this.state;
    let newTodolist = todolist.filter(item =>{
      return item.status === false
    })
    this.setState({
      todolist:newTodolist
    })

  }
  render() {
    const { todolist } = this.state
    return (
      <div className="wrap">
        <Header updateList={this.updateList} />
        <List todolist={todolist} changeStatus={this.changeStatus} delete={this.delete} />
        <Footer todolist={todolist} allCheck={this.allCheck} clearDone={this.clearDone} />
      </div>
    )
  }
}

Header.js

import React, { Component } from 'react';
import { nanoid } from 'nanoid'
import './index.css'

export default class Header extends Component {
    handleKeyUP = (e) => {
        // 事件对象
        const { target, keyCode } = e;
        if (keyCode !== 13) return;
        if (target.value.trim() === '') {
            alert('输入的内容不能为空');
            return
        }
        let data = {
            id: nanoid(),
            name: target.value,
            status: false
        }
        this.props.updateList(data);
    }
    render() {
        return (
            <div className='header'>
                <input type="text" placeholder="请输入需要做的事情" onKeyUp={this.handleKeyUP} />
            </div>
        )
    }
}

List.js

import React, { Component } from 'react'
import './index.css'

export default class List extends Component {
    //当状态发生变化时的操作
    handleCheck = (id) =>{
        return (e)=>{
         //console.log(id,e.target.checked);
          this.props.changeStatus(id,e.target.checked)
        }
    }

    // 当点击删除时候的操作
    delete = (id) =>{
        return () =>{
        if(window.confirm('确定删除吗?'))
        this.props.delete(id);
        }
    }
    render() {
        
        const {todolist} = this.props;
        return (
            <ul className='clearfix'>
                {todolist.map(todo =>{
                    return (<li className="list" key={todo.id}>
                        {/* 当选中的状态进行改变的时候 */}
                    <input type="checkbox" checked={todo.status} onChange={this.handleCheck(todo.id)}/>
                    <p>{todo.name}</p>
                    <button onClick={this.delete(todo.id)}>删除</button>
                </li>)
                })}
            </ul>
        )
    }
}

Footer.js

import React, { Component } from 'react'
import './index.css'

export default class Footer extends Component {
    // 全选按钮回到函数
    handleAllCheck = (e) => {
        this.props.allCheck(e.target.checked);
    }
    // 清除已经完成的任务
    handleClearDone = ()=>{
         this.props.clearDone();
        }
    render() {
        const {todolist} =  this.props;
        const newList = todolist.filter( item =>{
            return item.status === true;
        });
        const doneCount = newList.length;
        const allCount = todolist.length;
        return (
            <div className='footer'>
                <div className='left'>
                    <input type="checkbox" onChange={this.handleAllCheck}  checked={ doneCount === allCount && allCount !== 0 ? true : false}/>
                    <p>已完成{doneCount}/全部{allCount}</p>
                </div>
                <button onClick={this.handleClearDone}>清除已完成任务</button>
            </div>
        )
    }
}

12、脚手架配置代理

方式一:在package.json中,添加

“proxy”:“http://localhost:5000”

说明:

优点:配置简单,前端请求资源时可以不加任何前缀;

缺点:不能配置多个代理;

工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000(优先匹配前端资源)

方式二:在src目录中,添加setupProxy.js

在这个文件中需要时CJS语法

const proxy = require('http-proxy-middleware');
module.exports = function(app){
app.use(
    proxy('/api1',{//遇见/api1前缀的请求,就会触发该代理配置
    target:'http://localhost:5000',//请求转发给谁
    changeOrigin:true,//控制服务器收到的请求头中Host的值
    pathRewrite:{
    '^/api1':''
    }//重写请求路径(必须)
    })
   ),
    proxy('/api2',{
    target:'http://localhost:5001',
    changeOrigin:true,
    pathRewrite:{
    '^/api2':''
    }
    })
   )
}

说明:

优点:可以配置多个代理,可以灵活的控制请求是否走代理;

缺点:配置繁琐,前端请求资源时必须加前缀;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值