Dva.js

点击访问 Dva.js 官网

1、安装创建

  • 安装:npm install dva-cli -g
  • 创建:dva new 项目名称
  • 启动:npm start
  • 目录结构:

在这里插入图片描述

2、Demo

2.1、改造项目结构

在这里插入图片描述

2.2、CODE

· index.js

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

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

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

// 3. Model
app.model(require('./models/simpleDemo').default);
app.model(require('./models/asyncDemo').default);

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

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

· index.css

html,
body,
:global(#root) {
  height: 100%;
}

* {
  margin: 0;
  padding: 0;
}

· router.js

import React from 'react'
import { Router, Route, Switch, Redirect } from 'dva/router'
import App from './routes/App'
import Film from './routes/Film'
import Cinema from './routes/Cinema';
import Center from './routes/Center';
import Detail from './routes/Detail';
import Login from './routes/Login';

function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path='/login' component={Login} />
        <Route path="/" render={() => (
          <App>
            <Switch>
              <Route path="/film" component={Film} />
              <Route path="/cinema" component={Cinema} />
              <Route path="/center" render={props => !!sessionStorage.getItem('token') ? <Center {...props} /> : <Redirect to='/login' />} />
              <Route path="/detail/:id" component={Detail} />

              <Redirect from='/' to='film' />
            </Switch>
          </App>
        )} />
      </Switch>
    </Router>
  );
}

export default RouterConfig;

· components/Tabbar.js

import { NavLink } from 'dva/router'
import React from 'react'
import style from './Tabbar.css'

export default function Tabbar() {
    return (
        <footer>
            <ul>
                <li>
                    <NavLink to='/film' activeClassName={style.active}>Film</NavLink>
                </li>
                <li>
                    <NavLink to='/cinema' activeClassName={style.active}>Cinema</NavLink>
                </li>
                <li>
                    <NavLink to='/center' activeClassName={style.active}>Center</NavLink>
                </li>
            </ul>
        </footer>
    )
}

· components/Tabbar.css

footer {
    position: fixed;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 50px;
    line-height: 50px;
    text-align: center;
    background: #fff;
}

footer ul {
    list-style: none;
    display: flex;
}

footer ul li {
    flex: 1;
}

.active {
    color: #f00;
}

· routes/App.js

import React from 'react'
import Tabbar from '../components/Tabbar'

export default function App({ children }) {
    return (
        <div>
            App
            {children}
            <Tabbar />
        </div>
    )
}

· routes/Center.js

import { connect } from 'dva'
import React, { useState } from 'react'

function Center({ list, dispatch, history }) {

    useState(() => {
        dispatch({ type: 'async/getList' })
    }, [])

    const logout = () => {
        sessionStorage.clear()
        history.push('/login')
    }

    return (
        <div>
            Center<br />
            <button onClick={logout}>退出登录</button>
            <hr />
            <ul>
                {
                    list?.map(i => (
                        <li key={i.id}>
                            {i.nm}<br />
                            <img src={i.img} alt={i.nm} style={{ width: 100 }} />
                        </li>
                    ))
                }
            </ul>
        </div>
    )
}

export default connect((mapStateToProps, mapDispatchToProps, mergeProps, options) => {
    return {
        list: mapStateToProps.async.list
    }
})(Center)

· routes/Cinema.js

import { connect } from 'dva'
import React, { useState } from 'react'

function Cinema({ name, age, list, dispatch }) {

    useState(() => {
        dispatch({ type: 'demo/getList' })
    }, [])

    const changeName = () => {
        dispatch({
            type: 'demo/save',
            payload: {
                name: name.split('-')[0] + '-' + new Date().getTime()
            }
        })
    }

    return (
        <div>
            <h4>Cinema:</h4>
            {`name: ${name} / age: ${age}`}<br />
            <button onClick={changeName}>随机修改name</button>
            <h4>影院列表:</h4>
            <ul>
                {
                    list?.map(c => (<li key={c.cinemaId}>{c.name}</li>))
                }
            </ul>
        </div>
    )
}

export default connect((mapStateToProps, mapDispatchToProps, mergeProps, options) => {
    console.log(mapStateToProps, mapDispatchToProps, mergeProps, options)
    return {
        name: mapStateToProps.demo.name,
        age: 3.1415926,
        list: mapStateToProps.demo.list
    }
})(Cinema)

· routes/Detail.js

import React from 'react'

export default function Detail({ match: { params: { id } } }) {
    return (
        <div>Detail:{id}</div>
    )
}

· routes/Film.js

import React, { useEffect, useState } from 'react'
import request from '../utils/request'

export default function Film({ history }) {

    const [films, setFilms] = useState([])

    useEffect(() => {
        request('https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=6926685', {
            headers: {
                'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"16722839631329013205237761","bc":"110100"}',
                'X-Host': 'mall.film-ticket.film.list'
            }
        }).then(({ data: { data: { films } } }) => setFilms(films))
    }, [])

    return (
        <>{
            films?.map(film => (
                <li key={film?.filmId} onClick={() => history.push(`/detail/${film.filmId}`)}>
                    <span>{film?.name}</span><br />
                    <img src={film?.poster} alt={film.name} style={{ width: 100 }} />
                </li>
            ))
        }</>
    )
}

· routes/Login.js

import React from 'react'

export default function Login({ history }) {

    const login = () => {
        sessionStorage.setItem('token', 'xxx')
        history.push('/')
    }

    return (
        <div>
            Login<br />
            <button onClick={login}>登录</button>
        </div>
    )
}

· models/asyncDemo.js

import { getShowList } from '../services/demo'

// 跨域model(在 .weboackrc 配置代理)
export default {
    namespace: 'async',

    state: {
        list: []
    },

    effects: {
        *getList({ payload }, { call, put }) {
            const { data: { data: { hot } } } = yield call(getShowList, payload)
            yield put({
                type: 'save',
                payload: {
                    list: hot
                }
            })
        }
    },

    reducers: {
        save: (preState, { payload }) => {
            return {
                ...preState,
                ...payload
            }
        }
    }
}

· models/simpleDemo.js

import { getCinemaList } from '../services/demo'

export default {

    namespace: 'demo',

    state: {
        name: '嘎嘎嘎',
        list: []
    },

    // 订阅
    subscriptions: {
        setup({ dispatch, history }) {
            console.log('初始化')
            console.log('dispatch==>', dispatch)
            console.log('history==>', history)
        },
    },

    // 专门负责异步获取数据: redux-saga
    effects: {
        *getList({ payload }, { call, put }) {
            const { data: { data: { cinemas } } } = yield call(getCinemaList)
            yield put({
                type: 'save',
                payload: {
                    list: cinemas
                }
            });
        },
    },

    // 专门负责修改state
    reducers: {
        save(state, action) {
            return { ...state, ...action.payload };
        },
    }
}

· services/demo.js

import request from '../utils/request';

export function getCinemaList() {
  return request('https://m.maizuo.com/gateway?cityId=110100&ticketFlag=1&k=9546096', {
    headers: {
      'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"16722839631329013205237761","bc":"110100"}',
      'X-Host': 'mall.film-ticket.cinema.list'
    }
  });
}


export function getShowList() {
  return request('/api/mmdb/movie/v3/list/hot.json?ct=%E5%A4%A7%E8%BF%9E&ci=65&channelId=4');
}

· .webpackrc

{
    "proxy": {
        "/api": {
            "target": "https://i.maoyan.com",
            "changeOrigin": true
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

纯纯的小白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值