06-React状态管理 Redux(工作流程, 核心概念, 求和案例, 异步Action, React-Redux, 多状态管理, 纯函数, 高阶函数, Redux开发者工具)

2022-08-24 08:41:08 浏览数 (1)

Redux

简介

其实就是一个集中的状态管理技术, 类似于VueX, 以及后端的分布式配置中心, 在前端的文章里提后端,是不是不太好~, 但是能学习这个技术的人, 从简短的一句话中应该就已经简单的了解了这个技术,以及它的使用情况, 我就不过多写概念了, 主要写使用方式

Redux工作流程

三个核心概念

Action

  • 动作对象
  • 包含两个属性

字段

作用

数据类型

是否唯一

是否必填

type

标识属性

字符串

data

数据属性

任意

代码语言:javascript复制
{
  "type":"add",
  "data:":{
    "name":"flower",
    "age":18
  }
}

Reducer

  • 用于初始化状态, 加工状态
  • 加工时, 依据旧的state和action,产生新的state的纯函数

Store

  • 将state, action, reducer 联系在一起的对象
  • 如何获取:
代码语言:javascript复制
import {createStore} from 'redux'
import reducer from './reducers'
const store = createStore(reducer)
  • 此对象的功能

函数

参数

作用

getState()

获取state

dispatch(action)

action对象

分发action,处罚reducer调用,产生新的state

subscribe(listener)

listener对象

注册监听,当产生新的state时,自动调用

添加依赖

代码语言:javascript复制
yarn add redux

求和案例

React版本

代码语言:javascript复制
import React, {Component} from 'react';

class Count extends Component {
    state = {
        count: 0
    }

    render() {
        return (
            <div style={{textAlign: 'center'}}>
                <h1>当前求和为:{this.state.count}</h1>
                <select ref={c => this.count = c} style={{width: '50px'}}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button style={{marginLeft: '10px'}} onClick={this.sum('add')}> </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('re')}>-</button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('j')}>当前求和为奇数 </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('async')}>异步 </button>
            </div>
        );
    }

    sum = type => {
        return event => {
            let {value} = this.count
            value = parseInt(value)
            let {count} = this.state
            if (type === 'add') {
                count = count   value
                this.setState({count})
                return
            }
            if (type === 're') {
                count = count - value
                this.setState({count})
                return
            }
            if (type === 'j') {
                if (count % 2 !== 0) {
                    count = count   value
                    this.setState({count})
                }
                return;
            }
            if (type === 'async') {
                count = count   value
                setTimeout(() => {
                    this.setState({count})
                }, 2000)
            }

        }
    }
}

export default Count;

Redux精简版

创建store.js

代码语言:javascript复制
/**
 * 1: 引入createStore
 * 2: 引入为自定义组件服务的reducer
 * 3: 对外暴露store
 */
import {legacy_createStore as createStore} from 'redux'
import countReducer from './count_reducer'

export default createStore(countReducer)

创建count_reducer.js

代码语言:javascript复制
/**
 * 1: 该文件是用于创建一个为Count组件服务的reducer, reducer的本质就是一个函数
 * 2: reducer函数会接收到两个参数, 分别为: 之前的状态(preState), 动作对象(action)
 */
const initValue = 0
export default function countReducer(preState = initValue, action) {
    const {type, data} = action
    if (type === 'add')
        return preState   data
    if (type === 're')
        return preState - data

    return preState
}

使用redux改造原有Count组件

代码语言:javascript复制
import React, {Component} from 'react';
import store from "../../redux/count/store";

class Count extends Component {
    componentDidMount() {
        // 检测Redux中状态的变化, 只要变化, 就调用Render
        store.subscribe(()=>{
            // 调用刷新页面函数, 啥也不干就 重新渲染一下render
            this.forceUpdate()
        })
    }
    render() {
        return (
            <div style={{textAlign: 'center'}}>
                <h1>当前求和为:{store.getState()}</h1>
                <select ref={c => this.count = c} style={{width: '50px'}}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button style={{marginLeft: '10px'}} onClick={this.sum('add')}> </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('re')}>-</button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('j')}>当前求和为奇数 </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('async')}>异步 </button>
            </div>
        );
    }

    sum = type => {
        return event => {
            let {value} = this.count
            value = parseInt(value)
            if (type === 'add') {
                store.dispatch({type:'add',data:value})
            }
            if (type === 're') {
                store.dispatch({type:'re',data:value})
            }
            if (type === 'j') {
                if (store.getState() % 2 !== 0) {
                    store.dispatch({type:'add',data:value})
                }
            }
            if (type === 'async') {
                setTimeout(() => {
                    store.dispatch({type:'add',data:value})
                }, 2000)
            }
        }
    }
}

