Dva教程

Dva教程

2019千锋DvaJS视频精讲,全网首发!【Web前端】

千锋Web前端教程:01_dva_初始化

(01_dva_初始化&)

01_dva_初始化&

暴露request对象发送请求

其他地方调用query

src\routes\IndexPage.jsx

import React from 'react';
import {connect} from "dva";

import * as apis from "../services/example"

class IndexPage extends React.Component{
  handleSetName=()=>{
    this.props.dispatch({
      type:"indexTest/setName",
      data:{
        name:"猪猪侠"
      }
    })
  }
  handleSetNameAsync=()=>{
    this.props.dispatch({
      type:"indexTest/setNamaAsync",
      data:{
        name:"猪猪侠"
      }
    })
  }
  componentDidMount(){
    // apis.testCnode().then((res)=>{
    //   console.log(res);
    // })
    // 测试mock
    apis.mockdata().then((res)=>{
      console.log(res);
    })

  }
  testCnode=()=>{
    this.props.dispatch({
      type:"indexTest/testCnode"
    })
  }
  render(){
    console.log(this.props.cnodeData);
    return (
      <div>
        我是首页
        {this.props.msg}
        <div>
          {
            this.props.name
          }
        </div>
        <button onClick={this.handleSetName}>setName</button>
        <button onClick={this.handleSetNameAsync}>setNameAsync</button>
        <button onClick={this.testCnode}>testCnode</button>
      </div>
    )
  }
}
const mapStateToProps=state=>{
  return {
    msg:"我爱北京天安门",
    name:state.indexTest.name ,
    cnodeData:state.indexTest.cnodeData
  }
}
export default connect(mapStateToProps)(IndexPage);

src\utils\request.js

import fetch from 'dva/fetch';

function parseJSON(response) {
  return response.json();
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }

  const error = new Error(response.statusText);
  error.response = response;
  throw error;
}

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 */
export default function request(url, options) {
  return fetch(url, options)
    .then(checkStatus)
    .then(parseJSON)
    .then(data => ({ data }))
    .catch(err => ({ err }));
}

src\services\example.js

import request from '../utils/request';
const pox="/apis"

export function query() {
  return request('/api/users');
}


export function testCnode() {
  return request(pox+'/api/v1/topics');
}
// 注册mock接口
export function mockdata() {
  return request("api/mockdta");
}

千锋Web前端教程:02_dva_路由

(02_dva_路由&)

02_dva_路由&

增加路由

增加userPage

Dva的初始化

进行跳转,包裹组件

使用按钮跳转

通过history跳转

Routes放在路由中配置的组件

Component放入通用组件

引入通用组件

Child中进行跳转,props中没有history

通过withRoutes写入路由

另一种跳转方式

修改首页,#为/路由

起别名,减少报错

src\routes\userPage.jsx

import React ,{Fragment}from 'react';
import {Link} from 'dva/router';
import Child from "../components/child"
class userPage extends React.Component{
  handleToIndex=()=>{
    //  console.log(this.props)
    this.props.history.push("/")
  }
  render(){
    return (
      <Fragment>
       <div>我是用户页</div>
       <Link to="/">首页</Link>
       <button onClick={this.handleToIndex}>首页</button>
       <Child/>
      </Fragment>
    )
  }
}
export default userPage

src\router.js

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

function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={IndexPage} />
        <Route path="/user" exact component={userPage} />
      </Switch>
    </Router>
  );
}

export default RouterConfig;

src\components\child.jsx

import React from 'react';
import { withRouter } from 'dva/router';
class Child extends React.Component {
  handleToIndex(){
    // console.log(this.props)
    this.props.history.push("/");
  }
  render() {
    return (
      <div>
        <div>我是通用组件</div>
        <button onClick={this.handleToIndex.bind(this)}>首页_child</button>
      </div>
    )
  }
}
export default withRouter(Child);

userPage.jsx

import React ,{Fragment}from 'react';
import {Link} from 'dva/router';
import Child from "../components/child"
class userPage extends React.Component{
  handleToIndex=()=>{
    //  console.log(this.props)
    this.props.history.push("/")
  }
  render(){
    return (
      <Fragment>
       <div>我是用户页</div>
       <Link to="/">首页</Link>
       <button onClick={this.handleToIndex}>首页</button>
       <Child/>
      </Fragment>
    )
  }
}
export default userPage

