的translate插件_知否 ?知否 ?React插件了解一下!

为什么选择插件,而不是组件?

  • 调用简单  this.$toast("xxx") ,不必再模板中提前定义 , 动态插入移除
  • 插件独立于业务
  • 更新不影响代码逻辑,做到热更新
  • 抽象,封装
  • 适用于toast,Dialog,Alert,Message,picker,Actionsheet等组件
2eccb620d07101142e0f9103896ddb4d.gif

react-toast-alert demo地址

使用方法:

import $ from '@/component/Toast/index';

...

$.toast({
 type:0,
 content: "我是默认Toast",
 time: 1000,
 opacity: .5,
 onSucc() {
  console.log("我是Toast的回调!")
 }
 });

$.toast("我是默认Toast");


$.toast({
 type:3,
 content: "我是默认loading",
 time: 1000,
});

setTimeout(() => {  //3s后隐藏
 $.hide();
}, 3000);


$.dialog({
 type: 0,
 opacity:0.5,
 title: "我是title",
 content: "我是content",
 btnSucc: "我是成功",
 btnFail: "我是取消",
 onSucc(e) {
  e.stopPropagation();
  $.toast("我是默认Toast");
 },
 onFail(e) {
  e.stopPropagation();
  console.log("我是失败的回调!");
 }
});

Vue 插件

在Vue里,一般将toast,alert等非业务相关的写成插件,挂载在Vue的原型链上,使用的时候直接this.$toast即可,非常方便!相关原理在这里就不说了,感兴趣的可以查阅官网. 先看看Vue的插件写法:

@/components/vue-toast/index.js

import ToastComponent from "./vue-toast.vue"; // 引入先前写好的vue
var Toast = {};
//避免重复install,设立flag
Toast.installed = false;
Toast.install = function(Vue, options = {
 type: "success", //success fail  warning loading toast
 msg: "操作成功",
 time: 1000,
 callback() {

 }
}) {
 if(Toast.installed) return;
 var obj;
 Vue.prototype.$toast = (config = {}, type) => {
  if(type == 'close') {
   obj && obj.removeToast();
   return false;
  }
  if(typeof config=="object"){
   config = {
    ...options,
    ...config
   }
  }else{
   config = {
    ...options,
    ...{
     type: "toast", 
                 msg: config
    }
   }
  }
  
  // 如果页面有toast则不继续执行
  if(document.querySelector('.vue-toast')) return;
  // 1、创建构造器,定义好提示信息的模板
  const toastTip = Vue.extend(ToastComponent);
  obj = new toastTip();

  for(var property in config) {
   obj[property] = config[property];
  }

  //删除弹框
  obj.removeToast = function() {
   document.body.removeChild(tpl);
  }

  //插入页面
  let tpl = obj.$mount().$el;
  document.body.appendChild(tpl);
  Toast.installed = true;

  if(['success', 'fail', 'warning','toast'].indexOf(config.type) > -1) {
   setTimeout(() => {
    obj.removeToast();
    obj.callback();
   }, config.time)
  }

  ['close'].forEach(function(type) {
   Vue.prototype.$toast[type] = function(msg) {
    return Vue.prototype.$toast({}, type)
   }
  });
 };
};
// 自动安装  ,有了ES6就不要写AMD,CMD了
if(typeof window !== 'undefined' && window.Vue) {
 window.Vue.use(Toast)
};

export default Toast

@/components/vue-toast/vue-toast.vue

<template>
  <div class="mask vue-toast">
    <div>
      <div class="toast" v-if="['success', 'fail', 'warning','loading'].indexOf(type) > -1">
        <div class="icon" v-if="['success', 'fail', 'warning'].indexOf(type) > -1">
          <div v-if="type=='success'" class="success-icon">div>
          <div v-if="type=='fail'" class="fail-icon">div>
          <div v-if="type=='warning'" class="warning-icon">div>
        div>
        <div class="loading-icon" v-else>
          <span>span>
          <span>span>
          <span>span>
          <span>span>
          <span>span>
          <span>span>
          <span>span>
          <span>span>
          <span>span>
          <span>span>
          <span>span>
          <span>span>
        div>
        <div class="msg" v-html="msg">div>
      div>
      <div v-else class="toast-msg" v-html="msg">div>
    div>
  div>