export default Count;

函数小结

函数

参数

作用

getState()

获取state

dispatch(action)

action对象

分发action,处罚reducer调用,产生新的state

subscribe(listener)

listener对象

注册监听,当产生新的state时,自动调用

Redux完整版

对面上的案例进行改造

新增常量constant.js

代码语言:javascript复制
/**
 * 该模块用于定义action对象的type类型, 统一管理常量值
 */
export const ADD = 'add';
export const RE = 're';

改造reducer, 引入常量

代码语言:javascript复制
/**
 * 1: 该文件是用于创建一个为Count组件服务的reducer, reducer的本质就是一个函数
 * 2: reducer函数会接收到两个参数, 分别为: 之前的状态(preState), 动作对象(action)
 */
import {ADD, RE} from "./constant";

const initValue = 0
export default function countReducer(preState = initValue, action) {
    const {type, data} = action
    console.log(preState, action)
    if (type === ADD)
        return preState   data
    if (type === RE)
        return preState - data

    return preState
}

新增count_action.js

代码语言:javascript复制
/**
 * 该文件专门为Count组件生成Action对象
 */
import {ADD, RE} from './constant'

export const creatAddAction = data => ({type: ADD, data})
export const creatReAction = data => ({type: RE, data})

使用action函数替换传入的对象

代码语言:javascript复制
import React, {Component} from 'react';
import store from "../../redux/count/store";
import {creatAddAction, creatReAction} from "../../redux/count/count_action";

class Count extends Component {
    componentDidMount() {
        // 检测Redux中状态的变化, 只要变化, 就调用Render
        store.subscribe(()=>{
            // 调用刷新页面函数, 啥也不干就 重新渲染一下render
            this.forceUpdate()
        })
    }
    render() {
        return (
            <div style={{textAlign: 'center'}}>
                <h1>当前求和为:{store.getState()}</h1>
                <select ref={c => this.count = c} style={{width: '50px'}}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button style={{marginLeft: '10px'}} onClick={this.sum('add')}> </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('re')}>-</button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('j')}>当前求和为奇数 </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('async')}>异步 </button>
            </div>
        );
    }

    sum = type => {
        return event => {
            let {value} = this.count
            value = parseInt(value)
            if (type === 'add') {
                store.dispatch(creatAddAction(value))
            }
            if (type === 're') {
                store.dispatch(creatReAction(value))
            }
            if (type === 'j') {
                if (store.getState() % 2 !== 0) {
                    store.dispatch(creatAddAction(value))
                }
            }
            if (type === 'async') {
                setTimeout(() => {
                    store.dispatch(creatAddAction(value))
                }, 2000)
            }
        }
    }
}

export default Count;

异步Action

在调用dispatch的时候传入的action对象, 如果对象是Object, 那么就是同步的action, 如果是函数, 那么就是异步的action

添加依赖

代码语言:javascript复制
yarn add redux-thunk

编写异步函数

代码语言:javascript复制
/**
 * 该文件专门为Count组件生成Action对象
 */
import {ADD, RE} from './constant'

// 同步Action, 返回值为Object
export const creatAddAction = data => ({type: ADD, data})
export const creatReAction = data => ({type: RE, data})

// 所谓的异步Action,就是指所谓的返回值是函数
export const creatAsyncAddAction = (data,timeout) => dispatch => setTimeout(()=> dispatch(creatAddAction(data)) ,timeout)

设置Store支持函数

代码语言:javascript复制
/**
 * 1: 引入createStore
 * 2: 引入为自定义组件服务的reducer
 * 3: 对外暴露store
 */
import {legacy_createStore as createStore, applyMiddleware} from 'redux'
import countReducer from './count_reducer'
// 用于支持异步Action
import thunk from "redux-thunk";

export default createStore(countReducer,applyMiddleware(thunk))

修改Count组件

代码语言:javascript复制
if (type === 'async') {
  // setTimeout(() => {
  store.dispatch(creatAsyncAddAction(value, 500))
  // }, 2000)
}

去除setTimeout, 交由Store支持

React-Redux

简介

一看名称就是react自己写的, 应该是封装了redux,方便使用集成

工作流程

其实就是在Count组件外面包了一层用于和Redux做交互的容器, 用于获取数据和交互

添加依赖

代码语言:javascript复制
yarn add react-redux

使用react-redux实现求和案例

修改Count组件

代码语言:javascript复制
import React, {Component} from 'react';

class Count extends Component {

