Umi@2.x

249 阅读2分钟

umi APi

umi/withRouter

umi-withRouter.png

Umi@2.x中使用 dva

>= umi@2起,dva的整合可以直接通过 umi-plugin-react 来配置。

特性

  • 按目录约定注册 model,无需手动 app.model
  • 文件名即 namespace,可以省去 model 导出的 namespace key
  • 无需手写 router.js,交给 umi 处理,支持 model 和 component 的按需加载
  • 内置 query-string 处理,无需再手动解码和编码
  • 内置 dva-loading 和 dva-immer,其中 dva-immer 需通过配置开启
  • 开箱即用,无需安装额外依赖,比如 dva、dva-loading、dva-immer、path-to-regexp、object-assign、react、react-dom 等。
yarn add umi-plugin-react

然后在 .umirc.js 里配置插件:

export default {
  plugins: [
    [
      'umi-plugin-react',
      {
        dva: true,
      },
    ]
  ],
};

定义 dva model

dva-model.png

组件连接dva model

comp-connect-dva-model.png

dva-immer

推荐开启 dva-immer 以简化 reducer 编写

export default {
  plugins: [
    [
      'umi-plugin-react',
      {
        dva: {
          immer: true
        }
      }
    ],
  ],
};

开启了 dva-immer 之后,编写 reducers 就方便了:

reducers: {
    updateUserList(state, { payload }) {
        // return {
        //     ...state,
        //     userList: payload
        // }

        state.userList = payload
    },
    deleteUser(state, action) {
        // return {
        //     ...state,
        //     userList: state.userList.filter(user => user.id !== action.id)
        // }

        state.userList = state.userList.filter(user => user.id !== action.id)
    }
},

其实 reducers 可以写得更简单,仅仅写一个 setState 就可以了。dispatch 的时候,表明要改变的 state 即可。put({ type: 'setState', payload: {userInfo: userInfo}})

reducers: {
    setState(state, { payload }) {
        return  {
            ...state,
            ...payload
        }
    },
},

dva-loading 的使用

待异步请求方法成功之后,loading.effects['dvaTest/fetchUserList'] 得到 false。

const mapStateToProps = (state) => {
    const { loading } = state

    return {
        // `dvaTest/fetchUserList` 是 model 中异步请求方法
        userListLoading: loading.effects['dvaTest/fetchUserList']
    }
}

umi2.x 使用mock

v2.umijs.org/zh/guide/mo…

在项目根目录添加 mock 文件夹

// mock/users.js
export default {
    // 支持值为 Object 和 Array
    'GET /api/users': {
        name: 'alex.cheng',
        avatar: '',
        userid: '00000001',
        notifyCount: 12,
    },
  
    // GET POST 可省略
    '/api/users/1': { id: 1 },
  
    // 支持自定义函数,API 参考 express@4
    'POST /api/users/create': (req, res) => { res.end('OK'); },
  };

使用

fetch('http://recplus-test.jd.com:8000/api/users')
    .then(res => {
        console.log('????', res)
        return res.json()
    })
    .then(res => {
        console.log('res ', res)
    })

为了让数据更加丰富,我们可以引入 mockjs 来生成更加全面和丰富的模拟数据。

umi使用动态组件 dynamic

使用 umi 提供的 dynamic 方法,基于 react-loadable 实现。

下面这个例子是:3s 后渲染一个组件,在还未渲染时,通过 loading 方法设置一个 loading 组件。

import dynamic from 'umi/dynamic'

const DynamicComp = dynamic({
    loader: () => {
        return new Promise(r => {
            setTimeout(() => {
                r(() => <div>I will render after</div>)
            }, 3000);
        })
    },
    loading: () => {
        return (
            <div>Loading...</div>
        )
    }
})

umi权限路由

/src/pages/other/index.jsx 文件中,头部的注释是关键。index.jsx 会通过 ./src/routes/auth.jsx 文件来渲染。我们可以在 auth.jsx 中做逻辑处理和判断,决定是否需要渲染index.jsx 组件。

/**
 * title: chl other index page
 * Routes:
 *  - ./src/routes/auth.jsx
 */

const Other = function(props) {
  return (
    <div className={styles.normal}>
      <h1>{props.flag}</h1>
      <Button onClick={() => setLocale('zh-CN')}>setLocale</Button>
    </div>
  );
}

export default connect(state => {
    return {
        flag: state.localModels.key
    }
})(Other)

/src/routes/auth.jsx

const Auth = (props) => {
    const [show, setShow] = useState(false)
    return (
        <div>
            <Button onClick={() => setShow(!show)}>权限路由</Button>
            {show && props.children}
        </div>
    );
}
 
export default Auth;