template>
<script>export default {
  data() {return {msg: " ",type: "success"
    };
  }
};script>
<style scoped="scoped " lang="less">
.mask {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.4);
  position: fixed;
  left: 0px;
  top: 0px;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 10000;
  .toast-msg {
    font-size: 0.24rem;
    text-align: center;
    position: relative;
    transform: translateX(-50%);
    color: #fff;
    left: 50%;
    padding: 0.18rem 0.27rem;
    overflow: hidden;
    border-radius: 4px;
    white-space: nowrap;
    display: block;
    background: rgba(0, 0, 0, 0.7);
  }
  .toast {
    font-size: 0rem;
    padding: 0.27rem .090rem;
    width: 2.26rem;
    overflow: hidden;
    display: flex;
    align-items: center;
    flex-direction: column;
    color: #f2f2f2;
    background: rgba(51, 51, 51, 0.94);
    border-radius: 0.09rem;
    text-align: center;
    .icon {
      width: 0.72rem;
      height: 0.72rem;
      border-radius: 50%;
      border: 1px solid #f2f2f2;
      position: relative;
      justify-content: center;
      align-items: center;
      display: flex;
      
      position: relative;
      .success-icon {
        border-right: 1px solid #f2f2f2;
        border-bottom: 1px solid #f2f2f2;
        transform: rotate(45deg);
        width: 0.27rem;
        height: 0.45rem;
        margin-top: -0.18rem;
      }
      .fail-icon {
        &:before {
          content: " ";
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%) rotate(45deg);
          border-top: 1px solid #f2f2f2;
          width: 0.5rem;
          height: 0px;
        }
        &:after {
          content: " ";
          content: " ";
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%) rotate(-45deg);
          border-top: 1px solid #f2f2f2;
          width: 0.5rem;
          height: 0px;
        }
      }
      .warning-icon {
        &:before {
          content: " ";
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -500%) rotate(90deg);
          border-top: 1px solid #f2f2f2;
          width: 0.27rem;
          height: 0px;
        }
        &:after {
          content: " ";
          content: " ";
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, 250%) rotate(-45deg);
          background: #f2f2f2;
          width: 3px;
          border-radius: 50%;
          height: 3px;
        }
      }
    }
    .msg {
      margin-top: 0.18rem;
      font-size: 0.24rem;
    }
  }
}

.loading-icon {
  font-size: 0px;
  box-sizing: border-box;
  width: 0.72rem;
  height: 0.72rem;
  position: relative;
  span {
    position: absolute;
    height: 1px;
    left: 50%;
    top: 50%;
    width: 0.18rem;
    animation: loading-fade-light 1.1s infinite linear;
    background: rgba(255, 255, 255, 0.3);
    transform-origin: -0.18rem 50%;
    margin-left: 0.18rem;
    &:nth-child(1) {
      animation-delay: 0s;
      transform: rotate(0deg);
    }
    &:nth-child(2) {
      animation-delay: 0.1s;
      transform: rotate(30deg);
    }
    &:nth-child(3) {
      animation-delay: 0.2s;
      transform: rotate(60deg);
    }
    &:nth-child(4) {
      animation-delay: 0.3s;
      transform: rotate(90deg);
    }
    &:nth-child(5) {
      animation-delay: 0.4s;
      transform: rotate(120deg);
    }
    &:nth-child(6) {
      animation-delay: 0.5s;
      transform: rotate(150deg);
    }
    &:nth-child(7) {
      animation-delay: 0.6s;
      transform: rotate(180deg);
    }
    &:nth-child(8) {
      animation-delay: 0.7s;
      transform: rotate(210deg);
    }
    &:nth-child(9) {
      animation-delay: 0.8s;
      transform: rotate(240deg);
    }
    &:nth-child(10) {
      animation-delay: 0.9s;
      transform: rotate(270deg);
    }
    &:nth-child(11) {
      animation-delay: 1s;
      transform: rotate(300deg);
    }
    &:nth-child(12) {
      animation-delay: 1.1s;
      transform: rotate(330deg);
    }
  }
}

@-webkit-keyframes loading-fade-light {
  0% {
    background-color: #fff;
  }
  100% {
    background-color: rgba(255, 255, 255, 0);
  }
}

@keyframes loading-fade-light {
  0% {
    background-color: #fff;
  }
  100% {
    background-color: rgba(255, 255, 255, 0);
  }
}
style>

入口文件注册:

import vueToast from '@/components/vue-toast'
Vue.use(vueToast);

React 插件toast的封装

Toast/index.js

