react框架简单总结

脚手架

  • 安装脚手架:npm install -g create-react-app
  • 修改镜像源:npm config set registry registry.npm.taobao.org
  • 创建项目:npx create-react-app my-app
  • 进入到目录:cd my-app
  • 启动项⽬:npm start
  • 暴露配置项:npm run eject

初识react

1.将src下的所有文件都删除,
2.将public文件下除列favicon.ico和index.html之外的文件都删除掉
修改index.html文件
3.我们需要删除选中的内容
4.这两行内容是我们之前引入的一个图标和manifest文件
在这里插入图片描述
5.在src目录下,
6.在index.js中开始编写React代码

import React from "react";
import ReactDOM from 'react-dom';

ReactDOM.render(<h2>Hello React</h2>, document.getElementById("root"));

7.如果我们不希望直接在 ReactDOM.render 中编写过多的代码,就可以单独抽取一个组件App.js

import React, { Component } from 'react';

export default class App extends Component {
  render() {
    return <h2>Hello App</h2>
  }
}

8.在index.js中引入App,并且使用它

import React from "react";
import ReactDOM from 'react-dom';

import App from './App';

ReactDOM.render(<App/>, document.getElementById("root"));

在这里插入图片描述

核心基础

1.基础结构
在这里插入图片描述
2.两个入口
在这里插入图片描述
3.安装vscode插件
可愉快的使用rcc rfc imp等快捷键…
分别用来创建类组件,函数式组件,和导入文件

4.jsx基础语法

import React from 'react';
import ReactDOM from 'react-dom';
// import App from './App';

const jsx = <div>hello world</div>
ReactDOM.render(jsx,document.querySelector('#root'))

5.{}
在这里插入图片描述
6.对象
在这里插入图片描述
7.条件语句
在这里插入图片描述
8.数组
在这里插入图片描述
9.属性的使⽤
在这里插入图片描述

组件

  1. 函数式组件
export function About(){
	....
}
  1. 类组件(常用)
    一个登录界面,包含获取antd输入框值和路由跳转的小功能
import React,{Component} from 'react';
import logo from '../images/1.png'
import '../assets/login.css'
import {Button,Form, Input } from 'antd'
import { UserOutlined, LockOutlined } from '@ant-design/icons';

export default class Login extends Component{
    constructor(props){
        super(props)
        this.state = {
            username:'',
            password:''
        }
    }
    handleSubmit = (obj) => {
        // react中的跳转页面的方法
        this.props.history.replace('/admin')
    };
    handleChange = (name,val) => {
        this.setState({
            [name]:val
        })
    };
    render(){
        return (
            <div>
                <header>
                    <img src={logo}/>
                    <span>后台管理系统</span>
                </header>
                <div className='loginContainer'>
                    <h2>立即登录</h2>
                    <Form
                        onFinish={(values) => this.handleSubmit(values)}
                        >
                        <Form.Item>
                            <Input prefix={<UserOutlined/>} placeholder="用户名" onChange={val => this.handleChange('username',val)}/>
                        </Form.Item>
                        <Form.Item>
                            <Input
                                prefix={<LockOutlined/>}
                                type="password"
                                placeholder="密码"
                                onChange={val => this.handleChange('password',val)}
                            />
                        </Form.Item>
                        <Form.Item>
                            <Button type="primary" htmlType="submit">登录</Button>
                        </Form.Item>
                    </Form>
                </div>
            </div>
        )
    }
}

事件处理(this问题的三大方案)

1.bind(this)
2.定义方法后使用箭头函数
3.定义方法时使用箭头函数
在这里插入图片描述

生命周期

在这里插入图片描述

通信

