美文网首页
12、M、脚手架create-react-app(1)

12、M、脚手架create-react-app(1)

作者: 夜幕小草 | 来源:发表于2018-02-07 10:09 被阅读48次

1、基本知识

npm install -g create-react-app       /* 安装create-react-app,建议使用cnpm */

create-react-app hl-app                 /* 使用命令创建应用,myapp为项目名称 */

cd hl-app                                        /* 进入目录,然后启动 */

npm start

按以上执行,即可快速创建React开发环境。

打开http://localhost:3000/ 查看

配置工程

npm install redux --save   //安装数据流 redux
npm run eject   //安装相关的插件,跟配置
npm install express --save // 安装express 
npm install install -g nodemon // 这个nodemon是帮助我们不用每次修改都重启服务器
运行时候: nodemon server.js  替换了之前的node server.js
只需要在页面上刷新就可以的了
注意: res.send  跟 res.json 他们之间是不太相同的

安装数据库 MongoDB 见官网: 然后命令行: mongo -->为了看是否安装成功

npm install mongoose --save //在项目中安装的,链接本地数据库MongoDB

使用mongodb----增(create)删(remove)改(update) 查(find findOne)

const express = require('express')
const mongoose = require('mongoose')

// 链接mongo,并且使用dashu集合
const DB_URL = 'mongodb://localhost:27017/dashu'
mongoose.connect(DB_URL)
// 以下这行可要可不要,要的话就是可以方便看到链接成功了
mongoose.connection.on('connected', function () {
    console.log('mongo connect success')
})
// 类似于mysql的表 mongo里有文档、字段的概念
const User = mongoose.model('user', new mongoose.Schema({
    user: {type: String, require: true},
    age: {type: Number, require: true}
}))
//新增数据create
/*User.create({
    user: 'xiaohua',
    age: 20
}, function (err, doc) {
    if (!err) {
        console.log(doc)
    } else {
        console.log(err)
    }
})*/
// 删除remove
// User.remove({age:20}, function () {
//     console.log('delete success!')
// })
// 跟新(改)update
User.update({'user': 'xiaoming'}, {'$set': {age: 38}}, function (err, doc) {
    console.log(doc)
})

// 新建app
const app = express()


app.get('/', function (req, res) {
    res.send('<h1>hello world~~~~~</h1>')
})

app.get('/data', function (req, res) {
    // 查询数据用find, 查询一条是用findOne
    User.find({}, function (err, doc) {
        if(!err) {
            res.json(doc)
        } else {
            res.send('server 500')
        }
    })
    // res.json({name: 'yemuxiaocao', type: 'IT', age: 90})
})

app.listen(9090, function () {
    console.log('Node app run port 9090')
})

2、react跟es6基本知识

---props 属性传值  onClick事件  react生命周期
import React, { Component } from 'react';
import { Button } from 'antd-mobile';


class App extends Component {
  render() {
      const boss = '大树老板'
    return (
        <div>
            <h1>老板名字:{boss}</h1>
            <员工 员工='夜幕小草'></员工>
            <员工2 员工='夜幕小草222'></员工2>
        </div>
    );
  }
}

// props属性 由父组件传给子组件
class 员工 extends Component {
    constructor(props) {
        super(props)
        this.state = {
            solders: ['小牛', '阿虎', '阿辉', '小美']
        }
        /*第一种方式解决this*/
        // this.addSolder = this.addSolder.bind(this)
        console.log('组件初始化')
    }

    componentWillMount() {
        console.log('组件马上就要挂载了')
    }
    componentDidMount() {
        console.log('组件已经挂载')
    }
    componentWillReceiveProps(nextProps) {
        console.log('组件要接收父组件的值了')
    }
    shouldComponentUpdate() {
        console.log('判断组件是不是要更新组件')
        return true; //记得要返回true
    }
    componentWillUpdate() {
        console.log('马上就要更新组件了')
    }
    componentDidUpdate() {
        console.log('组件更新完毕')
    }
    componentWillUnmount() {
        console.log('组件卸载了')
    }