import React from "react";
import ReactDOM from 'react-dom';
import Toast from './toast';
 
export default class Global {
 static toastEle='';
 static toast(option) {
  var setting={
   type:0,
    content:"默认信息",
    time:2000,
    opacity:0,
    onSucc:()=>{}
  };
  
  if(typeof option =="string"){
   setting={...setting,content:option,type:4}
  }else{
   setting={...setting,...option}
  }
  
  this.show(0,setting);
  
  if(setting.type!==3){   //loading需要手动关闭
   setTimeout(() => {
    this.hide();
    setting.onSucc();
   }, setting.time);
  }
 }
 
 static dialog(option) {
   var setting={
    type:0,
    title:"我是默认title",
    content:"我是默认content",
    btnSucc:"我是默认btn",
    CloseShow:false,
    onClose(){
     console.log("蒙层回调");
      },
    onSucc(){
     console.log("成功回调");
      },
      onFail(){
       console.log("失败回调");
      }
   };
   
   setting={...setting,...option};
   
   this.show(1,setting);
 }
   
 
 static show(n,setting) {
  
  var div = document.createElement('div');
  var id = document.createAttribute("id");
  
  this.toastEle='pluginEle-'+new Date().getTime();
  
  id.value = this.toastEle;
  div.setAttributeNode(id);
  document.body.appendChild(div);
  ReactDOM.render(<Toast setting={setting} />, div);
 }
 static hide() {
  var toastEle = document.querySelector("#"+this.toastEle);
  if(toastEle){
   ReactDOM.unmountComponentAtNode(toastEle);
      document.body.removeChild(toastEle);
  }
 }
}

Toast/toast.js

import React from "react";
import './toast.less'

export default class Toast extends React.Component {
 constructor(props) {
  super(props);
 }

 checkToast(n) {
  switch(n) {
   case 0:
    return (<div className="icon"><div className="success-icon">div>div>)
    break;
   case 1:
    return (<div className="icon"><div className="fail-icon">div>div>)
    break;
      case 2:
    return (<div className="icon"><div className="warning-icon">div>div>)
    break;
      case 3:
    return (
               <div className="loading-icon"><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span>div>
           )
    break;
   default:
       return null
  }
 }

 render() {

  let {
   type,content,opacity = 0
  } = this.props.setting;

  let style = {
   "background": `rgba(0,0,0,${opacity})`
  }

  return(
   <div className="mask" style={style}><div className="toast">
           {this.checkToast(type)}<div className="msg">{content}div>div>div>
  );
 }
}

Toast/toast.less

.mask {
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.4);
    position: fixed;
    left: 0px;
    top: 0px;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 10000;
    .toast-msg {
        font-size: 24px;
        text-align: center;
        position: relative;
        transform: translateX(-50%);
        color: #fff;
        left: 50%;
        padding:18px 27px;
        overflow: hidden;
        border-radius: 4px;
        white-space: nowrap;
        display: block;
        background: rgba(0, 0, 0, 0.7);
    }
    .toast {
        font-size: 0px;
        padding: 27px 9px;
        width: 226px;
        overflow: hidden;
        display: flex;
        align-items: center;
        flex-direction: column;
        color: #f2f2f2;
        background: rgba(51, 51, 51, 0.94);
        border-radius: 9px;
        text-align: center;
        .icon {
            width:72px;
            height:72px;
            border-radius: 50%;
            border: 1px solid #f2f2f2;
            position: relative;
            justify-content: center;
            align-items: center;
            display: flex;
            position: relative;
            margin-bottom: 18px;
            .success-icon {
                border-right: 1px solid #f2f2f2;
                border-bottom: 1px solid #f2f2f2;
                transform: rotate(45deg);
                width:27px;
                height: 45px;
                margin-top: -18px;
                
            }
            .fail-icon {
                &:before {
                    content: " ";
                    position: absolute;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%) rotate(45deg);
                    border-top: 1px solid #f2f2f2;
                    width: 50px;
                    height: 0px;
                }
                &:after {
                    content: " ";
                    content: " ";
                    position: absolute;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%) rotate(-45deg);
                    border-top: 1px solid #f2f2f2;
                    width: 50px;
                    height: 0px;
                }
            }
            .warning-icon {
                &:before {
                    content: "";
                    display: block;
                    position: absolute;
                    top: 15px;
                    left: 50%;
                    background:#f2f2f2;
                    width:1px;
                    height: 30px;
                }
                &:after {
                    content: "";
                    position: absolute;
                    bottom: 14px;
                    left: 50%;
                    background:#f2f2f2;
                    width: 6px;
                    margin-left: -2px;
                    border-radius: 50%;
                    height: 6px;
                }
            }
        }
        .msg {
            
            font-size:24px;
        }
    }
}