src/index.js

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

// 1. Initialize
import {createBrowserHistory as createHistory}  from 'history';


const app = dva({
  history: createHistory(),
});

// const app = dva();

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

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

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

千锋Web前端教程:03_models_reducers

(03_models_reducers&)

03_models_reducers&

多个model数据仓库,都要有namespace

引用注册models

视图中使用model

读取model中的state,用法和reducers一样

定义多个state

获取name Misa

要可以修改name值,setName第一个参数是state,第二个参数是传入的值playload,代表从上面的state,playload从组建中传递过来的参数,要返回state

调用setName,点击按钮

通过dispatch进行调用,type通过namespace进行调用后面是要调用的函数

点击调用函数

传递参数

点击获取值

点击视图没有更新,不要生成新的state,生成新的地址

src\models\indexTest.js

import * as apis from "../services/example"
export default {
  namespace: 'indexTest',
  state: {
    name:"Msea",
    cnodeData:[]
  },
  reducers:{
    setName(state,payLoad){
      // console.log(payLoad.data.name);
      let _state=JSON.parse(JSON.stringify(state));
        _state.name=payLoad.data.name;
      return _state;
    },
    setCnodeDataList(state,payLoad){
      let _state=JSON.parse(JSON.stringify(state));
      _state.cnodeData=payLoad.data
      return  _state;
    },
    testPath(state,payLoad){
      console.log("用户页");
      return state;
    }
  },
  effects:{
    *setNamaAsync ({payload},{put,call}){
      yield put({
        type:"setName",
        data:{
          name:"超人强"
        }
      })
    },
    *testCnode({payload},{put,call}){
      let rel= yield call(apis.testCnode);
      if(rel.data){
        yield put({
          type:"setCnodeDataList",
          data:rel.data.data
        }) 

      }
    }
  },
  subscriptions:{
    haha({dispatch,history}){
      history.listen(({pathname})=>{
        if(pathname==="/user"){
          dispatch({
            type:"testPath"
          })
        }
      })
    }
  }

};

index.js

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

// 1. Initialize
import {createBrowserHistory as createHistory}  from 'history';


const app = dva({
  history: createHistory(),
});

// const app = dva();

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

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

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

IndexPage.jsx

import React from 'react';
import {connect} from "dva";

import * as apis from "../services/example"

class IndexPage extends React.Component{
  handleSetName=()=>{
    this.props.dispatch({
      type:"indexTest/setName",
      data:{
        name:"猪猪侠"
      }
    })
  }
  handleSetNameAsync=()=>{
    this.props.dispatch({
      type:"indexTest/setNamaAsync",
      data:{
        name:"猪猪侠"
      }
    })
  }
  componentDidMount(){
    // apis.testCnode().then((res)=>{
    //   console.log(res);
    // })
    // 测试mock
    apis.mockdata().then((res)=>{
      console.log(res);
    })

  }
  testCnode=()=>{
    this.props.dispatch({
      type:"indexTest/testCnode"
    })
  }
  render(){
    console.log(this.props.cnodeData);
    return (
      <div>
        我是首页
        {this.props.msg}
        <div>
          {
            this.props.name
          }
        </div>
        <button onClick={this.handleSetName}>setName</button>
        <button onClick={this.handleSetNameAsync}>setNameAsync</button>
        <button onClick={this.testCnode}>testCnode</button>
      </div>
    )
  }
}
const mapStateToProps=state=>{
  return {
    msg:"我爱北京天安门",
    name:state.indexTest.name ,
    cnodeData:state.indexTest.cnodeData
  }
}
export default connect(mapStateToProps)(IndexPage);

router.js

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

function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={IndexPage} />
        <Route path="/user" exact component={userPage} />
      </Switch>
    </Router>
  );
}

export default RouterConfig;

千锋Web前端教程:04_models_effects

(04_models_effects&)

04_models_effects&

Model中的异步,基于redux的saga

