最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • react 監聽 search 變化

    正文概述 掘金(Darcrandex)   2020-12-18   641

    原文链接

    業務場景

    1. A 頁面中存在查詢表單,表單的更新能被保存,並且在頁面刷新後,保留參數項。
    2. 從 B 頁面跳轉到 A 頁面,並攜帶查詢參數。到達 A 頁面後,能獲得參數。

    實現

    1. 使用類裝飾器
    2. 允許使用默認值
    3. 自動監聽search的變化
    4. 自動將search轉化為對象
    5. 提供search字符串和對象的互轉工具函數

    代码

    import { withRouter } from "react-router-dom";
    
    /**
     * @desc 将Location中的search字符串转换为对象
     * @param {string} search
     */
    export function getSearchObject(search = "") {
      const result = {};
      if (search) {
        const searchStr = search.split("?")[1];
        const searchKeyValueArr = searchStr.split("&");
        for (let i = 0; i < searchKeyValueArr.length; i++) {
          const [key, value] = searchKeyValueArr[i].split("=");
          result[key] = decodeURIComponent(value);
        }
      }
    
      return result;
    }
    
    /**
     * @desc 将对象转化为search字符串
     * @param {object} obj
     */
    export function objectToSearch(obj = {}) {
      let searchStr = "";
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          const value = encodeURIComponent(obj[key]);
          searchStr += `${key}=${value}&`;
        }
      }
    
      return searchStr ? "?" + searchStr.slice(0, -1) : "";
    }
    
    /**
     * @desc 可监听search变化的装饰器
     *
     * @desc 限制:
     * @desc state.search用于存放参数对象,不能命名冲突
     * @desc onRouteSearchUpdate用于监听更新,不能命名冲突
     *
     * @param {boolean?} listenOnDidMount 是否在组件初始化时就触发'onRouteSearchUpdate'
     */
    export default function withSearchListener(listenOnDidMount = true) {
      let initSearch = {};
    
      return (WrappedComponent) =>
        withRouter(
          class extends WrappedComponent {
            componentDidMount() {
              // 初始化默认的search
              initSearch = this.state.search || {};
    
              if (
                typeof WrappedComponent.prototype.componentDidMount === "function"
              ) {
                WrappedComponent.prototype.componentDidMount.call(this);
              }
    
              if (listenOnDidMount) {
                this.onRouteSearchUpdate(
                  getSearchObject(this.props.location.search),
                  this.props.location
                );
              }
            }
    
            componentDidUpdate(prevProps) {
              if (
                typeof WrappedComponent.prototype.componentDidUpdate === "function"
              ) {
                WrappedComponent.prototype.componentDidUpdate.call(this);
              }
    
              if (prevProps.location.search !== this.props.location.search) {
                this.onRouteSearchUpdate(
                  getSearchObject(this.props.location.search),
                  this.props.location
                );
              }
            }
    
            /**
             * @desc 当路由中的'search'更新时触发
             * @param {string?} search
             * @param {object?} location
             */
            onRouteSearchUpdate(search = {}, location = {}) {
              // 根据默认的search来合并出新的search
              const nextSearch = { ...initSearch, ...search };
    
              this.setState({ search: nextSearch }, () => {
                if (
                  typeof WrappedComponent.prototype.onRouteSearchUpdate ===
                  "function"
                ) {
                  WrappedComponent.prototype.onRouteSearchUpdate.call(
                    this,
                    nextSearch,
                    location
                  );
                }
              });
            }
          }
        );
    }
    

    使用

    import React, { Component } from "react";
    import withSearchListener, { objectToSearch } from "@/utils/search-listener";
    
    @withSearchListener()
    class App extends Component {
      state = { search: { a: "", b: "" } };
      componentDidMount() {
        console.log(this.state.search);
      }
      onRouteSearchUpdate(search = {}, location = {}) {
        console.log(this.state.search);
      }
    
      render() {
        return "";
      }
    }
    

    路徑映射成對象的關係

    {
      "/page-a?a=123&b=456": { "a": "123", "b": "456" },
      "/page-a?a=123": { "a": "123", "b": "" },
      "/page-a?a=123&b=456&c=789": { "a": "123", "b": "456", "c": "789" }
    }
    

    起源地下载网 » react 監聽 search 變化

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元