Dva + React + Mock 搭建项目 (主要讲解DvaJs)

 

一、初始化dva

1、安装 dva-cli

$ npm install dva-cli -g
$ dva -v
dva-cli version 0.9.1

2、创建新应用

安装完 dva-cli 之后,就可以在命令行里访问到 dva 命令。现在,你可以通过 dva new 创建新应用。

$ dva new dva-quickstart

这会创建 dva-quickstart 目录,包含项目初始化目录和文件,并提供开发服务器、构建脚本、数据 mock 服务、代理服务器等功能。

然后我们 cd 进入 dva-quickstart 目录,并启动开发服务器:

$ cd dva-quickstart
$ npm start

几秒钟后,你会看到以下输出:

Compiled successfully!

The app is running at:

  http://localhost:8000/

Note that the development build is not optimized.
To create a production build, use npm run build.

在浏览器里打开 http://localhost:8000 ,你会看到 dva 的欢迎界面。

打开F12你会看到一个报错,报错来源于node/model下面的依赖包,引入方式问题,可以自行百度解决(不影响使用!)

到此,dva项目就创建完成!

基本目录结构

 

二、dva路由设置

1、创建新页面 src/routes/userPage.js

import React from 'react';

class userPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {  };
  }
  render() {
    return (
      <div>用户页面</div>
    );
  }
}

export default userPage;

然后可以打开src/index.js看到第4步引入了 ./router.js

2、再打开src/routre.js ,在里面照葫芦画瓢引入userPage.js

import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import IndexPage from './routes/IndexPage';
//引入userpage
import UserPage from './routes/userPage';

function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={IndexPage} />
        {/* 添加新路由 */}
        <Route path="/user"  component={UserPage} />
      </Switch>
    </Router>
  );
}

export default RouterConfig;

浏览器页面在输入 http://localhost:8000/#/user 就可以访问到用户页面了

也可以用到Link跳转

//引入Fragment 作为一个根组件
import React,{Fragment} from 'react';
//引入link
import { Link } from 'dva/router';

class userPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {  };
  }
  render() {
    return (
      <Fragment>
         <div>用户页面</div>
         <br/>
         <Link to="/">跳转首页</Link>
      </Fragment>
    );
  }
}

export default userPage;

再次刷新页面,点击跳转首页,就可以跳回到首页了!

怎么样用函数跳转呢,接着看

//引入Fragment 作为一个根组件
import React,{Fragment} from 'react';
//引入link
import { Link } from 'dva/router';

class userPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {  };
  }
    
  //跳转首页函数
  handleToIndex = () =>{
    this.props.history.push('/');
  }

  render() {
    return (
      <Fragment>
         <div>用户页面</div>
         <br/>
         <Link to="/">跳转首页</Link>
         <br/>
         <br/>
         <button onClick={this.handleToIndex}>首页</button>
      </Fragment>
    );
  }
}

export default userPage;

这样就实现了函数跳转页面!

如何实现组件跳转页面呢,进一步操作!

在src/components创建一个新文件Child.js

import React from 'react';
//引入 withRouter
import { withRouter } from 'dva/router';

class Child extends React.Component {
  constructor(props) {
    super(props);
    this.state = {  };
  }

  //组件跳转首页
  handleToIndex = () =>{
    this.props.history.push('/');
  }

  render() {
    return (
      <div>
        <div>通用组件</div>
        <button onClick={this.handleToIndex}>首页_child</button>
      </div>
    );
  }
}

//写入路由
export default withRouter(Child);

然后再在route/userPage.js  中引入 Child组件

//引入Fragment 作为根节点
import React,{Fragment} from 'react';
//引入Link
import { Link } from 'dva/router';

//引入通用组件
import Child from '../components/Child';

class userPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {  };
  }

  //跳转首页函数
  handleToIndex = () =>{
    this.props.history.push('/');
  }

  render() {
    return (
      <Fragment>
        <div>用户页面</div>
        <br/>
        <Link to="/">跳转首页</Link>
        <br/>
        <br/>
        <button onClick={this.handleToIndex}>首页</button>
        <br/>
        <br/>
        <Child/>
      </Fragment>
    );
  }
}

export default userPage;

再点击下组件的跳转首页按钮,即可实现组件跳转,写这个组件是为了讲解组件如何引入路由跳转!

现在访问页面地址是哈希路由,如果不想用哈希路由访问的话,只需要修改一下src/index.js下面的配置就好了

import dva from 'dva';
import './index.css';

//修改不使用哈希路由访问
import {createBrowserHistory as createHistory} from 'history';
// 1. Initialize
const app = dva({
  history: createHistory(),
});

// 1. Initialize
// const app = dva();

// 2. Plugins
// app.use({});

// 3. 引入Model
// app.model(require('./models/indexTest').default);

// 4. Router
app.router(require('./router').default);

// 5. Start
app.start('#root');

现在就可以直接用http://localhost:8000/访问了  而不是 http://localhost:8000/#/  (这位同学别走神,认真点,别看了,就是你!!!!)

 

 

三、讲解model中的reducers