Generator函数前面都要有*,第一个参数是payload,第二个参数是put和call

Yield是console的结果

目的要修改state,异步执行调用接口,获取数据放到state就可以全局使用了

尽量不要再reducers写逻辑

Put传递一个action,需要一个type,直接调用setName就可以,和传入的参数

调用put,yield调用一个action。通过yield调用put,put里面发action调用方法,call就是发送异步

异步函数调用也需要触发一下

千锋Web前端教程:05_models_Api

(05_models_Api&)

05_models_Api&

Dva的异步,通过接口,通过代理调用接口,代理在webpackrc中

去掉后面的path,代理改变重启服务

部署接口通过servers,通过发送ajax的对象调用

Fetch发送的ajax

暴露一个接口

需要代理,发现请求路径由apis会替换url

pages调用接口

测试,初始化生命周期,初始化运行触发testCode(),返回promise获得接口返回的数据

数据遍历到视图中

在models部署一个接口取数据

Call中引入接口,第二个参数要要带的参数

调用接口事件触发

调用发送请求

最终的目的要赋值给state,在视图中取到数据

Call发送接口要通过service拿到方法获取数据,异步判断什么时候拿到值,Yield put()发送一个action调用reducers,在reducer中定义方法

变为字符串,state中从playload中取里面的,要返回state不然报错。

到pages中去取值,state中取值,通过namespace和方法名

处理异步if()或者this.props

数据回来了render会执行一次并且打印console.log

Map遍历,掉接口绑定异步,接口中取值

首先配置代理访问接口,/api路径里有api就要做代理,services中传接口定义方法,pages中调用service中的方法,在pages中可以通过api调用方法promise中取数据。

Models中定义和调用,使用call发送异步请求,数据回来通过put触发actions type,在actions中直接修改了state变量。数据修改之后在mapStateToProps中的state中获取数据

通过连接获取

.webpackrc

{
      "proxy": {
        "/apis": {
          "target": "https://cnodejs.org",
          "changeOrigin": true,
          "pathRewrite": { "^/apis" : "" }
        }
      }
}

\src\services\example.js

import request from '../utils/request';
const pox="/apis"

export function query() {
  return request('/api/users');
}


export function testCnode() {
  return request(pox+'/api/v1/topics');
}
// 注册mock接口
export function mockdata() {
  return request("api/mockdta");
}

request.js

import fetch from 'dva/fetch';

function parseJSON(response) {
  return response.json();
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }

  const error = new Error(response.statusText);
  error.response = response;
  throw error;
}

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 */
export default function request(url, options) {
  return fetch(url, options)
    .then(checkStatus)
    .then(parseJSON)
    .then(data => ({ data }))
    .catch(err => ({ err }));
}

IndexPage.jsx

点击testCode数据回来以后会执行一次render,点击会再执行一次

import React from 'react';
import {connect} from "dva";

import * as apis from "../services/example"

class IndexPage extends React.Component{
  handleSetName=()=>{
    this.props.dispatch({
      type:"indexTest/setName",
      data:{
        name:"猪猪侠"
      }
    })
  }
  handleSetNameAsync=()=>{
    this.props.dispatch({
      type:"indexTest/setNamaAsync",
      data:{
        name:"猪猪侠"
      }
    })
  }
  componentDidMount(){
    // apis.testCnode().then((res)=>{
    //   console.log(res);
    // })
    // 测试mock
    apis.mockdata().then((res)=>{
      console.log(res);
    })

  }
  testCnode=()=>{
    this.props.dispatch({
      type:"indexTest/testCnode"
    })
  }
  render(){
    console.log(this.props.cnodeData);
    return (
      <div>
        我是首页
        {this.props.msg}
        <div>
          {
            this.props.name
          }
        </div>
        <button onClick={this.handleSetName}>setName</button>
        <button onClick={this.handleSetNameAsync}>setNameAsync</button>
        <button onClick={this.testCnode}>testCnode</button>
      </div>
    )
  }
}
const mapStateToProps=state=>{
  return {
    msg:"我爱北京天安门",
    name:state.indexTest.name ,
    cnodeData:state.indexTest.cnodeData
  }
}
export default connect(mapStateToProps)(IndexPage);