.loading-icon {
    font-size: 0px;
    margin-bottom: 18px;
    box-sizing: border-box;
    width: 72px;
    height: 72px;
    position: relative;
    span {
        position: absolute;
        height: 1px;
        left: 50%;
        top: 50%;
        width: 18px;
        animation: loading-fade-light 1.1s infinite linear;
        background: rgba(255, 255, 255, 0.3);
        transform-origin: -18px 50%;
        margin-left: 18px;
        &:nth-child(1) {
            animation-delay: 0s;
            transform: rotate(0deg);
        }
        &:nth-child(2) {
            animation-delay: 0.1s;
            transform: rotate(30deg);
        }
        &:nth-child(3) {
            animation-delay: 0.2s;
            transform: rotate(60deg);
        }
        &:nth-child(4) {
            animation-delay: 0.3s;
            transform: rotate(90deg);
        }
        &:nth-child(5) {
            animation-delay: 0.4s;
            transform: rotate(120deg);
        }
        &:nth-child(6) {
            animation-delay: 0.5s;
            transform: rotate(150deg);
        }
        &:nth-child(7) {
            animation-delay: 0.6s;
            transform: rotate(180deg);
        }
        &:nth-child(8) {
            animation-delay: 0.7s;
            transform: rotate(210deg);
        }
        &:nth-child(9) {
            animation-delay: 0.8s;
            transform: rotate(240deg);
        }
        &:nth-child(10) {
            animation-delay: 0.9s;
            transform: rotate(270deg);
        }
        &:nth-child(11) {
            animation-delay: 1s;
            transform: rotate(300deg);
        }
        &:nth-child(12) {
            animation-delay: 1.1s;
            transform: rotate(330deg);
        }
    }
}

@-webkit-keyframes loading-fade-light {
    0% {
        background-color: #fff;
    }
    100% {
        background-color: rgba(255, 255, 255, 0);
    }
}

@keyframes loading-fade-light {
    0% {
        background-color: #fff;
    }
    100% {
        background-color: rgba(255, 255, 255, 0);
    }
}

使用

import $ from '@/component/Toast/index';

...

$.toast({
 type:0,
 content: "我是默认Toast",
 time: 1000,
 opacity: .5,
 onSucc() {
  console.log("我是Toast的回调!")
 }
});
  
$.toast("我是默认Toast");

为什么不挂载在React原型链上?

有坑!主要原因还是React组件的this神出鬼没!

ES6 toast插件


var body = document.body
var tip
var timeout
var time = 3000
var setStyleTime = 50
function Tip (str, time) {
  if (tip) {
    clearTimeout(timeout)
    // tip.find('p').html(str);
  } else {
    tip = document.createElement('div')
    tip.className = '__toast'
    tip.innerHTML = str
    // tip.style.cssText = 'z-index: 999;position: fixed;webkit-transition: opacity .3s ease;transition: opacity .3s ease;opacity: 0;color: #fff;border-radius: 8px;left: 50%;width: 80%;margin-left: -40%; /*px*/text-align: center;line-height: 1.5;background: rgba(0,0,0,.6);padding: 1% 1%;top: 45%;box-sizing: border-box;font-size: 1.5em;';
    body.appendChild(tip)
    setTimeout(function () {
      tip.style.opacity = 1
    }, setStyleTime)
  }
  timeout = clear(time)
}

function clear (time) {
  return setTimeout(remove, time)
}

function remove () {
  if (tip) {
    body.removeChild(tip)
    tip = null
  }
}

function entry (msg, expire) {
  msg = msg || ''
  if (!expire || expire <= setStyleTime) {
    expire = time
  }

  Tip(msg, expire)
};

export default entry

附:React开发技巧

自动注册全局组件或函数 require.context

我的业务场景大部分是中后台,虽然封装和使用了很多第三方组件,但还是免不了需要自己封装和使用很多业务组件。但每次用的时候还需要手动引入,真的是有些麻烦的。

/**
 * @desc webpack打包入口文件  
 * @example 自动引入子目录下所有js文件
 */
let moduleExports = {};