    render() {
        const {count} = this.props
        return (
            <div style={{textAlign: 'center'}}>
                <h1>当前求和为:{count}</h1>
                <select ref={c => this.count = c} style={{width: '50px'}}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button style={{marginLeft: '10px'}} onClick={this.sum('add')}> </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('re')}>-</button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('j')}>当前求和为奇数 </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('async')}>异步 </button>
            </div>
        );
    }

    sum = type => {
        return event => {
            let {value} = this.count
            value = parseInt(value)
            const {count, add, re, addAsync} = this.props
            if (type === 'add') {
                add(value)
            }
            if (type === 're') {
                re(value)
            }
            if (type === 'j') {
                if (count % 2 !== 0) {
                    add(value)
                }
            }
            if (type === 'async') {
                addAsync(value, 500)
            }
        }
    }
}

export default Count;

定义容器组件

代码语言:javascript复制
// 引入Count组件
import CountUI from "../../components/Count";
// 引入connect 用于连接UI和store
import {connect} from 'react-redux'
import {creatAddAction, creatAsyncAddAction, creatReAction} from "../../redux/count/count_action";

// 函数的返回值作为状态传递给了UI组件
const mapStateToProps = (state) => {
    return {
        count: state
    }
}
// 函数的返回值作为函数操作传递给了UI组件
const mapDispatchToProps = (dispatch) => {
    return {
        add: (data) => {
            dispatch(creatAddAction(data))
        },
        addAsync: (data,timeout) => {
            dispatch(creatAsyncAddAction(data,timeout))
        },
        re: (data) => {
            dispatch(creatReAction(data))
        }
    }
}

// 创建并暴露一个Count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(CountUI);

修改APP组件

代码语言:javascript复制
import React, {Component} from 'react';
import Count from "./containers/Count";
import store from "./redux/count/store";

class App extends Component {
    render() {
        return (
            <div>
                {/* 传入store对象 */}
                <Count store={store}/>
            </div>
        );
    }
}

export default App;

修改index组件

代码语言:javascript复制
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from "./redux/count/store";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);
// 订阅store状态更新
store.subscribe(()=>{
    root.render(<App/>)
})

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

优化求和案例

优化容器组件

代码语言:javascript复制
// 引入Count组件
import CountUI from "../../components/Count";
// 引入connect 用于连接UI和store
import {connect} from 'react-redux'
import {creatAddAction, creatAsyncAddAction, creatReAction} from "../../redux/count/count_action";

// 创建并暴露一个Count的容器组件
export default connect(
    state => ({
        count: state
    }),
    {
        add: creatAddAction,
        addAsync: creatAsyncAddAction,
        re: creatReAction
    }
)(CountUI);

原理

原来的是一个函数, 优化为一个对象, 直接返回一个action, 然后react-redux会自动调用dispatch进行action分发

优化Index组件

代码语言:javascript复制
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

可以将原来添加的监听删除了, 因为react-redux会自动监听redux的状态变化, 并重新渲染render

优化Store传入

将原有的APP组件中传入的store删除

代码语言:javascript复制
import React, {Component} from 'react';
import Count from "./containers/Count";

class App extends Component {
    render() {
        return (
            <div>
                {/* 传入store对象 */}
                <Count/>
            </div>
        );
    }
}

export default App;

修改Index组件

代码语言:javascript复制
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// 引入store   提供者
import store from "./redux/count/store";
import {Provider} from "react-redux";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <Provider store={store}>
        <App />
    </Provider>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

这样就可以将store传递给所有需要store的容器组件了

将UI组件和容器组件整合

代码语言:javascript复制
import React, {Component} from 'react';
// 引入connect 用于连接UI和store
import {connect} from 'react-redux'
import {creatAddAction, creatAsyncAddAction, creatReAction} from "../../redux/count/count_action";

class Count extends Component {

    render() {
        const {count} = this.props
        return (
            <div style={{textAlign: 'center'}}>
                <h1>当前求和为:{count}</h1>
                <select ref={c => this.count = c} style={{width: '50px'}}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button style={{marginLeft: '10px'}} onClick={this.sum('add')}> </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('re')}>-</button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('j')}>当前求和为奇数 </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('async')}>异步 </button>
            </div>
        );
    }

    sum = type => {
        return event => {
            let {value} = this.count
            value = parseInt(value)
            const {count, add, re, addAsync} = this.props
            if (type === 'add') {
                add(value)
            }
            if (type === 're') {
                re(value)
            }
            if (type === 'j') {
                if (count % 2 !== 0) {
                    add(value)
                }
            }
            if (type === 'async') {
                addAsync(value, 500)
            }
        }
    }
}