indexTest.js

import * as apis from "../services/example"
export default {
  namespace: 'indexTest',
  state: {
    name:"Msea",
    cnodeData:[]
  },
  reducers:{
    setName(state,payLoad){
      // console.log(payLoad.data.name);
      let _state=JSON.parse(JSON.stringify(state));
        _state.name=payLoad.data.name;
      return _state;
    },
    setCnodeDataList(state,payLoad){
      let _state=JSON.parse(JSON.stringify(state));
      _state.cnodeData=payLoad.data
      return  _state;
    },
    testPath(state,payLoad){
      console.log("用户页");
      return state;
    }
  },
  effects:{
    *setNamaAsync ({payload},{put,call}){
      yield put({
        type:"setName",
        data:{
          name:"超人强"
        }
      })
    },
    *testCnode({payload},{put,call}){
      let rel= yield call(apis.testCnode);
      if(rel.data){
        yield put({
          type:"setCnodeDataList",
          data:rel.data.data
        }) 

      }
    }
  },
  subscriptions:{
    haha({dispatch,history}){
      history.listen(({pathname})=>{
        if(pathname==="/user"){
          dispatch({
            type:"testPath"
          })
        }
      })
    }
  }

};

千锋Web前端教程:06_models_subscriptions

(06_models_subscriptions&)

06_models_subscriptions&

Subscription订阅消息,dispatch调用方法和history,初始化就会注册函数

监听路径如果user触发,如果首页不触发history.listen,判断pathname

用户页修改数据,dispatch调用testPath函数

监听一直都在

千锋Web前端教程:07_dva.mock

(07_dva.mock&)

07_dva.mock&

Mock文件夹下模拟接口,不是代理方式,制作mock数据,返回json数据

调用mock,在roadhogic中暴露接口,拿到js文件

已经合法是一个mock接口

在service中注册mock接口 ,不需要proxy

Pages视图调用方法,发送接口,

也可以在effect通过异步call调用发送异步请求和put执行action

Reducers不要写逻辑,修改state状态

注册监听,路由发生dispatch触发reducers中的方法

mock\testMock.js

与代理没有关系,req请求,res响应,响应json登录成功

module.exports={
    "GET /api/mockdta":(req,res)=>{
        console.log(req);
        res.send({
            msg:"登录成功"
        })
    }
}

.roadhogrc.mock.js

注册上进行调用

export default {
    ...require("./mock/testMock")
};

example.js

import request from '../utils/request';
const pox="/apis"

export function query() {
  return request('/api/users');
}


export function testCnode() {
  return request(pox+'/api/v1/topics');
}
// 注册mock接口
export function mockdata() {
  return request("api/mockdta");
}

IndexPage.jsx

import React from 'react';
import {connect} from "dva";

import * as apis from "../services/example"

class IndexPage extends React.Component{
  handleSetName=()=>{
    this.props.dispatch({
      type:"indexTest/setName",
      data:{
        name:"猪猪侠"
      }
    })
  }
  handleSetNameAsync=()=>{
    this.props.dispatch({
      type:"indexTest/setNamaAsync",
      data:{
        name:"猪猪侠"
      }
    })
  }
  componentDidMount(){
    // apis.testCnode().then((res)=>{
    //   console.log(res);
    // })
    // 测试mock
    apis.mockdata().then((res)=>{
      console.log(res);
    })

  }
  testCnode=()=>{
    this.props.dispatch({
      type:"indexTest/testCnode"
    })
  }
  render(){
    console.log(this.props.cnodeData);
    return (
      <div>
        我是首页
        {this.props.msg}
        <div>
          {
            this.props.name
          }
        </div>
        <button onClick={this.handleSetName}>setName</button>
        <button onClick={this.handleSetNameAsync}>setNameAsync</button>
        <button onClick={this.testCnode}>testCnode</button>
      </div>
    )
  }
}
const mapStateToProps=state=>{
  return {
    msg:"我爱北京天安门",
    name:state.indexTest.name ,
    cnodeData:state.indexTest.cnodeData
  }
}
export default connect(mapStateToProps)(IndexPage);

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wespten

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值