const r = require.context('./', true, /^\.\/.+\/.+\.js$/);
r.keys().forEach(key => {
    let attr = key.substring(key.lastIndexOf('/') + 1, key.lastIndexOf('.'));
    moduleExports[attr] = r(key);
});

module.exports = moduleExports;
9d9e8f419912a285f68fd341b0d5e5bf.png

我们其实可以基于 webpack 的require.context来实现自动加载组件并注册的全局的功能。相关原理在之前的文章中已经阐述过了。具体代码如下

9e468dde2ecf3cb5ba4af76f4a2ade44.png我们可以创建一个GlobalComponents文件夹,将你想要注册到全局的组件都放在这个文件夹里,在index.js里面放上如上代码。之后只要在入口文件main.js中引入即可。

//main.js
import './components/Table/index' // 自动注册全局业务组件

这样我们可以在模板中直接使用这些全局组建了。不需要再繁琐的手动引入了。

一把梭改变state值

this.setState({
   [name]: value
  });
const { data } = this.state;
this.setState({ data: {...data, key: 1 } });

另外一种可以通过callback的方式改变state的值

this.setState(({ data }) => ({ data: {...data, key: 1 } }));

还可以:

this.setState((state, props) => {
    return { counter: state.counter + props.step };
});

还可以一把梭:

this.state.a=1;
this.state.b="张三";
this.state.c=true;
this.state.xxx=...
...

this.setState(this.state);   //一把梭

this.setState支持异步async await

 this.setState((prevState) => ({
  isFiltered: !prevState.isFiltered
 }), () => {
  this.filterData();
 });
 clickMe=(e)=>{
    this.setState((prevState)=>{
      return {num:prevState.num+1}
    });
 }
  async clickMe1(){
    await this.setState((prevState)=>{
      return {num:prevState.num+1}
    });
    await this.setState((prevState)=>{
      return {num:prevState.num+1}
    });
    await this.setState((prevState)=>{
      return {num:prevState.num+1}
    });
  }

唯一key

react数组循环,基本都会设置一个唯一的key,表格的对象数组循环一般没什么问题,数据基本都会有一个id。那有种情况就比较坑了,出现在表单形式的页面结构中,对某个数组进行增删改操作,一般对于非对象数组而言,没有id,可能很多人会偷懒,循环的时候,直接设置数组的下标index作为key,当出现增删改时候,就会出现数据对不上或者重新渲染组件的问题等。解决方案有很多种,例如把字符串数组等重组对象数组,每个元素设置一个唯一id等。另外有个方式:推荐使用shortid生成唯一key的数组,和数据数组一起使用,省去提交数据时再重组数组。

import React from 'react';
import shortid from 'shortid';

class Demo extends React.Component {
    constructor(props) {
  super(props);
  this.state = {
   data: ['a', 'b', 'c']
  }
  this.dataKeys = this.state.data.map(v => shortid.generate());
 }
 
    deleteOne = index => { // 删除操作
        const { data } = this.state;
        this.setState({ data: data.filter((v, i) => i !== index) });
        this.dataKyes.splice(index, 1);
    }
    
    render() {
     return (
         <ul>
               {
                   data.map((v, i) => <li onClick={i => this.deleteOne(i)}  
                        key={this.dataKeys[i]}
                    >
                        {v}li>
                    )
               } ul>
     )
 }
}
// 稍微抽取,可以封装一个通用的组件

三目运算

通过判断值是否存在来控制元素是否显示,一般三目运算可以达到此效果,最简单的还是用短路的写法:

// 不错
const flag = 'something';
flag && <div>div>

// 很好
// 注意一般可能上面写法多一些,但当flag为0 的时页面上会显示0,用!!将其转为boolean避免坑,
// 代码也更规范
const flag = 'something';
!!flag && <div>div>

使用组件,传递props

const { data, type, something } = this.state;
<Demo data={data}type={type}something={something}
/>

也许另外一种传递方式更简洁:

const { data, type, something } = this.state;
<Demo 
    {...{ data, id, something }}
/>

简化props

组件的props有时候会定义很多,但是调用组件传递props的时候又想一个个传,不想一次性传递一个option对象,通过扩展运算符和解构赋值可以简化此操作:

const Demo = ({ prop1, prop2, prop3, ...restProps }) => (
    <div>
        xxxx
        { restProps.something }div>
)
// 父组件使用Demo
    prop1={xxx}
    prop2={xxx}
    something={xxx}
/>

优化React 性能

