zoukankan      html  css  js  c++  java
  • 平时写react 小技巧

    • Stateless function 无状态组件平时写组件用到比较多的就是无状态组件,不但优雅,也是优化react性能的一种手段。
        const Greeting = ({ name, style }) => {
          return <div style={style}>{name}</div>
        };
    • Array as children 把数组数据渲染出来

      经常会遇到处理数组数据的情况,可以用下面的方式简单的渲染出来。

        render() {
            return (
                (<ul>
                    {List.map((item) => (
                         <li>{item}</li>
                    ))}
                </ul>)
            )     
        }
    • 封装基础类组件

      比如 <input type="text" > 每次写很麻烦吧,可以封装一个成一个组件

        const input = (props) => {
            return <input type = {props.type} {...props} />
        }
    • Layout Component 布局组件

      组件可以分成很多类类,有的是布局类,有的是功能类。下面是一种布局类的组件。

        <FlexContainer>
          <div style={{ flex: 1 }}>{this.props.leftSide}</div>
          <div style={{ flex: 2 }}>{this.props.rightSide}</div>
        </FlexContainer>
    • Higher Order Component 高阶组件

      高阶组件很像decorator,提升组件的能力。比如你想一些组件里面使用一下功能,react-router 中

        import { withRouter } from 'react-router'
        withRouter(SomeComponent)

      例子:

        var Enhance = ComposedComponent => class extends React.Component {
          componentDidMount() {
            this.setState({ name: "李狗子" });
          }
          render() {
            return <ComposedComponent {...this.props} name = {this.state.name} />;
          }
        };
    • 受控组件,不受控组件

      项目中经常会用到这两种情况如:
      受控组件,更新的时候需要使用this.setState

        constructor() {
            super();
            this.state = {value: ""}
        }
        render() {
            return <input type="text" value={this.state.value} />
        }

      不受控组件,主要需要通过ref来获取input的值。

        render() {
            return <input type="text" ref="myInput" />
        }

      两种方法都可以在特定的场合去使用,个人觉得数据相对重要的页面需要使用受控组件会比较合适。

    • 使用三元表达式

      项目中经常有判断语句,用三元表达式可以很方便的写出想要的逻辑

        const demo = ({ isOK }) => {
            return isOK 
            ? <p> Yes </p> 
            : <p> No </p>
        };
    • 给setState传入function

      可以使用function来更新state

        this.setState((prevState, props) => ({
            return ...
        }));
    • 通过ref属性获取component

      场景:下面的例子是初始化组件后,让input默认获取光标。ref最终指向的已经渲染好的DOM节点,或者是react class的实例。具体可以看官方的文档

        componentDidMount() {
            this.input.focus();
        }
        render() {
            return (
                <input
                  ref={comp => { this.input = comp; }}
                />
            )
        }
    • 切勿使用...props传递数据

      一个非常错误的做法比如:

        <Component {...props} />

      props上面如果有非常多的属性,会造成非常昂贵的计算。正确的应该

        <Component name = { props.name } />

    以上是平时写React用到的一些写法小技巧,说有用还蛮有用的!

    有错误的地方还请指正!谢谢大家。

    下面2个链接都很棒哦!记得收藏star...

    参考:

    https://github.com/vasanthk/react-bits

    react 代码规范

    https://github.com/airbnb/javascript/tree/master/react

    dangerouslySetHTML 和 style 属性

    dangerouslySetHTML

    出于安全考虑的原因(XSS 攻击),在 React.js 当中所有的表达式插入的内容都会被自动转义,就相当于 jQuery 里面的 text(…) 函数一样,任何的 HTML 格式都会被转义掉:

    class Editor extends Component {
      constructor() {
        super()
        this.state = {
          content: '<h1>React.js 小书</h1>'
        }
      }
    
      render () {
        return (
          <div className='editor-wrapper'>
            {this.state.content}
          </div>
        )
      }
    }
    

    假设上面是一个富文本编辑器组件,富文本编辑器的内容是动态的 HTML 内容,用 this.state.content 来保存。我希望在编辑器内部显示这个动态 HTML 结构,但是因为 React.js 的转义特性,页面上会显示:

    表达式插入并不会把一个 <h1> 渲染到页面,而是把它的文本形式渲染了。那要怎么才能做到设置动态 HTML 结构的效果呢?React.js 提供了一个属性 dangerouslySetInnerHTML,可以让我们设置动态设置元素的 innerHTML:

    ...
      render () {
        return (
          <div
            className='editor-wrapper'
            dangerouslySetInnerHTML={{__html: this.state.content}} />
        )
      }
    ...
    

    需要给 dangerouslySetInnerHTML 传入一个对象,这个对象的 __html 属性值就相当于元素的 innerHTML,这样我们就可以动态渲染元素的 innerHTML 结构了。

    有写朋友会觉得很奇怪,为什么要把一件这么简单的事情搞得这么复杂,名字又长,还要传入一个奇怪的对象。那是因为设置 innerHTML 可能会导致跨站脚本攻击(XSS),所以 React.js 团队认为把事情搞复杂可以防止(警示)大家滥用这个属性。这个属性不必要的情况就不要使用。

    style

    React.js 中的元素的 style 属性的用法和 DOM 里面的 style 不大一样,普通的 HTML 中的:

    <h1 style='font-size: 12px; color: red;'>React.js 小书</h1>
    

    在 React.js 中你需要把 CSS 属性变成一个对象再传给元素:

    <h1 style={{fontSize: '12px', color: 'red'}}>React.js 小书</h1>
    

    style 接受一个对象,这个对象里面是这个元素的 CSS 属性键值对,原来 CSS 属性中带 - 的元素都必须要去掉 - 换成驼峰命名,如 font-size 换成 fontSizetext-align 换成 textAlign

    用对象作为 style 方便我们动态设置元素的样式。我们可以用 props 或者 state中的数据生成样式对象再传给元素,然后用 setState 就可以修改样式,非常灵活:

    <h1 style={{fontSize: '12px', color: this.state.color}}>React.js 小书</h1>
    

    只要简单地 setState({color: 'blue'}) 就可以修改元素的颜色成蓝色。

    Prop 验证

    随着应用不断变大,保证组件被正确使用变得非常有用。为此我们引入propTypesReact.PropTypes 提供很多验证器 (validator) 来验证传入数据的有效性。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。注意为了性能考虑,只在开发环境验证 propTypes。下面用例子来说明不同验证器的区别:

    React.createClass({
      propTypes: {
        // 可以声明 prop 为指定的 JS 基本类型。默认
        // 情况下,这些 prop 都是可传可不传的。
        optionalArray: React.PropTypes.array,
        optionalBool: React.PropTypes.bool,
        optionalFunc: React.PropTypes.func,
        optionalNumber: React.PropTypes.number,
        optionalObject: React.PropTypes.object,
        optionalString: React.PropTypes.string,
    
        // 所有可以被渲染的对象:数字,
        // 字符串,DOM 元素或包含这些类型的数组。
        optionalNode: React.PropTypes.node,
    
        // React 元素
        optionalElement: React.PropTypes.element,
    
        // 用 JS 的 instanceof 操作符声明 prop 为类的实例。
        optionalMessage: React.PropTypes.instanceOf(Message),
    
        // 用 enum 来限制 prop 只接受指定的值。
        optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
    
        // 指定的多个对象类型中的一个
        optionalUnion: React.PropTypes.oneOfType([
          React.PropTypes.string,
          React.PropTypes.number,
          React.PropTypes.instanceOf(Message)
        ]),
    
        // 指定类型组成的数组
        optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
    
        // 指定类型的属性构成的对象
        optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
    
        // 特定形状参数的对象
        optionalObjectWithShape: React.PropTypes.shape({
          color: React.PropTypes.string,
          fontSize: React.PropTypes.number
        }),
    
        // 以后任意类型加上 `isRequired` 来使 prop 不可空。
        requiredFunc: React.PropTypes.func.isRequired,
    
        // 不可空的任意类型
        requiredAny: React.PropTypes.any.isRequired,
    
        // 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接
        // 使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
        customProp: function(props, propName, componentName) {
          if (!/matchme/.test(props[propName])) {
            return new Error('Validation failed!');
          }
        }
      },
      /* ... */
    });
    
      static get propTypes () {
        return {
          todoLeft: PropTypes.number.isRequired,
          actions: PropTypes.object.isRequired,
          filter: PropTypes.string.isRequired
        }
      }
      ...
        <strong>{this.props.todoLeft}</strong>
      ...

    默认 Prop 值

    React 支持以声明式的方式来定义 props 的默认值。

    var ComponentWithDefaultProps = React.createClass({
      getDefaultProps: function() {
        return {
          value: 'default value'
        };
      }
      /* ... */
    });
    

    当父级没有传入 props 时,getDefaultProps() 可以保证 this.props.value 有默认值,注意 getDefaultProps 的结果会被 缓存。得益于此,你可以直接使用 props,而不必写手动编写一些重复或无意义的代码。

    传递 Props:小技巧

    有一些常用的 React 组件只是对 HTML 做简单扩展。通常,你想少写点代码来把传入组件的 props 复制到对应的 HTML 元素上。这时 JSX 的 spread 语法会帮到你:

    var CheckLink = React.createClass({
      render: function() {
        // 这样会把 CheckList 所有的 props 复制到 <a>
        return <a {...this.props}>{'√ '}{this.props.children}</a>;
      }
    });
    
    React.render(
      <CheckLink href="/checked.html">
        Click here!
      </CheckLink>,
      document.getElementById('example')
    );
    

    单个子级

    React.PropTypes.element 可以限定只能有一个子级传入。

    var MyComponent = React.createClass({
      propTypes: {
        children: React.PropTypes.element.isRequired
      },
    
      render: function() {
        return (
          <div>
            {this.props.children} // 有且仅有一个元素,否则会抛异常。
          </div>
        );
      }
    
    });
    

    Mixins

    组件是 React 里复用代码最佳方式,但是有时一些复杂的组件间也需要共用一些功能。有时会被称为 跨切面关注点。React 使用 mixins 来解决这类问题。

    一个通用的场景是:一个组件需要定期更新。用 setInterval() 做很容易,但当不需要它的时候取消定时器来节省内存是非常重要的。React 提供 生命周期方法 来告知组件创建或销毁的时间。下面来做一个简单的 mixin,使用 setInterval() 并保证在组件销毁时清理定时器。

    var SetIntervalMixin = {
      componentWillMount: function() {
        this.intervals = [];
      },
      setInterval: function() {
        this.intervals.push(setInterval.apply(null, arguments));
      },
      componentWillUnmount: function() {
        this.intervals.map(clearInterval);
      }
    };
    
    var TickTock = React.createClass({
      mixins: [SetIntervalMixin], // 引用 mixin
      getInitialState: function() {
        return {seconds: 0};
      },
      componentDidMount: function() {
        this.setInterval(this.tick, 1000); // 调用 mixin 的方法
      },
      tick: function() {
        this.setState({seconds: this.state.seconds + 1});
      },
      render: function() {
        return (
          <p>
            React has been running for {this.state.seconds} seconds.
          </p>
        );
      }
    });
    
    React.render(
      <TickTock />,
      document.getElementById('example')
    );

    关于 mixin 值得一提的优点是,如果一个组件使用了多个 mixin,并且有多个 mixin 定义了同样的生命周期方法(如:多个 mixin 都需要在组件销毁时做资源清理操作),所有这些生命周期方法都保证会被执行到。方法执行顺序是:首先按 mixin 引入顺序执行 mixin 里方法,最后执行组件内定义的方法。

    这篇文章主要是写关于学习react中的一些自己的思考:

    1.setState到底是同步的还是异步的?

    2.如何在子组件中改变父组件的state

    3.context的运用,避免“props传递地狱”

    4.组件类里有私有变量a,它到底改放在this.a中还是this.state对象中(作为属性a)呢?

    1.setState到底是同步的还是异步的?

    class MyComponent extends React.Component{
       constructor(props) {
         super(props)
         this.state ={
         value:0
            }
       }
    handleClick = () => {
          this.setState({value:1})
               console.log('在handleClick里输出' + this.state.value);
    }
    render(){
               console.log('在render()里输出' + this.state.value);
    return (<div>
              <button onClick ={this.handleClick}>按钮</button>
            </div>)
          }
    }
    export default MyComponent
    //省略渲染过程,下面也一样

    在这里我们点击按钮时,调用handleClick函数,首先调用this.setState()设置value,随即把this.state.value输出,结果是什么?

    你可能会想,这还不简单——“在handleClick里输出1”呗,然而你错了,它的结果为:

    事实上,setState()的调用是异步的,这意味着,虽然你调用了setState({value:0}),但this.state.value并不会马上变成0,而是直到render()函数调用时,setState()才真正被执行。结合图说明一下:

    你可能又会问了:要是我在render()前多次调用this.setState()改变同一个值呢?(比如value)

    我们对handleClick做一些修改,让它变得复杂一点,在调用handleClick的时候,依次调用handleStateChange1 ,handleStateChange2,handleStateChange3,它们会调用setState分别设置value为1,2,3并且随即打印

    handleStateChange1 = () => {
           this.setState({value:1})
           console.log('在handleClick里输出' + this.state.value);
    }
    handleStateChange2 = () => {
           this.setState({value:2})
           console.log('在handleClick里输出' + this.state.value);
    }
    handleStateChange3 = () => {
           this.setState({value:3})
           console.log('在handleClick里输出' + this.state.value);
    }
    handleClick = () => {
          this.handleStateChange1();
          this.handleStateChange2();
          this.handleStateChange3();
    }

    那么输出结果会是什么呢?如果setState是同步调用的,那么结果显然为

    在handleClick里输出1

    在handleClick里输出2

    在handleClick里输出3

    但是结果为:,证明它是异步的

    这下好理解了吧,配合这幅图:

    2.如何在子组件中改变父组件的state呢?

    这是我们经常会遇到的问题之一,解决办法是:在父组件中写一个能改变父组件state的方法,并通过props传入子组件中

    class Son extends React.Component{
      render(){
           return(<div onClick = {this.props.handleClick}>
                    {this.props.value}
                  </div>)
              }
    }
    class Father extends React.Component{
        constructor(props){
              super(props)
              this.state ={
                    value:'a'
                   }
           }
        handleClick = () => {
             this.setState({value:'b'})
          }
        render(){
             return (<div style ={{margin:50}}>
                         <Son value = {this.state.value} handleClick = {this.handleClick}/>
                     </div>)
             }
    }

    点击子组件Son,内容由a变成b,说明父组件的state被修改了

    3.context的运用,避免“props传递地狱”

    3.1假设一个比较极端的场景:你需要从你的子组件里调用父父父父父组件的属性或方法,怎么办!当组件嵌套层级过深的时候,不断地传props作为实现方式简直就是噩梦!我称之为“props传递地狱”(这个词是我瞎编的,参考自“回调函数地狱”)

    我们接下来实现的是这样一个需求,把gene属性(基因)从组件GrandFather -->Father --> Son传递,如果用props传递:

    class Son extends React.Component{
      render(){
          return (<h3 style ={{marginTop:30}}>我从我的爷爷那里得到了基因--{this.props.gene}</h3>)
         }
     }
    class Father extends React.Component{
      render(){
          return (<Son gene = {this.props.gene}/>)
        }
    }
    class GrandFather extends React.Component{
      constructor(props) {
         super(props)
         this.state ={
           gene:'[爷爷的基因]'
           }
       }
      render(){
         return (<Father gene = {this.state.gene}/>)
        }
    }

    demo:

     

    【(。・`ω´・)虽然听起来有点怪怪的但是大家别介意哈】

    实现是实现了,但你想想,假设不是从“爷爷”组件,而是从“太太太太爷爷”组件传下来,这多可怕!不过没关系,react提供了一个叫做context(上下文)的API,你在顶层组件的context中定义的属性,可以在所有的后代组件中,通过this.context.属性去引用!让我们一睹为快:

    class Son extends React.Component{
       render(){
          console.log(this.context.color);
          return (<h3 style ={{marginTop:30}}>我从我的爷爷那里得到了基因--{this.context.gene}</h3>)
          }
    }
    Son.contextTypes ={
          gene:React.PropTypes.string
    }
    class Father extends React.Component{
       render(){
          return (<Son/>)
          }
    }
    class GrandFather extends React.Component{
       getChildContext(){
          return {gene:'[爷爷的基因]'}
       }
       render(){
          return (<Father />)
       }
    }
    GrandFather.childContextTypes = {
          gene: React.PropTypes.string
    };
    export default GrandFather

    demo效果同上!这个时候你发现,我们在<GrandFather>组件和<Father>组件中都没有向下传递props,我们就从最下层的Son组件中获取了gene属性,是不是很方便!

    解释下代码:

    getChildContext()是你在顶层组件中定义的钩子函数,这个函数返回一个对象——你希望在后代组件中取用的属性就放在这个对象中,譬如这个例子中我希望在Son组件中通过this.context.gene取属性,所以在getChildContext()中返回{gene:'[爷爷的基因]'}

    GrandFather.childContextTypes和Son.contextTypes 用于规定顶层组件和取顶层组件context的后代组件的属性类型

    【注意】GrandFather.childContextTypes和Son.contextTypes 这两个对象必须要规定!否则context只能取到空对象!一开始我犯的这个错误简直让我狂吐三升血。。。。

    有图有真相之context和props的区别

    3.2context是否推荐使用?

    虽然上面这个例子说明了context多么好用,但注意:官方并不推荐经常使用它,因为它会让你的应用架构变得不稳定(官方文档原话If you want your application to be stable, don't use context),在我看来,为什么在大多数情况下要使用props而不是实现数据流呢,因为props凭借组件和组件间严密的逻辑联系,使得你能够清晰地跟踪应用的数据流(it's easy to track the flow of data through your React components with props)当然了,如果你遇到上述的例子的情况,context还是大有裨益的 

    3.3需要改变context中的属性时候,不要直接改变它,而是使用this.state作为媒介,如果你试图在顶层组件的state中放入一个可变的属性你可以这样做:

    getChildContext(){
         return {type:this.state.type}
    }

    3.4在上述我限制gene的类型时候我是这样写的:gene: React.PropTypes.string,使用了React内置的React.PropTypes帮助属性,此时我的版本为 "react": "15.4.2",在15.5的版本后这一帮助属性被废弃,推荐使用props-types库,像这样:

    const PropTypes = require("Prop-Types");
    GrandFather.childContextTypes = {
         gene: PropTypes.string
    };

    当然,在这之前你需要npm install prop-types

    4组件类里有私有变量a,它到底改放在this.a中还是this.state对象中(作为属性a)呢?

    这得根据它是否需要实时的重渲染决定,如果该变量需要同步到变化的UI中,你应该把它放在this.state对象中,如果不需要的话,则把它放在this中(无代码无demo)

  • 相关阅读:
    C# 16 进制字符串转 int
    C# 16 进制字符串转 int
    dotnet 设计规范 · 抽象定义
    dotnet 设计规范 · 抽象定义
    C# 从零开始写 SharpDx 应用 控制台创建 Sharpdx 窗口
    C# 从零开始写 SharpDx 应用 控制台创建 Sharpdx 窗口
    C# 判断两条直线距离
    C# 判断两条直线距离
    PHP file() 函数
    PHP fgetss() 函数
  • 原文地址:https://www.cnblogs.com/minghui007/p/8177775.html
Copyright © 2011-2022 走看看