父子传递数据
class App extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            todos:['美术','数学'],
        }
        this.addTodo = this.addTodo.bind(this)
    }
    addTodo(todo){
        const {todos} = this.state;
        todos.unshift(todo)
        this.setState({todos})
    }
    render(){
        const {todos} = this.state;
        return (
            <div>
                <h1>Simple todo list</h1>    
                //父向子传递数据(函数也可看作数据)
                <Add addTodo={this.addTodo}/>
                <List todos={todos}/>
            </div>
        )
    }
}
class Add extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            value:''
        }
    }
    handleAdd = () => {
        const {addInput} = this.refs;
        // 子向父传递数据
        this.props.addTodo(addInput.value);
        // 清空输入框内容
        addInput.value = '';
    }
    render(){
        return (
            <div>
                <input type="text" ref='addInput'/>    
                <button onClick={this.handleAdd}>add</button>
            </div>
        )
    }
}
class List extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        const {todos} = this.props;
        return (
            <ul>
                {todos.map((todo,index) => <li key={index}>{todo}</li>)}
            </ul>
        )
    }
}

ReactDOM.render(<App />,document.querySelector('#app'))

setState

  • setState在生命周期中是异步的
  • setState在合成事件是异步的
  • 在this.setState(object,callback)中的回调函数中可以是同步的
  • setState在setTimeout中是同步的
    只需要关注打印的结果即可
 class State extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            counter:0
        }
    }
    // componentDidMount(){
    //     setState在生命周期中是异步的
    //     this.changeValue(1)
    // }
    setCounter = () => {
        // setState在复合事件中是异步的
        // this.changeValue(1)
        // setState在定时器中是同步的
        setTimeout(() => {
            this.changeValue(1)
        }, 0);
    }
    changeValue = v => {
        // this.setState(object,callback)中是同步的
        // this.setState({
        //     counter:this.state.counter + v
        // },()=>{
        //     console.log(this.state.counter);
        // })
        this.setState({
            counter:this.state.counter + v
        })
        console.log(this.state.counter);
    }
    render(){
        return (
            <div>
                <button onClick={this.setCounter}>异步</button>    
            </div>
        )
    }
}
ReactDOM.render(<State/>,document.querySelector('#root'))
为什么设计setState为异步

显著提升性能

1.如果每次调用setState都进行一次更新,那么意味着render函数或被频繁调用,界面重新渲染,效率较低。
2.最好的方法应该是获取多个更新的操作,之后进行批量更新。

如果同步更新了state,但是还没有执行render函数,那么stste和props不能保持同步,会在开发中产生很多问题,如父组件的state改变了而render还未完成导致子组件props的值未能同步。

react更新机制

  • props/state改变
  • render函数重新执行
  • 生产新的虚拟DOM树
  • 新旧虚拟DOM树进行Diff
  • 计算出差异进行更新
  • 更新到真实的DOM

1.同层节点之间相互比较
2.不同类型的节点,产生不同的树结构然后直接删除替换
3.同一类型节点:className修改只会更新className,style中某个属性修改只会更新某个属性
4.同类型组件:更新该组件的Props,调用组件render函数,继续Diff递归比较
5.开发中,可以通过key来指定哪些节点在不同渲染下保持稳定
6.对于列表修改数据往最后添加一条数据,最后的数据会生成一个mutation,最终将其插入DOM树即可。此时添加key意义不是很大
7.对于列表修改数据往前面或中间添加一条数据,React会对每一个子元素产生一个mutation,此时key的意义就重大了,存在key时会进行key的匹配,会产生位移的操作,可以减少不必要的更新

组件优化

先看一下代码
每次点击按钮 23 和39行全部打印了

class A extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            name:'小明'
        }
    }
    render(){
        console.log('A组件RENDER');
        return (
            <div>
                <p>我是A组件</p>
                <p>{this.state.name} </p>   
                <button onClick={this.changeName}>修改</button>
                <B></B>
            </div>
        )
    }
    changeName = () => {
        this.setState({})  //徐晃一枪 发现23 和39行全部打印了
    }
}
class B extends React.Component{
    render(){
        console.log('B组件RENDER');
        return (
            <div>
                我是B组件    
            </div>
        )
    }
}

ReactDOM.render(<A />,document.querySelector('#app'))

两个问题

  • 只要执行setState(),即使不改变状态数据, 组件也会重新render() ==> 效率低
  • 只要当前组件重新render(), 就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==> 效率低