    // 点击事件修改数据,并且this的注意事项
    // 第三种绑定this方式 addSolder = () => {}
    addSolder(){
        this.setState({
            solders: [...this.state.solders, '新员工']
        })
        console.log('新员工。。。。')
    }

    render() {
        console.log('渲染render函数')
        return (
            <div>
                <h2>员工:{this.props.员工}</h2>
                {/*第一种绑定this*/}
                {/*<button onClick={ this.addSolder}>添加新员工</button>*/}
                {/*第三种绑定this*/}
                {/*<button onClick={ this.addSolder}>添加新员工</button>*/}
                {/*第二种绑定this*/}
                <Button type="primary" onClick={ () => this.addSolder()}>添加新员工</Button>
                {/*<button onClick={ () => this.addSolder()}>添加新员工</button>*/}
                <ul>
                    {this.state.solders.map((v, index )=> { return <li key={index}>{v}</li>})}
                </ul>
            </div>
        )
    }
}
// props函数式方式
function 员工2(props) {
    return  <h2>员工:{props.员工}, 好厉害!</h2>
}


export default App;


使用 antd-mobile
按需加载 :npm install antd-mobile --save
npm install babel-plugin-import --save-dev
// .babelrc or babel-loader option
{
  "plugins": [
    ["import", { libraryName: "antd-mobile", style: "css" }] // `style: true` 会加载 less 文件
  ]
}
详细见官网:https://mobile.ant.design/docs/react/introduce-cn

3、redux基本使用

import { createStore } from 'redux'
//1新建store
//通过reducer建立
//根据老的state和action生成新的state
function counter(state=0, action) {
    switch (action.type) {
        case '加一':
            return state + 1
        case '减一':
            return state - 1
        default:
            return 10
    }
}

//新建store
const store = createStore(counter)

const init = store.getState()
console.log(init)

function listener() {
   const current = store.getState()
   console.log(`现在的数据是:${current}`)
}
//监听订阅数据变化
store.subscribe(listener)
// 派发事件,传递action
store.dispatch({type: '加一'})
store.dispatch({type: '加一'})
store.dispatch({type: '加一'})
store.dispatch({type: '加一'})
store.dispatch({type: '减一'})
store.dispatch({type: '减一'})
store.dispatch({type: '减一'})
store.dispatch({type: '减一'})
store.dispatch({type: '减一'})

一个友好的组件就是依赖性是比较弱的,所以在跟react组件搭配使用的时候,应该使用props这个属性来传递,在APP挂载的时候就应该挂上去的了。
4、友好的组件

index.js文件

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { createStore } from 'redux'
import {counter, add, det} from "./index.redux";

const store = createStore(counter)

function render() {
    ReactDOM.render(<App store={store} add={add} det={det}/>, document.getElementById('root'));
}
render()
registerServiceWorker();
/*监听手动跟新store*/
store.subscribe(render)
index.redux.js文件

// import {actionType} from "./index.actionType";
/* action type*/
const ADD = '加一'
const DET = '减一'


//根据老的state和action生成新的state
// reduer
export function counter(state=0, action) {
    switch (action.type) {
        case ADD:
            return state + 1
        case DET:
            return state - 1
        default:
            return 10
    }
}
/*action creator*/
export  function add() { return {type: ADD} }
export  function det() { return {type: DET} }

/*只不过是把action跟action-type分开了而已*/
APP.js文件

import React, { Component } from 'react';
import { Button } from 'antd-mobile';
// import {add, det} from "./index.redux";
// import {actions} from "./index.action";

class App extends Component {
  render() {
      const boss = '大树老板'
      const store = this.props.store
      const num = store.getState()
      const add = this.props.add()
      const det = this.props.det()

    return (
        <div>
            <h1>老板名字:{boss}</h1>
            <h2>当前的数量是{num}</h2>
            <Button type="primary" onClick={ () => store.dispatch(add)}>加一</Button>
            <Button type="primary" onClick={ () => store.dispatch(det)}>减一</Button>
            <员工 员工='夜幕小草'></员工>
            <员工2 员工='夜幕小草222'></员工2>
        </div>
    );
  }
}