reducers:以 key/value 格式定义 reducer。用于处理同步操作,唯一可以修改 state 的地方

1、现在src/models文件下创建一个文件 indexTest.js

export default {
  //命名空间
  namespace:'indexTest',
  //数据
  state:{
    name:'message'
  }
}

现在只是单纯创建了一个js文件,并没有在任何地方使用,那么这个需要如何使用呢,打开文件src/index.js入口文件

可以看到已经注释的第3步有一句:app.model(require('./models/xxxx').default);

2、在src/index.js中引入model  : app.model(require('./models/indexTest').default);

3、回到route/IndexPage.js中修改js

import React from 'react';
//引入connect 
import {connect} from 'dva';

class IndexPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {  };
  }
  render() {
    return (
      <div>
        <h2>我是首页</h2>
        <h4>我是model/indexTest.js的name:{this.props.name}</h4>
      </div>
    );
  }
}

//mapStateToProps 是一个函数(函数名可以自定义),它的作用就像它的名字那样,建立一个从(外部的)state对象到(UI组件的)props对象的映射关系。
//说白就是获取model中定义的state
const mapStateToProps = state =>{
  //这里可以输出看一下,已经获取到model的数据
  console.log(state)
  return {
    msg:'这里是获取model中的数据',
    name:state.indexTest.name,//获取model/indexTest.js中的数据
  }
}

export default connect(mapStateToProps)(IndexPage);

到目前为止我们就获取到model中定义的数据了,那么我要修改model中数据该怎么样修改呢?继续往下看!!!(敲黑板!!!!)

4、打开src/models/indexTest.js 修改

export default {
  //命名空间
  namespace:'indexTest',
  //数据
  state:{
    name:'message'
  },
  
  //reducers:以 key/value 格式定义 reducer。用于处理同步操作,唯一可以修改 state 的地方
  reducers:{
    //修改state函数
    //state:代表上面的state,paylocad:代表组件传过来的值
    setName(state,payLoad){
      //react中如果要修改视图,需要创建一个新的地址才可以重新渲染,如果只是动态修改值视图是不会重新渲染的
      let _state = JSON.parse(JSON.stringify(state));
      _state.name = payLoad.data.name;
      //必须返回_state,不然会报错
      return _state;
    }
  }
}

5、打开src/route/IndexPage.js 添加修改state的函数

handleSetName = () =>{
    console.log(this.props)
    //获取到props中dispatch方法修改model的数据
    //type:配置方法名称 type:"模块‘namespace’/方法名"传 要修改的值
    this.props.dispatch({
      type:'indexTest/setName',
      data:{
        name:'掏粪的小仙女'
      }
    })
}


{/* 添加修改model中state按钮 */}
 <button onClick={this.handleSetName}>setName</button>         

这样就实现了修改model中的state值!当然这只是 其中一种 继续往下看,还有其他的方法。

 

四、讲解model中的effects

//effects:以 key/value 格式定义 effect。用于处理异步操作和业务逻辑,不直接修改 state。由 action 触发,可以触发 action,可以和服务器交互,可以获取全局 state 的数据

  //主要是用到es6中的Generator 函数

  //Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

  //Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。

1、打开src/models/indexTest.js 添加一个 setNameAsync函数

export default {
  //命名空间
  namespace:'indexTest',
  //数据
  state:{
    name:'message'
  },
  
  //reducers:以 key/value 格式定义 reducer。用于处理同步操作,唯一可以修改 state 的地方
  reducers:{
    //修改state函数
    //state:代表上面的state,paylocad:代表组件传过来的值
    setName(state,payLoad){
      //react中如果要修改视图,需要创建一个新的地址才可以重新渲染,如果只是动态修改值视图是不会重新渲染的
      let _state = JSON.parse(JSON.stringify(state));
      _state.name = payLoad.data.name;
      //必须返回_state,不然会报错
      return _state;
    }
  },

  //effects:以 key/value 格式定义 effect。用于处理异步操作和业务逻辑,不直接修改 state。由 action 触发,可以触发 action,可以和服务器交互,可以获取全局 state 的数据
  //主要是用到es6中的Generator 函数
  //Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
  //Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
  effects:{
    //payload:页面传过来的值, put:理解成一个动作,通知reducers中的方法修改state
    *setNameAsync ({payload},{put,call}){
        console.log(payload)
        //调用reducers中的方法
        yield put({
          type:'setName',
          data:{
            name:payload.name
          }
        });
    }
  }

}

2、在src/route/IndexPage.js中

//使用effects  异步调用方法
  handleSetNameAsync = () =>{
    this.props.dispatch({
      type:'indexTest/setNameAsync',
      //payload需要跟model中setNameAsync方法第一个参数相同
      payload:{
        name:'猪肉佬卖西瓜'
      }
    })
  }


{/* 添加异步修改model中state按钮 */}
<button onClick={this.handleSetNameAsync}>setNameAsync</button> 

这样就实现了第二种修改model的方法,比较推荐这种写法,因为effects用于处理异步操作和业务逻辑,不直接修改 state。由 action 触发 reducers 修改model  !!!

 

 

未完 !!! 待续!!!!

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章