出现问题的原因就是上面react更新机制第四点提到的,当执行了setState(),就会执行render,render时发现有组件执行组件的render,导致不必要的更新

效率高的做法
只有当组件的state或props数据发生改变时才重新render()
原因
Component中的shouldComponentUpdate()总是返回true

方案一

  1. 重写shouldComponentUpdate()方法
  2. 比较新旧state或props数据, 如果有变化才返回true, 如果没有返回false,如果state数据多的话这个方案是不可行的

每次点击按钮 由于shouldComponentUpdate返回的是false,就不会执行更新操作,进而不会执行render方法

class A extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            name:'小明'
        }
    }
    shouldComponentUpdate(nextProps,nextState){
        // console.log(nextProps,nextState);
        return !(this.state.name == nextState.name);
    }

    render(){
        console.log('A组件RENDER');
        return (
            <div>
                <p>我是A组件</p>
                <p>{this.state.name} </p>   
                <button onClick={this.changeName}>修改</button>
                <B name={this.state.name}></B>
            </div>
        )
    }
    changeName = () => {
        this.setState({})
    }
}
class B extends React.Component{
    shouldComponentUpdate(nextProps,nextState){
        // console.log(nextProps,nextState);
        return !(this.props.name == nextProps.name);
    }
    render(){
        console.log('B组件RENDER');
        return (
            <div>
                <p>我是B组件</p>    
                <p>{this.props.name}</p>
            </div>
        )
    }
}
ReactDOM.render(<A />,document.querySelector('#app'))

附上一段源码
在这里插入图片描述

方案二

1.使用PureComponent
2. PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true
3. 解决不了函数式组件(使用memo解决)

注意:

  • 只是进行state和props数据的浅比较, 如果只是数据对象内部数据变了, 返回false
  • 不要直接修改state数据, 而是要产生新数据
    在这里插入图片描述在这里插入图片描述
class A extends React.PureComponent{
    constructor(props){
        super(props)
        this.state = {
            name:'小明'
        }
    }

    render(){
        console.log('A组件RENDER');
        return (
            <div>
                <p>我是A组件</p>
                <p>{this.state.name} </p>   
                <button onClick={this.changeName}>修改</button>
                <B name={this.state.name}></B>
            </div>
        )
    }
    changeName = () => {
    	//会触发两个组件的render方法
        this.setState({
            name:'黄杰'  
        })
    }
}
class B extends React.PureComponent{
    render(){
        console.log('B组件RENDER');
        return (
            <div>
                <p>我是B组件</p>    
                <p>{this.props.name}</p>
            </div>
        )
    }
}
ReactDOM.render(<A />,document.querySelector('#app'))
class A extends React.PureComponent{
    constructor(props){
        super(props)
        this.state = {
            name:'小明'
        }
    }
    render(){
        console.log('A组件RENDER');
        return (
            <div>
                <p>我是A组件</p>
                <p>{this.state.name} </p>   
                <button onClick={this.changeName}>修改</button>
                <B name={this.state.name}></B>
            </div>
        )
    }
    changeName = () => {
    	//无效,PureComponent是浅比较 必须修改的是一个新的地址 而不是旧的引用地址
        const obj = this.state;
        obj.name = '黄杰'
        this.setState(obj)
    }
}
class B extends React.PureComponent{
    render(){
        console.log('B组件RENDER');
        return (
            <div>
                <p>我是B组件</p>    
                <p>{this.props.name}</p>
            </div>
        )
    }
}
ReactDOM.render(<A />,document.querySelector('#app'))

函数式组件的优化-memo

每次点击按钮 A组件的render方法依旧会执行 但是B组件不会执行 如果是普通函数组件 B组件render是会执行的