// props属性 由父组件传给子组件
class 员工 extends Component {
    constructor(props) {
        super(props)
        this.state = {
            solders: ['小牛', '阿虎', '阿辉', '小美']
        }
        /*第一种方式解决this*/
        // this.addSolder = this.addSolder.bind(this)
        console.log('组件初始化')
    }

    componentWillMount() {
        console.log('组件马上就要挂载了')
    }
    componentDidMount() {
        console.log('组件已经挂载')
    }
    componentWillReceiveProps(nextProps) {
        console.log('组件要接收父组件的值了')
    }
    shouldComponentUpdate() {
        console.log('判断组件是不是要更新组件')
        return true; //记得要返回true
    }
    componentWillUpdate() {
        console.log('马上就要更新组件了')
    }
    componentDidUpdate() {
        console.log('组件更新完毕')
    }
    componentWillUnmount() {
        console.log('组件卸载了')
    }

    // 点击事件修改数据,并且this的注意事项
    // 第三种绑定this方式 addSolder = () => {}
    addSolder(){
        this.setState({
            solders: [...this.state.solders, '新员工']
        })
        console.log('新员工。。。。')
    }

    render() {
        console.log('渲染render函数')
        return (
            <div>
                <h2>员工:{this.props.员工}</h2>
                {/*第一种绑定this*/}
                {/*<button onClick={ this.addSolder}>添加新员工</button>*/}
                {/*第三种绑定this*/}
                {/*<button onClick={ this.addSolder}>添加新员工</button>*/}
                {/*第二种绑定this*/}
                <Button type="primary" onClick={ () => this.addSolder()}>添加新员工</Button>
                {/*<button onClick={ () => this.addSolder()}>添加新员工</button>*/}
                <ul>
                    {this.state.solders.map((v, index )=> { return <li key={index}>{v}</li>})}
                </ul>
            </div>
        )
    }
}
// props函数式方式
function 员工2(props) {
    return  <h2>员工:{props.员工}, 好厉害!</h2>
}
export default App;

5、使用插件使得redux跟react更加好的链接跟调试及其开发,调试工具在浏览器google应用商店分别搜索redux和react都是安装第一个

异步任务处理:npm install redux-thunk --save
使用applyMiddleware开启thunk中间件
在index.js页面开启
import thunk from 'redux-thunk'
import { createStore, applyMiddleware } from 'redux'
const store = createStore(counter, applyMiddleware(thunk))

index.redux.js文件
//异步操作
export function addAsync() {
    return dispatch => {
        setTimeout(()=>{
            dispatch(add())
        }, 2000)
    }
}

6、调试工具,在google应用商店搜索redux,安装第一个安装

index.js全局配置一下
import thunk from 'redux-thunk'
import { createStore, applyMiddleware, compose } from 'redux'
import {counter, add, det, addAsync} from "./index.redux";

//compose处理集合的问题
const store = createStore(counter, compose(
    applyMiddleware(thunk),
    window.devToolsExtension? window.devToolsExtension() : f=>{}
))

看一下效果


image.png

6-1、使用react-redux之前的代码(记录一下代码)

---APP.js文件

import React, { Component } from 'react';
import { Button } from 'antd-mobile';
// import {add, det} from "./index.redux";
// import {actions} from "./index.action";

class App extends Component {
  render() {
      const boss = '大树老板'
      const store = this.props.store
      const num = store.getState()
      const add = this.props.add()
      const det = this.props.det()
      const addAsync = this.props.addAsync()

    return (
        <div>
            <h1>老板名字:{boss}</h1>
            <h2>当前的数量是{num}</h2>
            <Button type="primary" onClick={ () => store.dispatch(add)}>加一</Button>
            <Button type="primary" onClick={ () => store.dispatch(addAsync)}>延时2秒加一</Button>
            <Button type="primary" onClick={ () => store.dispatch(det)}>减一</Button>
            <员工 员工='夜幕小草'></员工>
            <员工2 员工='夜幕小草222'></员工2>
        </div>
    );
  }
}