React 性能优化有很多种方式,那常见的一种就是在生命周期函数shouldComponentUpdate里面判断某些值或属性来控制组件是否重新再次渲染。

判断一般的字符串,数字或者基础的对象,数组都还是比较好处理,那嵌套的对象或者数组就比较麻烦了,对于这种,可以转成字符串处理,但属性值的位置不同时,那就无效了。

推荐使用lodash(或者其他的类似库)的isEqual对嵌套数组或对象进行判断(相比其他方式更简单些)

shouldComponentUpdate(nextProps, nextState) {
    if (_.isEqual(nextState.columns, this.state.columns)) return false;
    return true;
}

创建弹层

创建弹层的三种方式:

1.普通组件通过state和样式控制,在当前组件中显示弹层-每次引入组件并且render里面控制显示,挂载节点在某组件里面

// 弹层 
const Dialog = () => <div>弹层div>
// 某组件
render() {
    return (
        this.state.showDialog && <Dialog />
    )
}

2.通过Portals创建通道,在根节点外部挂载组件-但还是需要每次引入并且在render里面调用

// 弹层 
class Dialog extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement('div');
  }
  componentDidMount() {
    modalRoot.appendChild(this.el);
  }
  componentWillUnmount() {
    modalRoot.removeChild(this.el);
  }

  render() {
    return ReactDOM.createPortal(
      this.props.children || <div>xxxxdiv>,
      this.el,
    );
  }
}
// 某组件
render() {
    return (
        this.state.showDialog && <Dialog />
    )
}

3.推荐使用ReactDom.render创建弹层-挂载根节点外层,使用也更方便

// demo
let dialog;
class Dialog {
    show(children) {    // 显示
        this.div = document.createElement('div');
        document.body.appendChild(this.div);

        ReactDom.render(children || <div>xxxxdiv>, this.div);
    }
    destroy() {     // 销毁
        ReactDom.unmountComponentAtNode(this.div);
        this.div.parentNode.removeChild(this.div);
    }
}
export default {
    show: function(children) {
        dialog = new Dialog();
        dialog.show(children);
    },
    hide: xxxxx
};
// 某组件
import Dialog from 'xxx';
alert = () => {
    Dialog.show(xxxx);
}
render() {
    return (
        <button onClick={this.alert}>点击弹层button>
    )
}

插槽:children

render props是现在很流行的一种渲染方式,通过回调函数,渲染子组件,参数可为父组件的任意属性值(官网也有相应的介绍)新版的contextApi也采用了这个模式。

很多种场景使用此方式的做法:

// 权限控制组件,只需要封装一次connect,
// 通过render props向子组件传递权限
class AuthWidget extends Component {
    render() {
        return this.props.children(this.props.auth);
    }
}

const mapStateToProps = state => {
    const { auth } = state;
    return { auth: state.auth };
};
export default connect(mapStateToProps)(AuthWidget);

// 其他组件使用
    children={auth => auth.edit && 编辑}
/>

// 使用antd的form时
const Test = ({ form, children }) => {
    return children(form);
};
const FormTest = Form.create()(Test);

class Demo extends Component {
    render() {
        return (
            

                xxxxx
                    { form => {
                        this.form = form;
                        return (
                                    {getFieldDecorator('field', xxx)(
                                    )}
                        )
                    }}

        )
    }
}

子组件改变父组件的state

子组件改变父组件的state方式有很多种,可以在父组件设置一个通用函数,类似:setParentState,通过子组件回调处理时,就可以更方便的统一处理:

// 父组件
state = {
    data: {}
}
setParentState = obj => {
    this.setState(obj);
}
// 子组件
onClick = () => {
    this.props.setParentState({ data: xxx });
}

永远不要直接设置state的值

永远不要直接设置state的值:this.state.data = { a: 1 }。这个会导致几个问题: 1:组件不会重新渲染
2:shouldComponentUpdate(nextProps, nextState) 函数里面 this.state的值是已经改变了,和nextState的值相同。

举个栗子:

// wrong
const { data } = this.state;
data.a = 1;     // 等价于this.state.data.a = 1;
this.setState({ data });
// shouldComponentUpdate里面观察到 this.state 和nextState的值是相同的
// 此时函数里面性能相关的优化是无效的

// correct  需要用到当前state值的写法
this.setState(state => ({ data: {...state.data, a: 1} }))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/559240.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分级调节是调节机制吗_机制砂大热,5种制砂工艺及特点介绍,选对生产工艺,保证高效生产...

