React入门从项目搭建webpack到引入路由reactrouter和状态管理reactredux

8次阅读

共计 6628 个字符,预计需要花费 17 分钟才能阅读完成。

一、什么是 React

React 是什么?React 的官网是这样介绍的:
React- 用于构建用户界面的 JavaScript 库。
看起来十分简洁,React 仅仅是想提供一个构建用户界面的工具,也就是只关心 UI 层面,不关心数据层面,数据层面的东西交给专门的人 (react-redux) 来做。所以有些人会说 React 就是一个 ui 框架。
React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。所以,React 提供了 jsx 语法,也可以理解为让你在 ul组件 里写很多东西。jsx 最终是通过 babel 将组件转化为 React.createElement()函数来调用。组件化开发的乐趣需要慢慢体会。既然是 入门 ,下面通过 搭建项目 - 小例子 - 引入路由 / 状态管理 简单介绍下 react,有关复杂的概念这里暂不提及。

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

ReactDOM.render(
  element,
  document.getElementById('root')
);

二、项目搭建

上面说了,react 的组件开发是需要 babel 进行编译的,浏览器是不能直接解析的,所以 react 项目一般都是需要做一些简单的配置的。当然,有很多的配置完善的脚手架可以使用,比如官方脚手架 creat-react-app 或者蚂蚁金服的 dva 框架,使用起来都是很方便上手。但是咱们我觉得通过简单搭建一个项目可以更好的理解 react。下面将会通过 webpack 一步一步搭建一个可以使用的项目,但是 具体的优化 这里就先不考虑了。

1. 打开终端、创建项目

mkdir react-demo && cd react-demo // 创建文件夹,并进入文件夹

2. 初始化构建

npm init // 为了后面下载 npm 包和 node 配置使用
         // 一路回车键就可以了!项目中多出来一个 package.json 文件

3. 创建项目入口

新建 app.js 文件,引入 react 和 react-dom,新建一个 index.html, 包含 <div id=’app’></div>。

    import React from 'react'; // 终端执行 npm i react 下载 react
    import ReactDom from 'react-dom' // 终端执行 npm i react-dom 下载 react-dom
    
    function App(){ // 以函数的方式创建 react 组件
        return <div>welcom,react-app</div>
    }
    
    ReactDom.render( // 将组件 App 渲染挂载到页面的根节点 app
        <App />,
        document.getElementById('app')// 所以需要新建一个 html 文件提供 app 节点供组件挂载
    )

3.webpack 配置

创建好入口文件 app.js 后,需要将 jsx 语法文件通过 babel 编译,所以先引入 webpack,并新建 js 文件 webpack.config.js 做相关的配置如下:

npm i webpack webpack-cli --save // 安装 webpack 及 cli 依赖

webpack.config.js 文件内容:const path = require("path");
const {CleanWebpackPlugin} = require('clean-webpack-plugin');// 通过 npm 安装
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
module.exports = {
    entry:{app:'./app.js'},
    output: {path: path.resolve(__dirname, './dist'),
        filename: '[name].bundel.[hash].js'
    },
    module:{
        rules: [{
            test: /\.js$/,
            exclude: /(node_modules|bower_components)/,
            use:[{
                loader: 'babel-loader',
                options: {
                  presets: [
                      '@babel/preset-env',// 引入 babel
                      '@babel/preset-react' // 引入 babel-react 
                    ]
                }
            }]
        }]
    },
    plugins: [new CleanWebpackPlugin(),// 清空 dist 文件夹
        new HtmlWebpackPlugin({template: './index.html'}),// 添加 html 模版插件
    ]
}


安装依赖:npm install babel-loader@8.0.0-beta.0 @babel/core @babel/preset-env @babel/preset-react --save

npm i html-webpack-plugin clean-webpack-plugin --save

4. 配置 npm/script 启动项

打开 package.json 文件,添加一行 script 代码,如下:

此时我们的代码结构如下:

当我们在终端执行 npm run build 命令后,可以看到多出来打包后的 dist 文件夹,以及打包后的 js 文件,如下:

在浏览器里打开 dist 下的 index.html 文件,OK,第一行 react 代码闪亮出现!

4. 修改 npm/script 启动项
上面代码虽然显示出来了,但是不能每次更改代码都执行一次打包吧,太麻烦了?那就搭建一个 server 吧,在搭配上局部热更新 (hmr) 使用起来很是舒畅。需要修改 3 个地方:

1. 在 webpack.config.js 文件中添加以下代代码:devServer: {// 开启一个本地服务
        port: 9000,// 端口
        host:"0.0.0.0",// 配置后可通过本机 ip 访问,方便在手机上调试
        hot:true,//
}
2. 修改入口文件 app.js:import React from 'react';
import ReactDOM from 'react-dom'
import {hot} from 'react-hot-loader/root'// 添加依赖,通过 npm 下载

function AppCont(){return <div>welcom,react-app hot</div>}
const App = hot(() =>{// 根组件外层通过高阶组件包裹
    return <AppCont />
})

ReactDOM.render(
    <App />,
    document.getElementById('app')
)
3. 修改 package.json 文件:增加一个新的 script 命令 dev

"dev": "webpack-dev-server --mode=development --config  webpack.config.js"

执行 npm run dev 命令,打开 http://localhost:9000/,可以看到页面内容出现了,在文字后面添加 hot 后,发现页面内容更新了,但是没有刷新!ok 到这里,简单的项目已经搭建完成,可以进行开发了。

三、React 的一些概念

这里通过一个简单的例子来描述一下 react 的一些概念。输入框输入数字、点击后面 add+ 数据会改变并求和。

import React from 'react';

function Item (props){const {count,onChange,onAdd} = props;
    return <div>
        <input value={count} onChange={onChange} />
        <span onClick={onAdd}>add+</span>
    </div>
}