// props属性 由父组件传给子组件
class 员工 extends Component {
    constructor(props) {
        super(props)
        this.state = {
            solders: ['小牛', '阿虎', '阿辉', '小美']
        }
        /*第一种方式解决this*/
        // this.addSolder = this.addSolder.bind(this)
        console.log('组件初始化')
    }

    componentWillMount() {
        console.log('组件马上就要挂载了')
    }
    componentDidMount() {
        console.log('组件已经挂载')
    }
    componentWillReceiveProps(nextProps) {
        console.log('组件要接收父组件的值了')
    }
    shouldComponentUpdate() {
        console.log('判断组件是不是要更新组件')
        return true; //记得要返回true
    }
    componentWillUpdate() {
        console.log('马上就要更新组件了')
    }
    componentDidUpdate() {
        console.log('组件更新完毕')
    }
    componentWillUnmount() {
        console.log('组件卸载了')
    }

    // 点击事件修改数据,并且this的注意事项
    // 第三种绑定this方式 addSolder = () => {}
    addSolder(){
        this.setState({
            solders: [...this.state.solders, '新员工']
        })
        console.log('新员工。。。。')
    }

    render() {
        console.log('渲染render函数')
        return (
            <div>
                <h2>员工:{this.props.员工}</h2>
                {/*第一种绑定this*/}
                {/*<button onClick={ this.addSolder}>添加新员工</button>*/}
                {/*第三种绑定this*/}
                {/*<button onClick={ this.addSolder}>添加新员工</button>*/}
                {/*第二种绑定this*/}
                <Button type="primary" onClick={ () => this.addSolder()}>添加新员工</Button>
                {/*<button onClick={ () => this.addSolder()}>添加新员工</button>*/}
                <ul>
                    {this.state.solders.map((v, index )=> { return <li key={index}>{v}</li>})}
                </ul>
            </div>
        )
    }
}
// props函数式方式
function 员工2(props) {
    return  <h2>员工:{props.员工}, 好厉害!</h2>
}
export default App;

---index.js文件

/*1-3章关于react的测试*/
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import thunk from 'redux-thunk'
import { createStore, applyMiddleware, compose } from 'redux'
import {counter, add, det, addAsync} from "./index.redux";

//compose处理集合的问题
const store = createStore(counter, compose(
    applyMiddleware(thunk),
    window.devToolsExtension? window.devToolsExtension() : f=>{}
))

function render() {
    ReactDOM.render(<App store={store} add={add} det={det} addAsync={addAsync}/>, document.getElementById('root'));
}
render()
registerServiceWorker();
/*监听手动跟新store*/
store.subscribe(render)

/*第四章reduxtest*/

/*import { createStore } from 'redux'
//1新建store
//通过reducer建立
//根据老的state和action生成新的state
function counter(state=0, action) {
    switch (action.type) {
        case '加一':
            return state + 1
        case '减一':
            return state - 1
        default:
            return 10
    }
}

//新建store
const store = createStore(counter)

const init = store.getState()
console.log(init)

function listener() {
   const current = store.getState()
   console.log(`现在的数据是:${current}`)
}
//监听数据变化
store.subscribe(listener)
// 派发事件,传递action
store.dispatch({type: '加一'})
store.dispatch({type: '加一'})
store.dispatch({type: '加一'})
store.dispatch({type: '加一'})
store.dispatch({type: '减一'})
store.dispatch({type: '减一'})
store.dispatch({type: '减一'})
store.dispatch({type: '减一'})
store.dispatch({type: '减一'})*/


---index.redux.js文件

// import {actionType} from "./index.actionType";
/* action type*/
const ADD = '加一'
const DET = '减一'


