zoukankan      html  css  js  c++  java
  • React组件复用方式

    Component

    React核心思想,一切皆是组件,通过组件可以达到最理想的代码复用

    栗子

    import React from 'react';
    export default class ContainerComponent extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                count: 0
            }
            this.handlePlus = this.handlePlus.bind(this);
        }
    
        handlePlus() {
            this.setState({
                count: this.state.count + 1
            })
        }
    
        render() {
            return <div>
                <h1>{`I am a container component.`}</h1>
                <p>{`当前计数:${this.state.count}`}</p>
                <button onClick={this.handlePlus}>plus</button>
            </div>
        }
    }

    很简单的一个组件,如果其他需要用,直接引用即可

    import ContainerComponent from './ContainerComponent';

    但是为了满足最佳实践,我们将该组件分成容器组件跟展示组件

    容器组件:

    import React from 'react';
    import ShowComponent from './ShowComponent';
    export default class ContainerComponent extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                count: 0
            }
            this.handlePlus = this.handlePlus.bind(this);
        }
    
        handlePlus() {
            this.setState({
                count: this.state.count + 1
            })
        }
    
        render() {
            return <div>
                <h1>{`I am a container component.`}</h1>
                <ShowComponent
                    count={this.state.count}
                    handlePlus={this.handlePlus}
                />
            </div>
        }
    }

    展示组件

    export default ShowComponent;
    
    function ShowComponent(props) {
        return <div>
            <p>{`当前计数:${props.count}`}</p>
            <button onClick={props.handlePlus}>plus</button>
        </div>
    }

    这里啥是容器组件,啥是展示组件?

    容器组件:简单理解就是含有处理逻辑,处理数据的容器

    展示组件:只关心展示,跟数据无关,像控件,无状态组件更贴切。

    现在需求变了,如果展示组件不仅限于ShowComponent,现在多了ShowComponent2,showComponent3等等,怎么处理,噢?首先想到了什么?没错就是this.prop.children,

    我们尝试下。

    children

    栗子

    ContainerComponent

    import React from 'react';
    export default class ContainerComponent extends React.Component {
        constructor(props) {
            super(props)
        }
    
        render() {
            return <div>
                <h1>{`I am a container component.`}</h1>
                {this.props.children}
            </div>
        }
    }

    ShowComponent、ShowComponent2、ShowComponent3等等

    export default ShowComponent;
    
    function ShowComponent(props) {
        return <div>
            <p>{`当前计数:${props.count}`}</p>
            <button onClick={props.handlePlus}>plus</button>
        </div>
    }
    
    class ShowComponent extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                count: 0
            }
            this.handlePlus = this.handlePlus.bind(this);
        }
    
        handlePlus() {
            this.setState({
                count: this.state.count + 1
            })
        }
    
        render() {
            return <div>
                <p>{`当前计数:${this.state.count}`}</p>
                <button onClick={this.handlePlus}>plus</button>
            </div>
        }
    }

    可以实现我们的目的,但是缺点也比较明显,就是没办法将容器组件与展示组件分开,如果想分开,我们需要在ShowComponent中进行分,其实不难看出,this.props.children更像是一种layout的解决方案,仅用来定制layout,具体逻辑放到每个具体Component中进行。那么怎么处理这种情况更好呢~我们来看看一个解决方案—>回调渲染。

    回调渲染

    什么是回调渲染呢,简单来讲,就是采用调用的形式使用children API,就是this.props.children(),看个例子

    栗子

    import React from "react";
    import ReactDOM from "react-dom";
    import ContainerComponent from "./ContainerComponent";
    import ShowComponent from "./ShowComponent";
    
    {
      ReactDOM.render(
        <ContainerComponent>
          {({ count, handlePlus }) => (
            <ShowComponent count={count} handlePlus={handlePlus} />
          )}
        </ContainerComponent>,
        document.getElementById("app")
      );
    }

    ContainerComponent

    export default class ContainerComponent extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                count: 0
            }
            this.handlePlus = this.handlePlus.bind(this);
        }
    
        handlePlus() {
            this.setState({
                count: this.state.count + 1
            })
        }
    
        render() {
            return <div>
                <h1>{`I am a container component.`}</h1>
                {
                    this.props.children(
                        {
                            count: this.state.count,
                            handlePlus: this.handlePlus
                        }
                    )
                }
            </div>
        }
    }

    ShowComponent

    export default ShowComponent;
    
    function ShowComponent(props) {
        return <div>
            <p>{`当前计数:${props.count}`}</p>
            <button onClick={props.handlePlus}>plus</button>
        </div>
    }

    既可以达到ShowComponent与ContainerComponent解耦的目的(这里的意思是可以随意更改ShowComponet,可以换成其他组件),又可以实现了展示组件与容器组件分离。这只是个demo

    那么回调渲染到底解决了什么问题呢~回调渲染可以实现外层组件与内层组件的数据传递,可以很好的分离组件以及逻辑复用。

    谈到回调渲染,我们就会联想到另一个方案,Render Props,那么什么是Render Props呢

    Render Props

    RenderProps我认为是回调渲染的一种衍生方式,利用一个函数,进行组件传递,这个组件就是可变的部分,其余部分实现代码复用。我们试着用RenderProps方式对上个栗子进行改造,我们看个栗子。

    栗子

    import ContainerComponent from "./ContainerComponent";
    import ShowComponent from "./ShowComponent";
    
    {
      ReactDOM.render(
        <ContainerComponent
          render={({ count, handlePlus }) => (
            <ShowComponent count={count} handlePlus={handlePlus} />
          )}
        />,
        document.getElementById("app")
      );
    }

    ContainerComponent

    import React from 'react';
    import ShowComponent from './ShowComponent';
    export default class ContainerComponent extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                count: 0
            }
            this.handlePlus = this.handlePlus.bind(this);
        }
    
        handlePlus() {
            this.setState({
                count: this.state.count + 1
            })
        }
    
        render() {
            return <div>
                <h1>{`I am a container component.`}</h1>
                {
                    this.props.render({
                        count: this.state.count,
                        handlePlus: this.handlePlus
                    })
                }
            </div>
        }
    }

    ShowComponent

    export default ShowComponent;
    
    function ShowComponent(props) {
        return <div>
            <p>{`当前计数:${props.count}`}</p>
            <button onClick={props.handlePlus}>plus</button>
        </div>
    }

    其实跟回调渲染大同小异,回调渲染用的是React原生方法(this.props.children),RenderProps更灵活一些,可以定义多个函数,随意传递,比如

     ReactDOM.render(
        <ContainerComponent
          render={({ count, handlePlus }) => (
            <ShowComponent count={count} handlePlus={handlePlus} />
          )}
          renderMsg={() => <div>我是msg</div>}
          renderColor={() => <div>我是color</div>}
        />,
        document.getElementById("app")
      );

    好的总结一下,RenderProps解决了什么问题?

    同样达到了代码复用,组件拆解,降低耦合性,同时具备了回调渲染没有的灵活性。

    Hook

    在解决上面demo的例子,hook只是换了一种代码展示形式,解决方法是没变的,我们看改完的栗子

    import ContainerComponent from "./ContainerComponent";
    import ShowComponent from "./ShowComponent";
    
    {
      ReactDOM.render(
        <ContainerComponent
          render={({ count, handlePlus }) => (
            <ShowComponent count={count} handlePlus={handlePlus} />
          )}
        />,
        document.getElementById("app")
      );
    }

    ContainerComponent

    import React, { useState, useEffect } from "react";
    import ShowComponent from './ShowComponent';
    function ContainerComponent(props) {
        const [count, setCount] = useState(0);
        const handlePlus = () => {
            setCount(count + 1);
        }
        return <div>
            <h1>{`I am a container component.`}</h1>
            {
                props.render({
                    count: count,
                    handlePlus: handlePlus
                })
            }
        </div>
    }
    
    
    export default ContainerComponent;

    ShowComponent

    import React, { useState, useEffect } from "react";
    
    
    function ShowComponent(props) {
        return <div>
            <p>{`当前计数:${props.count}`}</p>
            <button onClick={props.handlePlus}>plus</button>
        </div>
    }
    
    export default ShowComponent;

    依然利用了RenderProps,只是将Class组件变成了Hook组件,这个其实体现不出来Hook的要解决的问题,

    Hook解决的问题跟HOC是比较类似的,侧重点是逻辑复用。看个栗子。

    公用部分

    function useFetch() {
      const [data, setData] = useState();
      useEffect(() => {
        new Promise((resolve) => {
          resolve({
            name: "dqhan",
            age: 28,
          });
        }).then((res) => {
          setData(res);
        });
      }, []);
    
      return data;
    }

    组件App

    function App() {
      let data = useFetch();
      return (
        <div>
          <div>App1</div>
        </div>
      );
    }

    组件App2

    function App2() {
      let data = useFetch();
      return (
        <div>
          <div>App2</div>
        </div>
      );
    }

    提取组件加载完成时获取数据的复用逻辑,这样能让代码复用看起来更直观。当然还有最后一种方式实现代码复用,就是HOC。这里就不谈了。

  • 相关阅读:
    微软Enterprise Library 4.0将支持依赖注入
    javascript cookies 存、取、删除实例
    动态调用 WebService(转)
    IE缓存是什么?cookies是什么?
    序列化
    PKI
    ASP.NET的(HttpModule,HttpHandler)(转)
    PKI基础 二.PKI基础5.数字证书及应用(转,一个加密解密的全过程)
    AOP技术基础(转)
    getChildByName()与getChildAt()效率比较
  • 原文地址:https://www.cnblogs.com/moran1992/p/13500505.html
Copyright © 2011-2022 走看看