// 创建并暴露一个Count的容器组件
export default connect(
    state => ({
        count: state
    }),
    {
        add: creatAddAction,
        addAsync: creatAsyncAddAction,
        re: creatReAction
    }
)(Count);

这样就不用增加工作量了, 每次写容器都得写两个文件了

多组件状态管理 数据交互

上面一直在用一个Count组件玩, 并没有涉及到组件交互和多组件状态存储, 下面就来玩一下

完整案例

Index组件

代码语言:javascript复制
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// 引入store   提供者
import store from "./redux/count/store";
import {Provider} from "react-redux";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <Provider store={store}>
        <App />
    </Provider>
);
reportWebVitals();

App组件

代码语言:javascript复制
import React, {Component} from 'react';
import Count from "./containers/Count";
import Person from "./containers/Person";

class App extends Component {
    render() {
        return (
            <div>
                {/* 传入store对象 */}
                <Count/>
                <hr/>
                <Person />
            </div>
        );
    }
}

export default App;

Count容器组件 UI组件

代码语言:javascript复制
import React, {Component} from 'react';
// 引入connect 用于连接UI和store
import {connect} from 'react-redux'
import {creatAddAction, creatAsyncAddAction, creatReAction} from "../../redux/count/count_action";

class Count extends Component {

    render() {
        const {count,persons} = this.props
        return (
            <div style={{textAlign: 'center'}}>
                <h2>Count组件</h2>
                <h3>下方Person组件的值为</h3>
                <ul>
                    <li>姓名-年龄</li>
                    {
                        persons.map(person => {
                            return <li key={person.id}>{person.name "-" person.age}</li>
                        })
                    }
                </ul>
                <h4>当前求和为:{count}</h4>
                <select ref={c => this.count = c} style={{width: '50px'}}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button style={{marginLeft: '10px'}} onClick={this.sum('add')}> </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('re')}>-</button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('j')}>当前求和为奇数 </button>
                <button style={{marginLeft: '10px'}} onClick={this.sum('async')}>异步 </button>
            </div>
        );
    }

    sum = type => {
        return event => {
            let {value} = this.count
            value = parseInt(value)
            const {count, add, re, addAsync} = this.props
            if (type === 'add') {
                add(value)
            }
            if (type === 're') {
                re(value)
            }
            if (type === 'j') {
                if (count % 2 !== 0) {
                    add(value)
                }
            }
            if (type === 'async') {
                addAsync(value, 500)
            }
        }
    }
}

// 创建并暴露一个Count的容器组件
export default connect(
    state => ({
        count: state.count,
        persons: state.persons
    }),
    {
        add: creatAddAction,
        addAsync: creatAsyncAddAction,
        re: creatReAction
    }
)(Count);

Person容器组件 UI组件

代码语言:javascript复制
import React, {Component} from 'react';
import {connect} from "react-redux";
import {createAddPersonAction} from "../../redux/count/person_action";
import {nanoid} from "nanoid";

class Person extends Component {
    render() {
        const {persons,count} = this.props
        console.log(persons);
        return (
            <div style={{textAlign: 'center'}}>
                <h2>Person组件</h2>
                <h3>Count组件求和为:{count}</h3>
                <input ref={c => this.name = c} type="text" placeholder={"请输入姓名"}/>
                <input ref={c => this.age = c} type="text" placeholder={"请输入年龄"}/>
                <button onClick={this.addPerson}>添加</button>
                <ul>
                    <li>姓名-年龄</li>
                    {
                        persons.map(person => {
                            return <li key={person.id}>{person.name "-" person.age}</li>
                        })
                    }
                </ul>
            </div>
        );
    }
    addPerson = () => {
        const name = this.name.value
        const age = this.age.value
        const {addPerson} = this.props
        const person = {
            id:nanoid(),
            name,
            age
        }
        console.log(person);
        addPerson(person)

    }
}

export default connect(state=>({
    persons:state.persons,
    count:state.count
}),{
    addPerson: createAddPersonAction
})(Person)

常量JS

代码语言:javascript复制
/**
 * 该模块用于定义action对象的type类型, 统一管理常量值
 */
export const ADD = 'add';
export const RE = 're';
export const ADD_PERSON = 'add_person';

StoreJS

代码语言:javascript复制
/**
 * 1: 引入createStore
 * 2: 引入为自定义组件服务的reducer
 * 3: 对外暴露store
 */
import {legacy_createStore as createStore, applyMiddleware, combineReducers} from 'redux'
import countReducer from './count_reducer'
import personReducer from './person_reducer'
// 用于支持异步Action
import thunk from "redux-thunk";

// 使用combineReducers合并多个Reducer
// 字段:reducer
const allReducers = combineReducers({
    count:countReducer,
    persons:personReducer
})