//根据老的state和action生成新的state
// reduer
export function counter(state=0, action) {
    switch (action.type) {
        case ADD:
            return state + 1
        case DET:
            return state - 1
        default:
            return 10
    }
}
/*action creator*/
export  function add() { return {type: ADD} }
export  function det() { return {type: DET} }

//异步操作
export function addAsync() {
    return dispatch => {
        setTimeout(()=>{
            dispatch(add())
        }, 2000)
    }
}

/*只不过是把action跟action-type分开了而已*/

7、使用react-redux来更好的链接react跟redux


image.png
npm install react-redux --save
image.png

改造后的代码: 提供了Provider 跟connect方法,是非常不错的
<Button type="primary" onClick={ () => store.dispatch(add)}>加一</Button>
connect里边已经有dispatch方法
<Button type="primary" onClick={ this.props.add}>加一</Button>

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import thunk from 'redux-thunk'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware, compose } from 'redux'
import {counter, add, det, addAsync} from "./index.redux";

//compose处理集合的问题
const store = createStore(counter, compose(
    applyMiddleware(thunk),
    window.devToolsExtension? window.devToolsExtension() : f=>{}
))


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

//引用react-redux,取消以下的的写法,属性add={add} det={det} addAsync={addAsync}也不要了,
//全部集合在connect当中
// function render() {
//     ReactDOM.render(<App store={store} add={add} det={det} addAsync={addAsync}/>, document.getElementById('root'));
// }
// render()
registerServiceWorker();
/*监听手动跟新store*/
// store.subscribe(render)

App.js文件

import React, { Component } from 'react';
import { Button } from 'antd-mobile';
import {connect } from 'react-redux'
import {add, det, addAsync} from "./index.redux";
// import {actions} from "./index.action";



class App extends Component {
  render() {
      const boss = '大树老板'
      // const store = this.props.store
      // const num = store.getState()
      // const add = this.props.add()
      // const det = this.props.det()
      // const addAsync = this.props.addAsync()

    return (
        <div>
            <h1>老板名字:{boss}</h1>
            <h2>当前的数量是{this.props.num}</h2>
            <Button type="primary" onClick={ this.props.add}>加一</Button>
            <Button type="primary" onClick={ this.props.addAsync}>延时2秒加一</Button>
            <Button type="primary" onClick={ this.props.det}>减一</Button>
            <员工 员工='夜幕小草'></员工>
            <员工2 员工='夜幕小草222'></员工2>
        </div>
    );
  }
}
/*获取数据--直接传给属性*/
const mapStatetoProps = (state) => {return {num: state}}
/*获取方法--*/
const actionCreators = {add, det, addAsync}
/*通过connect来链接*/
App = connect(mapStatetoProps, actionCreators)(App)
export default App;

index.redux.js文件

// import {actionType} from "./index.actionType";
/* action type*/
const ADD = '加一'
const DET = '减一'


//根据老的state和action生成新的state
// reduer
export function counter(state=0, action) {
    switch (action.type) {
        case ADD:
            return state + 1
        case DET:
            return state - 1
        default:
            return 10
    }
}
/*action creator*/
export  function add() { return {type: ADD} }
export  function det() { return {type: DET} }

//异步操作
export function addAsync() {
    return dispatch => {
        setTimeout(()=>{
            dispatch(add())
        }, 2000)
    }
}

/*只不过是把action跟action-type分开了而已*/

connect可以用装饰器方法来写:


image.png
npm run eject
npm install babel-plugin-transform-decorators-legacy --save-dev
然后在package.json文件中配置babel加上plugins配置
"plugins": [
      "transform-decorators-legacy",  // 就是配置此项
      [
        "import",
        {
          "libraryName": "antd-mobile",
          "style": "css"
        }
      ]
    ]


App.js文件 @connect链接方式减少丑陋的写法,简洁,这个就是装饰器的写法

import React, { Component } from 'react';
import { Button } from 'antd-mobile';
import {connect } from 'react-redux'
import {add, det, addAsync} from "./index.redux";
// import {actions} from "./index.action";

