一、什么是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 --savenpm 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.jsimport React from 'react';import ReactDOM from 'react-dom';import {createStore} from 'redux'; //添加redux依赖后,引入创建store的方法createStoreimport {Provider} from 'react-redux';//添加react-redux依赖,引入改节组件import reduce from './model/reduce';//createStore方法第一个参数是reduceimport {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开发框架搭建完毕,看到这里应该入门了吧。

如有不妥,欢迎指正!