专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
码农翻身  ·  漫画 | 为什么大家都愿意进入外企? ·  昨天  
程序员的那些事  ·  OpenAI ... ·  昨天  
OSC开源社区  ·  升级到Svelte ... ·  4 天前  
程序猿  ·  “我真的受够了Ubuntu!” ·  3 天前  
程序员的那些事  ·  惊!小偷“零元购”后竟向 DeepSeek ... ·  3 天前  
51好读  ›  专栏  ›  SegmentFault思否

从 loading 的 9 种写法谈 React 业务开发

SegmentFault思否  · 公众号  · 程序员  · 2019-01-10 08:00

正文


前言

这是一篇比较全面讲解 React 的文章,里面很多基础知识希望你自己一边查阅资料一边学习。全文从业务开发中最常用见 loading 效果不同是实现讲起,说下现在前端开发在业务上应该有的思考。

入门级操作

State

State: https://reactjs.org/docs/state-and-lifecycle.html

最简单的实现,我们在 Loading 组件内部声明一个状态,通过代码逻辑判断 loading 效果的展示。

  1. export default class extends Component {

  2.  ...

  3.  render() {

  4.    return this.state.loading ? <div className="loader" /> :

    finishdiv>;
  5.  }

  6. }

  7. 完整演示:https://codesandbox.io/s/j22nqo2k4y。

    Props

    Props:https://reactjs.org/docs/components-and-props.html

    随着业务的发展,这个 Loading 组件用到的地方会非常多,上面这个代码耦合了很多逻辑,为了让这个组件能够很好的复用,那我们抽离出组件的业务逻辑,将内部状态进行提升,那这个组件就是一个能被复用的 UI 组件。

    1. export default function(props) {

    2.  return props.loading ? <div className="loader" /> :

      finishdiv>;
    3. }

    4. 完整演示:https://codesandbox.io/s/k39472w027。

      注:上面两段代码你可能会想,为什么 FuncClass 都能实现一个组件,他们有什么差别吗?

      其实你在开发时不容易感觉到差别,但 React 本身是进行了很多差别处理,如果是 Class 类,React 会用 new 关键字实例化,然后调用该实例的 render 方法,如果是 Func 函数,React 会直接调用它。

      Refs

      Refs:https://reactjs.org/docs/refs-and-the-dom.html

      如果你是一个 jQuery 转型 React 的开发,会很自然的想到,我找到 Loading 组件的节点,控制他的显示与隐藏,当然这也是可以的,React 提供 Refs 方便你访问 DOM 节点 或 React 元素。

      1. export default class extends Component {

      2.  componentDidMount() {

      3.    fetch().then(() => {

      4.      this.el.changeLoading(false);

      5.    });

      6.  }


      7.  render() {

      8.    return (

      9.      <Loading ref={el => { this.el = el; }} />

      10.    );

      11.   }

      12. }

      完整演示:https://codesandbox.io/s/ywwmm3j46z。

      通用逻辑抽离

      当你的应用做到一定的复杂度,不同的页面都会有 loading 效果,你肯定不希望每个页面都重复的书写一样的逻辑,这样会导致你的代码重复且混乱。

      React 中有两个比较常见的解决方案 HOCRenderProps,其实这两个这两个概念都是不依赖 React 的。

      让我们暂时忘掉 React,下面我对 HOCRenderProps 写两个例子,你会发现组件复用是如此简单。

      HOC

      HOC:https://reactjs.org/docs/higher-order-components.html

      HOC 其实就是一种装饰器模式,它接受一个组件作为参数,然后返回相同的组件,这样就可以额外增加一些功能。

      1. const func = () => {

      2.  console.log("func");

      3. };


      4. const wrap = func => {

      5.  console.log("wrap");

      6.  return func;

      7. };


      8. // wrap 逻辑已被复用

      9. wrap(func)();

      完整演示:https://codesandbox.io/s/8zx85nrzk2。

      Render Props

      Render Props:https://reactjs.org/docs/render-props.html

      Render Props 就是我们给一个函数传递一个回调函数做为参数,该回调函数就能利用外面函数的执行结果做为参数,执行任何操作。

      1. const func = param => {

      2.  console.log("func");

      3. };


      4. const wrap = (param, func) => {

      5.  console.log("wrap");

      6.  func(param);

      7. };


      8. // wrap 逻辑已被复用

      9. wrap("", func);

      完整演示:https://codesandbox.io/s/0v1p4rp7xv。

      相同点:

      • 两者都能很好的帮助我们 重用组件逻辑

      • 和回调函数类似,当嵌套层数很多时,会造成 回调地狱

      不同点:

      • HOC 和 父组件有相同属性名属性传递过来,会造成属性丢失;

      • Render Props 你只需要实例化一个中间类,而 HOC 你每次调用的地方都需要额外实例化一个中间类。

      总的来说,在需要复用组件逻辑的时候,我个人更倾向于 Render Props 的方式。

      复杂状态管理

      当你的应用越来越大,组件之间交互越来越复杂,那整个页面的数据逻辑将变得难以管理,这时候为了方便管理应用的状态,你可以选择一些状态管理工具,例如 Redux(https://github.com/reduxjs/redux)、Flux(https://github.com/facebook/flux)、dva(https://github.com/dvajs/dva) 等。

      Redux

      Redux:https://redux.js.org/

      我不太想谈这些数据流框架,因为他们的概念 actionstoredispatch 太过于生涩难懂。

      现代前端框架 React 和 Vue 其实都是一个套路,通过数据渲染试图,然后视图上操作反过来更新数据,重新渲染视图,刷新页面。

      数据叫做 store,动作叫做 ation,触发行为叫 dispatch,然后数据到视图的渲染由 React/Vue 处理的。

      1. // reducers.js

      2. const initialState = {

      3.  loading: false

      4. };


      5. export default function reducer(state = initialState, action) {

      6.  switch (action.type) {

      7.    case "CHANGE_LOADING":

      8.      return {

      9.        loading: action.payload

      10.      };

      11.    default:

      12.      return state;

      13.  }

      14. }

      完整演示:https://codesandbox.io/s/94zoy50q6w。

      Saga

      Saga:https://redux-saga.js.org/

      当你代码中有大量的异步操作时,例如 fetch 请求,你肯定会想到 事件监听回调函数发布/订阅

      很好,上一个例子其实就是 事件监听的处理方式,然后 回调函数的主流的解决方案是 redux-thunk(https://github.com/reduxjs/redux-thunk),而 发布/订阅的主流解决方案是 saga。

      1. import { takeLatest, put } from "redux-saga/effects";


      2. import fetch from "./fetch";


      3. function* fetchInfo(action) {

      4.   yield put({

      5.    type: "CHANGE_LOADING",

      6.    payload: true

      7.  });


      8.  yield fetch();


      9.  yield put({

      10.    type: "CHANGE_LOADING",

      11.    payload: false

      12.  });

      13. }


      14. export default function* fetchSaga() {

      15.  yield takeLatest("FETCH_REQUEST", fetchInfo);

      16. }

      完整演示:https://codesandbox.io/s/rrnp9vk3wp。

      当你耐心看到这里,我知道你对 React 肯定有一定的经验,现在还可以做很多,例如把 loading 状态提升到 Store 的顶部,那整个站点就只有一个 loading 了,然后你还可以将 fetch 再封装一个 HOC 修改 loading 状态,这就是一个相对完美的 loading,其实 React 业务开发都可以用这个套路。

      新的 API

      Context

      Context:https://reactjs.org/docs/context.html

      上面 redux 的例子是不是过于复杂。

      对于简单的业务,虽然有很多页面,嵌套层次也很复杂,你当然可以不用状态管理工具,你可以试着使用 Context,它可以方便你传递数据,它其实就是 Render Props 的一种实现。

      1. export







请到「今天看啥」查看全文