class A extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            name:'小明'
        }
    }
    render(){
        console.log('A组件RENDER');
        return (
            <div>
                <p>我是A组件</p>
                <p>{this.state.name} </p>   
                <button onClick={this.changeName}>修改</button>
                <B name={this.state.name}></B>
            </div>
        )
    }
    changeName = () => {
        this.setState({})
    }
}
const B = React.memo((props) => {
    console.log('B组件render');
    return (
        <div>
            <p>我是B组件</p>
            <p>{props.name}</p>
        </div>
    )
})
ReactDOM.render(<A />,document.querySelector('#app'))

使用context解决爷爷向孙子传递数据的问题

两个地方要注意:

  1. 使用context后必须使用PropTypes进行强校验
  2. 爷爷要使用childContextTypes对象和getChildContext()函数
  3. 孙子要使用contextTypes上下文type来获取数据
import React from "react";

import PropTypes from 'prop-types';

class SideBar extends React.Component{
    render(){
        return (
            <div>
                <p>侧边栏</p>
                <Navbar></Navbar>
            </div>
        )
    }
}

class Navbar extends React.Component{
    static contextTypes = {
        obj:PropTypes.object.isRequired
    }
    render(){
        return (
            <div>{this.context.obj.name}的侧边栏</div>
        )
    }
}

export class Page extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            name:'蜗牛'
        }
    }
    static childContextTypes = {
        obj:PropTypes.object.isRequired
    }
    getChildContext(){
        return {obj:this.state}
    }
    render(){
        return (
            <div>
                我是一个{this.state.name}
                <SideBar/>
            </div>
        )
    }
}

手写一个简单的redux

./redux.js

// 手写redux源码 最简代码
/**
 * redux中几个重要的组成 getState subscribe dispatch 
 */
export function createStore(reducer){
    let currentState = {};
    let currentListener = [];

    function getState(){
        return currentState;
    }
    
    function subscribe(listen){
        currentListener.push(listen);
    }

    function dispatch(action){
        currentState =- reducer(currentState,action);
        currentListener.forEach(v => v());
        return action;
    }

    // 初始化时执行一次得到initState 因为该type匹配不到
    dispatch({type:'@IMOOC/WONIU-REDUX'})
    return {getState,subscribe,dispatch}
}

./reducer.js

import {createStore} from './redux';

// 这就是reducer处理函数,参数是状态和新的action
function counter(state=0, action) {
  console.log(state, action)
  switch (action.type) {
    case '加机关枪':
      return state + 1
    case '减机关枪':
      return state - 1
    default:
      return 100
  }
}
// 新建保险箱
const store = createStore(counter)
const init = store.getState()
console.log(`一开始有机枪${init}`)
function listener(){
  const current = store.getState()
  console.log(`现在有机枪${current}`)
}
// 订阅,每次state修改,都会执行listener
store.subscribe(listener)
// 提交状态变更的申请
store.dispatch({ type: '加机关枪' })
store.dispatch({ type: '加机关枪' })
store.dispatch({ type: '加机关枪' })
store.dispatch({ type: '减机关枪' })
store.dispatch({ type: '减机关枪' })

react-redux使用

如果要使用装饰器模式@符号,
首先要执行命令 npm i eject来暴漏一些文件,然后再package.json文件中的babel栏目配置:

"plugins":[
  [
    "@babel/plugin-proposal-decorators",
    {
      "legacy": true
    }
  ]
]

/index.js文件

import React from "react";
import ReactDOM from "react-dom";
import App from './App';
import { createStore,applyMiddleware } from "redux";
import {counter} from "./index.redux";
// 处理异步操作
import thunk from "redux-thunk";
import { Provider } from "react-redux";

const store = createStore(counter,applyMiddleware(thunk));

ReactDOM.render(
    <Provider store={store}>
        <App/>
    </Provider>,
    document.querySelector('#root')
);

/index.redux.js 抽离出来的redux文件

//actionType
const ADD = 'ADD'
const SUB = 'SUB'

export function counter(state = 0,action){
    switch (action.type) {
        case ADD:
            console.log(action);
            return state+1;
        case SUB:
            console.log(action);
            return state-1;
        default:
            return 10;
    }
}
// actionCreator
export function add(){
    return {type:ADD}
}
export function sub(){
    return {type:SUB}
}