class Add extends React.Component{constructor(){super();
        this.state = {addList : [0,0,0,0]
        }
        this.onChange = this.onChange.bind(this)
        this.onAdd = this.onAdd.bind(this)
    }
    onChange(e,index){this.state.addList.splice(index,1,e.target.value)
        this.setState({addList:this.state.addList})
    }
    onAdd(e){this.state.addList.splice(e,1,Number(this.state.addList[e]) + 1 )
        this.setState({addList:this.state.addList})
    }
    render (){const { addList} = this.state;
        return <div>
            {addList.map((item,index)=>{return <Item key={index} count={item} onChange={(e)=>{this.onChange(e,index)}} onAdd={()=>{this.onAdd(index)}}  />
                })

            }
            <div>{addList[0]*1 + addList[1]*1 + addList[2]*1 + addList[3]*1}</div>
        </div>
    }
}

export default Add;

麻雀虽小 … 用来入门也是够用了!

1.react 组件的创建的 3 种方式

1.React.createClass
常用的是 class 继承和 无状态函数 的方式,还有一种 React.createClass 过于繁琐而且会导致不必要的性能开销所以基本上算是被废弃了。
2.无状态组件
直接通过函数声明编写,一般作为纯展示组件使用,内部没有 state(可以通过 hooks 使用),不会实例化,也就不需要分配多余的内存,从而性能得到一定的提升。但是内部无法使用 this,也没有生命周期
3.React.Component
React 目前极为推宠的创建有状态组件的方式。内部可以使用 this 和生命周期。可以使用 state。
React.Component 创建的组件,其成员函数 不会自动绑定 this,需要手动绑,否则 this 不能获取当前组件实例对象。绑定方式有 3 种:可以在构造函数中完成绑定(constructor 推荐),也可以在调用时使用 method.bind(this)来完成绑定,还可以使用 arrow function 来绑定。

2. 参数传递

一般就是 父向子 传递参数通过 props 传递。
子向父 传递则要通过父组件传递的函数来传递。
跨组件传递后面会提到使用 redux 想怎么传就怎么传。

3. 受控组件 / 非受控组件

表单元素除了收到 state 控制,还会受到用户输入控制。有两个来源,使得内容不可预测。React 使用 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
可以看到要给受控组件提供 onChange 函数来保证 state 数据的统一性。

三、引入 redux

上面看到了父子组件间的传参还很方便的,但是如果要在 Add 组件外(也就是跨组件传递)使用求和后的数据怎么办?
当然,可以使用增加中间组件、context 等方法,这里讲一下大型项目常用的 redux 状态管理,redux 本身的原理也很简单。
1. 提供 createStore 创建 store 库,将数据都存放在一起,单向数据流。
2. 数据只读,修改数据只能通过 dispatch 方法,传递 action 对象(必须含有 type 属性)在纯函数reduce 里修改,每一次都是拷贝一个新的数据,不会修改原来的数据源,保证了数据的来源可溯性。

修改 app.js
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore} from 'redux'; // 添加 redux 依赖后,引入创建 store 的方法 createStore
import {Provider} from 'react-redux';// 添加 react-redux 依赖,引入改节组件
import reduce from './model/reduce';//createStore 方法第一个参数是 reduce
import {hot} from 'react-hot-loader/root';
import AddItem from './component/addItem';


const store = createStore(reduce)

function AppCont(){return <Provider store={store}><AddItem /></Provider>// 根组件外面包裹高阶组件
}
const App = hot(() =>{return <AppCont />})

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

新建 reduce 文件,处理 reduce 函数。由于后面项目庞大后,reduce 函都写在一起肯定太臃肿,redux 提供了拆分的方法,可以通过业务进行拆分,最后通过 combineReducers 来合并。

import {combineReducers} from 'redux';
const initState = {addList:[0,0,0,0]
}

function addSum(state=initState,action){switch (action.type){
        case 'add' : 
            return {
                ...state,
                addList:[...action.payload]
            }
        default : return {...state}
    }
    
}
export default combineReducers({addSum})

addItem 文件需要做一些修改,将原来写在 state 的数据,通过 store 来存取。修改方法跟下面新增加 Sum 组件一样:通过 connect 函数来连接组件和 store。

import React from 'react';
import {connect} from 'react-redux';
function Sum(props){const {addList} = props
    return <div>{Number(addList[0]) + Number(addList[1]) + Number(addList[2]) + Number(addList[3])
    
    }</div>
}
export default connect(data=>data.addSum)(Sum);

四、引入 react-router

react 单页面模式下,路由显得很重要了,react 将 router 单独剔除,形成一个单独的组件,使用起来更加的方便,代码的耦合程度也降低不少。
提供 HashRouter、BrowserRouter 两种根路由方式,重要的区别是 HashRouter 是通过 hash 路径访问,在浏览器直接输入地址可以访问,BrowserRouter 通过 h5 的 history api 访问,输入地址时会像服务器查询,因为是单页面,没有历史所以查询不到,不过通过我们使用 webpack 的 devserver 配置 historyApiFallback: true, 可以访问,服务端渲染也可以访问。

    npm i react-router-dom --save
 <Router>
    <Route path="/" component={AddItem}></Route>
    <Link to="/tab1/1">tab1</Link>
    <Link to="/tab2/2">tab2</Link>
    <Link to="/tab3/3">tab3</Link>
    <Route path="/tab1/:num" component={PageItem}></Route>
    <Route path="/tab2/:num" component={PageItem}></Route>
    <Route path="/tab3/:num" component={PageItem}></Route>
 </Router>

OK,到这里一个简单的 react 开发框架搭建完毕,看到这里应该入门了吧。



如有不妥,欢迎指正!

正文完
 0