随着我国大部分地区河砂、湖砂禁采、限采&#xff0c;机制砂迎来发展好时机&#xff0c;各地新建生产线如火如荼。人工机制砂工艺大致经历了由锤式破碎机制砂、棒磨机制砂、立轴冲击式破碎机( 以下简称“立轴破”) 制砂等的单破碎段制砂工艺&#xff0c;到立轴破碎机与棒磨机联…

cadence自动生成铺铜_干货 | 国内铜湿法冶金工艺现状分析

更多、更及时的交易信息&#xff0c;干货内容&#xff0c;请关注易矿网来源 | 网络编辑 | 易矿资讯&#xff0c;转载请注明出处1.国内外铜湿法冶金技术发展现状自1968年以来&#xff0c;世界上已设计、建设并运转了约50家浸出—溶剂萃取—电积厂&#xff0c;其中美国有16家&…

dataframe合并两个表_Pandas 数据处理 | 怎么对多个数据表合并,你了解么?

点击上方 Z先生点记&#xff0c;加为星标第一时间收到 Python 技术干货&#xff01;merge() 函数用于合并两个 DataFrame 对象或 Series&#xff0c;数据处理时经常会用到这个函数&#xff0c;官网给出该函数的定义如下&#xff1a;pandas.merge(left, right, how: str inner,…

中fuse_保险丝座中保险丝的材质,结构,接线方式以及区别的介绍

保险丝材料主要是由铝锑合金等低熔点合金制成的。保险丝必需是易熔化的金属丝&#xff0c;才能在电流大时及时熔断&#xff0c;起到保护作用&#xff0c;所以通常用铅锑合金丝。保险丝的结构&#xff1a;一般保险丝由三个部分组成&#xff1a;一是熔体部分&#xff0c;它是保险…

找对象年龄差多大最好_女生找对象到底最看重什么?调查了全球6万多名女性的结果是......

文/英国那些事儿微信号&#xff1a;hereinuk“怎么想找个女朋友这么难啊&#xff01;&#xff1f;”这种吐槽估计不少单身男生应该都有过&#xff0c;“女生到底对找男朋友都有啥要求啊&#xff1f;&#xff01;”这个问题应该也是很多男生心中久久得不到解答的问题。不过就在最…

个人生活助手app_美居App 6版重磅升级 开启智慧生活新范式

2019年12月30日,美的IoT在美的全球创新中心HolaCon场景实验室举办了主题为“全屋智慧2020智慧生活新范式”美居焕新分享会,现场发布了美居App 6版一系列重磅升级的新功能。图:美居焕新会现场美居是美的智能家居的用户入口。截至目前,已经有超过4000万的用户通过美居使用美的智能…

程序员述职报告范文_物流人员述职报告范文(通用5篇)

物流人员述职报告范文(通用5篇)时间是看不见也摸不到的&#xff0c;就在你不注意的时候&#xff0c;它已经悄悄的和你擦肩而过&#xff0c;回顾过去的工作&#xff0c;倍感充实&#xff0c;收获良多&#xff0c;需要认真地为此写一份述职报告。你还在为写述职报告而苦恼吗&…

java环境变量javac不能成功 win7_配置Java环境

jdk下载 jdk.rar运行JDK文件点击下一步点击“更改目录”&#xff0c;将安装目录设置在自己喜欢的地方&#xff08;建议&#xff09;&#xff0c;或者直接点击下一步&#xff08;此时默认装到C盘&#xff09; 此处演示安装到G:codepathjava安装完后直接点解关闭&#xff08;注&a…

制图折断线_CAD制图初学入门之CAD标注时必须要区分的两个概念

由于很多CAD制图初学入门者对于CAD软件中的部分功能了解的不是很清楚&#xff0c;所以在使用CAD标注功能的时候可能会遇到各种问题&#xff0c;比如CAD折弯标注和CAD线性折弯标注。下面就给大家分享一些与CAD标注有关的CAD制图初学入门技巧吧&#xff01;在使用浩辰CAD软件进行…

仪表板断面_【干货】内外饰断面设计规范

您的关注和分享就是对小编最大的支持来源 ▎ 车圈没有圈前言本标准明确了内外饰、仪表板的设计要素标准&#xff0c;使内外饰、仪表板的断面设计更加规范化&#xff0c;并作为内外饰、仪表板断面设计质量的评价依据。本标准包含车身、电器、底盘、总布置、造型等部分相关的内容…