// 处理异步请求必须使用react-thunk
export function addAsync(){
    return dispatch => {
        setTimeout(() => {
            dispatch(add())
        }, 1000);
    }
}

/app.js文件中,需要用到store的组件中

import React from "react";
import { connect } from "react-redux";

import {add,sub,addAsync} from './index.redux'

@connect(
    state => ({num:state}),
    {add,sub,addAsync}
)
class App extends React.Component{
    render (){
        let add = this.props.add;
        let sub = this.props.sub;
        let addAsync = this.props.addAsync;
        let num = this.props.num;
        return (
            <div>
                <h2>现在的数字是{num}</h2>
                <button onClick={()=>add()}>1</button>
                <button onClick={()=>sub()}>1</button>
                <button onClick={()=>addAsync()}>1秒会加1</button>
            </div>
        )
    }
}

export default App;

react-router-dom使用

最好使用以下版本 @^5.3.0 最新版Redirect标签不可用

Route是搭配path和component使用
Link,Redirect是搭配to使用

 <BrowserRouter>
     <Switch>
         <Route path='/login' component={Auth}></Route>
         <Route path='/dashboard' component={Dashboard}></Route>
         <Redirect to='/dashboard'></Redirect>
     </Switch>
 </BrowserRouter>
 
 <div>
     <ul>
         <li><Link to='/dashboard/'>一营</Link></li>
         <li><Link to='/dashboard/erying'>二营</Link></li>
         <li><Link to='/dashboard/qibinglian'>骑兵连</Link></li>
     </ul>
     <Switch>
         //但路由最后是以/结尾时,一般要加上exact配合使用
         <Route path='/dashboard/' exact component={App}></Route>
         <Route path='/dashboard/erying' component={Erying}></Route>
         <Route path='/dashboard/qibinglian' component={Qibinglian}></Route>
     </Switch>
 </div>

临时想到几个点:

  1. 当组件不是路由组件时,想得到路由信息,要引入withRouter 从’react-router-dom’引入
  2. 子路由获取方式为this.props.match.params.user
<Route path='/chat/:user' component={Chat}></Route>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue和React都是非常流行的前端框架,它们各有优缺点,下面是它们的主要特点: Vue的优点: 1. 简单易学:Vue的API设计简单易懂,上手较为容易。 2. 渐进式框架:Vue可以逐渐应用到一个已有的项目中,也可以构建单页应用。 3. 双向数据绑定:Vue支持双向数据绑定,可以自动更新视图。 4. 组件化开发:Vue的组件化开发方式更加灵活,可以更好的复用代码。 5. 官方工具链:Vue提供了一整套的官方工具链,包括脚手架、测试工具等。 Vue的缺点: 1. 生态系统相对React较小:相比React,Vue的生态系统还不够完善。 2. 限制较多:Vue对于一些高级的特性和用法的支持相对较少。 3. 性能问题:在处理大量数据时性能会受到影响。 React的优点: 1. 适用范围广:React可以应用于Web、移动端、VR等多个平台。 2. 生态系统完善:React的生态系统非常完善,有大量的第三方库和插件。 3. 高度灵活:React的API设计非常灵活,开发者可以根据需要自由选择使用。 4. 虚拟DOM:React使用虚拟DOM来提高渲染性能。 5. 服务器渲染:React支持服务器端渲染,可以提高首屏渲染速度。 React的缺点: 1. 学习曲线较陡峭:React的API设计相对复杂,需要一定的学习成本。 2. JSX语法:React使用JSX语法,需要学习一种新的语言。 3. 不支持双向数据绑定:React不支持双向数据绑定,需要手动管理组件状态。 4. 不完全组件化:React的组件化开发方式相对Vue略有不足。 总结: Vue和React各有优缺点,开发者可以根据自己的需求和项目特点选择合适的框架。如果需要快速上手和开发小型项目,Vue可能是更好的选择;如果需要构建大型项目或跨平台应用,React可能会更适合一些。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值