/*获取数据--直接传给属性*/
// const mapStatetoProps = (state) => {return {num: state}}
/*获取方法--*/
// const actionCreators = {add, det, addAsync}
/*通过connect来链接*/
// App = connect(mapStatetoProps, actionCreators)(App)

@connect(
    // 你要state什么属性放到props里边
    state => ({num: state}),
    // 你要什么方法,放到props里边, 自动dispatch
    {add, det, addAsync}
    )

class App extends Component {
  render() {
      const boss = '大树老板'
      // const store = this.props.store
      // const num = store.getState()
      // const add = this.props.add()
      // const det = this.props.det()
      // const addAsync = this.props.addAsync()

    return (
        <div>
            <h1>老板名字:{boss}</h1>
            <h2>当前的数量是{this.props.num}</h2>
            <Button type="primary" onClick={ this.props.add}>加一</Button>
            <Button type="primary" onClick={ this.props.addAsync}>延时2秒加一</Button>
            <Button type="primary" onClick={ this.props.det}>减一</Button>
            <员工 员工='夜幕小草'></员工>
            <员工2 员工='夜幕小草222'></员工2>
        </div>
    );
  }
}
export default App;

image.png
8、react-router4路由配置及其使用 官网:https://reacttraining.com/
image.png
image.png
npm install react-router-dom --save
image.png
---index.js文件
路由的简单用法:
主要是BrowserRouter, Route, Link。。BrowserRouter里边要有一个总标签包住,exact 是完全匹配 。Link是链接。
Redirect 直接跳转
Route对应的是路由,里边有一个path属性

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import thunk from 'redux-thunk'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware, compose } from 'redux'
import {counter, add, det, addAsync} from "./index.redux";
import {BrowserRouter, Route, Link, Redirect , Switch} from 'react-router-dom'

//compose处理集合的问题
const store = createStore(counter, compose(
    applyMiddleware(thunk),
    window.devToolsExtension? window.devToolsExtension() : f=>{}
))

function Two() {
    return <h1>员工222</h1>
}
function Three() {
    return <h1>员工333</h1>
}
ReactDOM.render(
    (<Provider store={store}>
        <BrowserRouter>
            <div>
                <ul>
                    <li>
                        <Link to='/'>一员工</Link>
                    </li>
                    <li>
                        <Link to='/two'>二员工</Link>
                    </li>
                    <li>
                        <Link to='/three'>三员工</Link>
                    </li>
                </ul>
                <Redirect to='/three' component={Three}></Redirect>
                <Route path='/' exact component={App}></Route>
                <Route path='/two' component={Two}></Route>
                <Route path='/three' component={Three}></Route>

                {/*<App />*/}
            </div>
        </BrowserRouter>
    </Provider>), document.getElementById('root'));
image.png

import {conbinReudcers} from 'redux'
合并reducer,因为状态很多的时候

image.png
reducer.js文件

// 合并所有的reducer 并且返回。 使用的方法是combineReducers
import {combineReducers} from 'redux'
import {counter} from "./index.redux";
import {auth} from "./Auth.redux";

export default combineReducers({counter, auth})
auth.js文件

import React, {Component} from 'react'
import { connect } from 'react-redux'
import { login } from './Auth.redux'
import { Route, Link, Redirect, Switch} from 'react-router-dom'

// 两个reducers, 每个reducers都有一个state
// 合并reducers
@connect(
    state => state.auth,
    {login}
)

class Auth extends Component{
    constructor(props){
        super(props)
    }


    render(){
        const app = <button></button>

        return (
            <div>
                { this.props.isAuth ? <Redirect to='/dashboard'/> : null}
                <h2>你没有权限,你还没有登录!!!</h2>
                <button onClick={this.props.login}>登录</button>
            </div>
            )
    }
}

export default Auth

<------------------------------------------------------------待续-------------------------------------------------------->

相关文章

网友评论

      本文标题:12、M、脚手架create-react-app(1)

      本文链接:https://www.haomeiwen.com/subject/jloawxtx.html