定时器_Qt定时器小坑

今天在做音视频合成功能&#xff0c;由于Qt的定时器精度问题&#xff0c;导致视频合成有问题。视频合成是采用FFmpeg实现的&#xff0c;将h264视频和aac视频合成到mp4容器中。音频写入到mp4容器验证过是正常的&#xff0c;但视频写入到mp4容器中&#xff0c;播放出来总是过快。…

全系统各类型工程水土保持方案编制实践技术

内容涵盖八大专题&#xff1a;点型项目、市政工程、线型工程、矿山工程、水利工程、取土场/弃渣场、补报项目、水土保持监测验收 课程一&#xff1a;点型水土保持方案编制方法及案例分析实践 课程二&#xff1a;市政工程水土保持方案编制方法及案例分析实践课程三&#xff1a;…

测量怎么显示坐标_全站仪坐标放样究竟如何操作?

全站仪是一种高技术测量仪器&#xff0c;集合了电&#xff0c;机&#xff0c;光为一体&#xff0c;它的出现让测量更为精准化&#xff0c;操作也更为简单便捷&#xff0c;也正是因为这些优势&#xff0c;让全站仪在工程测量中得到了非常广泛的应用。而全站仪坐标放样就是根据已…

c语言如何输入矩阵_如何在 COMSOL 软件中调试外部材料

问题描述我实现了一种用于“结构力学”的外部材料&#xff0c;但我的模型无法求解。解决方法外部材料一般通过 C 语言编码&#xff0c;然后被编译到共享库中&#xff0c;供 COMSOL Multiphysics 在运行时使用。如果您在编译外部材料代码时遇到问题&#xff0c;请参阅 COMSOL Mu…

idal 创建springboot 项目_SpringBoot教程:Maven方式创建SpringBoot项目

一.Maven方式创建Spring Boot项目1.配置Maven环境在以maven方式创建Spring Boot项目之前&#xff0c;请先确保自己的Maven并配置好环境变量&#xff0c;并且在ideal中关联好maven环境。2.创建一个新的maven项目3.设置项目坐标信息&#xfffc;到此为止&#xff0c;就已经成功的…

mysql xa_Mysql对XA的支持

mysql8.0文档&#xff1a;https://dev.mysql.com/doc/refman/8.0/en/xa-statements.html。13.3.8.1 XA Transaction SQL Syntax章节讲述了Mysql对于XA事务的语法。XA {START|BEGIN} xid [JOIN|RESUME] XA END xid [SUSPEND [FOR MIGRATE]] XA PREPARE xid XA COMMIT xid [ONE P…

mysql 视图 过程 函数_MySQL视图,函数,触发器,存储过程

1. 视图视图是一个虚拟表&#xff0c;它的本质是根据SQL语句获取动态的数据集&#xff0c;并为其命名&#xff0c;用户使用时只需使用【名称】即可获取结果集&#xff0c;可以将该结果集当做表来使用。使用视图我们可以把查询过程中的临时表摘出来&#xff0c;用视图去实现&…

socket抓包_64、抓包分析tcp与udp

从前面的两个案例&#xff0c;我们了解到了如何通过原生socket函数分别创建tcp和udp服务&#xff0c;以及通过相应的客户端进行连接测试。在本文中&#xff0c;我们将继续深入地去了解tcp和udp的差别&#xff0c;和思考它们两者如何应该多个客户端请求1、抓包分析这里采用tcpdu…

fw313r手机登录_迅捷(FAST)fw313r路由器手机设置教程

本文中&#xff0c;鸿哥主要给大家介绍&#xff0c;迅捷(FAST)fw313r路由器用手机设置的方法。一台新买回来的迅捷(FAST)fw313r路由器&#xff0c;要用手机来设置它连接Internet上网&#xff0c;需要以下几个步骤&#xff1a;1、正确连接FW313R路由器2、手机连接FW313R的信号3、…

mysql 5.6.21不能选择安装路径_mysql5.6.21服务器安装图解(选择安装和数据目录)

mysql安装图解(服务器上安装mysql&#xff0c;只安装mysql服务)1.3 mysql安装及配置版本&#xff1a;MySQL5.6.21 64位1.3.1 安装.net framework.exe 4.0注意&#xff1a;mysql5.6版本需要安装.net framwork.exe 4.0环境1.3.2 安装mysql数据库(1)打开安装程序后&#xff0c;…