export default createStore(allReducers,applyMiddleware(thunk))

Count Create Action

代码语言:javascript复制
/**
 * 该文件专门为Count组件生成Action对象
 */
import {ADD, RE} from './constant'

// 同步Action, 返回值为Object
export const creatAddAction = data => ({type: ADD, data})
export const creatReAction = data => ({type: RE, data})

// 所谓的异步Action,就是指所谓的返回值是函数
export const creatAsyncAddAction = (data,timeout) => dispatch => setTimeout(()=> dispatch(creatAddAction(data)) ,timeout)

Person Create Action

代码语言:javascript复制
import {ADD_PERSON} from "./constant";

export const createAddPersonAction = person => ({type:ADD_PERSON,data:person})

Count Reducer

代码语言:javascript复制
/**
 * 1: 该文件是用于创建一个为Count组件服务的reducer, reducer的本质就是一个函数
 * 2: reducer函数会接收到两个参数, 分别为: 之前的状态(preState), 动作对象(action)
 */
import {ADD, RE} from "./constant";

const initValue = 0
export default function countReducer(preState = initValue, action) {
    const {type, data} = action
    console.log(preState, action)
    if (type === ADD)
        return preState   data
    if (type === RE)
        return preState - data

    return preState
}

Person Reducer

代码语言:javascript复制
import {ADD_PERSON} from "./constant";

const initValue = []
export default function personHandler(preState = initValue, action) {
    const {type, data} = action
    if (type === ADD_PERSON) {
        return [data, ...preState]
    }
    return preState
}

效果

实现了多组件Store存储,并交互数据

纯函数

  • 一些特别的函数,只要是同样的输入(实参),必定得到同样的输出(返回)
  • 必须遵守以下的约束
    • 不得改写参数数据
    • 不会产生任何副作用, 例如网络请求, 输入和输出设备
    • 不能调用Date.now()或者Math,random等不纯的方法
  • redux的reducer函数必须是一个纯函数

高阶函数

  1. 理解: 一类特别的函数
    1. 情况1: 参数是函数
    2. 情况2: 返回是函数
  2. 常见的高阶函数:
    1. 定时器设置函数
    2. 数组的forEach()/map()/filter()/reduce()/find()/bind()
    3. promise
    4. react-redux中的connect函数
  3. 作用: 能实现更加动态, 更加可扩展的功能

Redux开发者工具

应为我也不能上Google只能粘贴一个文件夹了

添加依赖

代码语言:javascript复制
yarn  add redux-devtools-extension

修改StoreJs

代码语言:javascript复制
/**
 * 1: 引入createStore
 * 2: 引入为自定义组件服务的reducer
 * 3: 对外暴露store
 */
import {legacy_createStore as createStore, applyMiddleware, combineReducers} from 'redux'
import countReducer from './count_reducer'
import personReducer from './person_reducer'
// 用于支持异步Action
import thunk from "redux-thunk";
// 引入Redux开发者工具
import {composeWithDevTools} from 'redux-devtools-extension'


// 使用combineReducers合并多个Reducer
// 字段:reducer
const allReducers = combineReducers({
    count:countReducer,
    persons:personReducer
})
// 调用
export default createStore(allReducers,composeWithDevTools(applyMiddleware(thunk)))

效果

可以记录组件的action执行和值的变化

React项目打包部署

代码语言:javascript复制
yarn build
代码语言:javascript复制
E:jsreact_redux>yarn build
yarn run v1.22.19
$ react-scripts build
Creating an optimized production build...
Compiled successfully.

File sizes after gzip:

  53.7 kB  buildstaticjsmain.555f55e7.js
  1.79 kB  buildstaticjs787.a95b438b.chunk.js
  264 B    buildstaticcssmain.e6c13ad2.css

The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.

The build folder is ready to be deployed.
You may serve it with a static server:

  yarn global add serve
  serve -s build

Find out more about deployment here:

  https://cra.link/deployment

Done in 11.82s.

E:jsreact_redux>

打包完成后会生成一个build文件夹, 我记得Vue应该是dist

代码语言:javascript复制
npm -i serve -g

全局安装serve 当然, 真的上线也不是这么玩的, 一般前端上线都是挂在Nginx下的, 这里这个就是为了本地启动一个服务

代码语言:javascript复制
E:jsreact_redux>npm i serve -g
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.

added 89 packages, and audited 90 packages in 21s

23 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

E:jsreact_redux>

进入到项目文件夹执行 serve build(文件名) 就可以启动一个服务

这样就可以访问了

并且React的图标也变为线上模式了,而不是debug模式了

0 人点赞