TSとスタイルのコンポーネントを使用して小道具をレンダリング


我々はグリッドを構築することができる反応コンポーネントを構築しました.レンダリングプロップメソッドのおかげで、それは各子供のために利用可能な幅を公開します.
このポストでは、まず、内部で使用するコンポーネントを作成することによって改善します.次に、Builderメソッドのおかげで、グリッド作成プロセスを自動化します.

you can find the code in repo


クリエイトsrc/components/GridElement
  • GridElement.types.ts
  • GridElement.styles.ts
  • GridElement.tsx
  • 何が欲しい


    の間にアダプタとして機能するコンポーネントが欲しいGridLayout そして、我々が実際にそれに入れたいもの.したがって、それはcontent . 第2の柱style , は、幅を含んでいて、オプションのままで高さと背景色の追加を残します(後者はtheme あなたが使っているならばThemeProvider 上流.

    Per semplicità, non applichiamo il ThemeProvider.


    GridElement.types.ts
    export interface GridElementProps {
        style: {
            width: number;
            height?: number;
            backgroundColor?: string;
        }
        content: any;
    }
    
    スタイルのコンポーネントに移動しましょう.受け取った小文字は、以前に決めたものを模倣します.コンテンツを中心にします.幅は外側から決定されるGridLayout ). 高さと背景色は、それらが提供された場合にのみ適用されます&& .
    GridElement.styles.ts
    import styled from 'styled-components'
    
    type WrapperProps = {
        width: number;
        height?: number;
        backgroundColor?: string;
    }
    
    export const GridElementWrapper = styled.div<WrapperProps>`
      display: flex;
      justify-content: center;
      align-items: center;
    
      width: ${({ width }) => `${width}px`};
      ${({ height }) => height && `height: ${height}px`};
      ${({ backgroundColor }) => backgroundColor && `background-color: ${backgroundColor}`};
    
    最後に、我々はここにいるGridElement.tsx . それは非常に簡単です:それは単一のスタイルの小道具を受け取るのでstyle パッケージは、スプレッド演算子のおかげで、単にそれを広げることができます.The content を挿入します.
    GridElement.tsx
    import { GridElementProps } from './GridElement.types'
    import { GridElementWrapper } from './GridElement.styles'
    
    const GridElement = ({ style, content }: GridElementProps): JSX.Element => {
        return (
            <GridElementWrapper
                {...style}
            >
                {content}
            </GridElementWrapper>
        )
    }
    
    export default GridElement
    
    それで、それを使用しましょうGridLayout コンポーネント.
    App.tsx
    import React from 'react'
    import GridElement from './components/GridElement/GridElement';
    import GridLayout from './components/GridLayout/GridLayout'
    
    const colors = ['green', 'white', 'red']
    
    const App = () => (
      <div>
        <h1>React Render Props Grid Layout</h1>
        <GridLayout
          columnsAmount={3}
        >
          {(itemWidth) => React.Children.map(colors, (color, index) => (
            <GridElement
              style={{
                width: itemWidth,
                height: 100,
                backgroundColor: color
              }}
              content={index}
            />
          ))}
        </GridLayout>
      </div>
    )
    
    export default App;
    
    結果は以下の通りです:

    はい、ok、クール.しかし、コードのそのヒープを見てすぐに我々はより良い行うことができます心に浮かぶ.
    すべての要素が同じ測定値を持つことを望むとします.我々は、この情報をGridLayout 自身.私たちはまたGridElement それの中で直接、そのようにApp.tsx コードGridLayout を用いる).

    計画

    GridLayout つの新しい小道具を受け入れることができます
  • アイテム:構成オブジェクトのリスト、それぞれグリッドに配置する要素とその相対的なスタイルを表します.
  • ビルダー:項目に渡された各要素のレンダリングを記述するメソッド強さは、各要素を包んでいるという事実にあるGridElement , したがって、自動的にそのスタイルを管理します.
  • The smartest kids will have guessed that many things can be managed in this way, not just style.


    GridLayout.types.ts
    export interface GridLayoutProps {
        columnsAmount: number;
        children?: (width: number) => JSX.Element | JSX.Element[]
        rowHeight?: number;
        items?: configItems[];
        builder?: (item: JSX.Element) => JSX.Element;
    }
    
    export interface configItems {
        style: {
            width?: number,
            height?: number,
            backgroundColor?: string
        };
        component: JSX.Element
    }
    
    Builderメソッドを使用すると、子プロセスのレンダリングプロップが使用されないことを意味します.つまたは他の管理は、コンポーネント自体で管理されます.
    構成オブジェクトの一覧についてcomponent プロパティは、コンポーネントそのものです.style , 一方、特定のスタイルに特定のスタイリングを適用することができます.しかし省略した場合、要素のスタイルはデフォルトのものになりますwidth = elementWidth , backgroundColor おそらく適応後、テーマによって提供されるGridElementWrapper . しかし、注意を無駄にしないでください.
    前のポストのように、次のコンポーネントのサイズは、読み取りをオフにすることができます.では、概念を打破しましょう.
  • 子供とビルダーの同時使用に対して警戒してください.
  • ビルダーが使用されたとき、アイテムを供給することを強制されます.
  • 子どもの条件的使用又はその内容の範囲内でのビルダー法の使用GridElement .
  • 残りはまだ変わらない.後でコードのブロックを参照してください.
    GridLayout.tsx
    import React, { useState, useEffect, createRef, ReactElement } from 'react'
    import { GridLayoutProps } from './GridLayout.types'
    import { Grid } from './GridLayout.styles'
    import GridElement from '../GridElement/GridElement'
    
    const GridLayout = ({ children, columnsAmount, rowHeight, builder, items }: GridLayoutProps): ReactElement => {
        if (typeof children === 'undefined' && typeof builder === 'undefined') {
            throw new Error('Either children or builder is required')
        }
        if (typeof builder !== 'undefined' && (typeof items === 'undefined' || items.length < 0)) {
            throw new Error('When using builder your should provide also items')
        }
    
        const gridRef = createRef<HTMLDivElement>()
        const [elementWidth, setElementWidth] = useState<number>(0);
    
        useEffect(() => {
            const { current } = gridRef
            let gridWidth = current!.getBoundingClientRect().width
            setElementWidth(Math.round(gridWidth / columnsAmount));
        }, [columnsAmount, rowHeight, gridRef])
    
        return (
            <Grid
                columnsAmount={columnsAmount}
                rowHeight={rowHeight}
                ref={gridRef}
            >
                {Boolean(children) && children!(elementWidth)}
                {Boolean(builder) && items!.map(({ component, style }, index) => {
                    const { width, height, backgroundColor } = style
                    console.log(height)
                    return (
                        <GridElement
                            key={index}
                            style={{
                                width: width || elementWidth,
                                height,
                                backgroundColor,
                            }}
                            content={builder!(component)}
                        />
                    )
                })}
            </Grid>
        )
    }
    
    export default GridLayout
    
    (一)児童及びビルダーの同時使用に対する警戒
    if (typeof children === 'undefined' && typeof builder === 'undefined') {
            throw new Error('Either children or builder is required')
        }
    
    明らかに、2つの方法が共存するなら、我々は1つまたは他の優先順位を与えることができました.でも.
    2 .使用者が使用したときに商品を供給することを強制された
    if (typeof builder !== 'undefined' && (typeof items === 'undefined' || items.length < 0)) {
            throw new Error('When using builder your should provide also items')
        }
    
    他のものが存在しないものが存在しないから.私がそこから来るところは、彼らがカロ&カミーシアだと言われています.
    3 . Content * * Children *の使用またはContainerメソッドの使用方法GridElement *
    {Boolean(children) && children!(elementWidth)}
    
    方法の存在のチェックから離れて、それは新しい何もしません.もう一つは、
    {Boolean(builder) && items!.map(({ component, style }, index) => {
                    const { width, height, backgroundColor } = style
                    console.log(height)
                    return (
                        <GridElement
                            key={index}
                            style={{
                                width: width || elementWidth,
                                height,
                                backgroundColor,
                            }}
                            content={builder!(component)}
                        />
                    )
                })}
    
    これが重要なポイントです.子供が存在するか、ビルダーが存在することを心に留めておいて、2つのケースのうちの1つだけが実行されるでしょう.
    この場合、構成オブジェクトはGridElements . 各オブジェクトの最終的なスタイルはGridElement どのような場合でも、最初の不在で何をすべきかを知っています.
    Builderメソッドは、GridElement を渡し、component 自身.

    If you are wondering why we are manually mapping items then explicitly passing the key rather than using React.Children.map(), the reason is that the latter must act on a component list. But here we have a list of items.


    今、私たちのグリッドレイアウトを見て醜い正方形のシリーズを強調しましょう.それが壊れるかどうか見ましょう!
    色のリストがあります.コンポーネントをインデックスの内部で単純にする構成オブジェクトのリストにマップしましょう.カスタムコンポーネントです.スタイルはここでどのように動作するかを見るために、ジャンクの山です.
  • 幅:100はインデックスによって乗算されます、しかし、偶数だけのために;さもなければデフォルトに戻る
  • 高さ:ベース30に加えられたインデックスは20を掛けました.
  • backgroundcolor :マップされている要素.
  • App.tsx
    import React from 'react'
    import GridLayout from './components/GridLayout/GridLayout'
    import { configItems } from './components/GridLayout/GridLayout.types'
    
    const colors = ['green', 'yellow', 'red', 'blue', 'orange']
    
    const elements: configItems[] = colors.map((color, index) => ({
      component: <div>{index}</div>,
      style: {
        width: index % 2 == 0 ? 100 * index : undefined,
        height: 20 * Math.pow(index, 2) + 30,
        backgroundColor: color
      }
    }))
    
    const App = () => (
      <div>
        <h1>React Render Props Grid Layout - The Return</h1>
        <GridLayout
          columnsAmount={3}
          items={elements}
          builder={(item) => (
            <div>{item}</div>
          )}
        />
      </div>
    )
    
    export default App;
    
    このオブジェクトのリストをGridLayoutに渡しましょう.それで、ビルダーでは、私たちは各々の背中のコンポーネントを得るだけです-スタイルは内部的に扱われました.

    Ugly, innit? But only because I wanted to make explicit the versatility of what we have built. I'm sure you understand the possibilities.


    ポストクレジット


    私はさらに住みません、しかし、私は始めを去ります:我々がgridlayoutに別の支柱(必須でない)を通過するならば、どうですか?どのような場合、各要素の実装に適用されるアニメーションの種類を定義するか?私はフレーマーの動きは、スタイルのコンポーネントと完全に行くと信じています.
    我々が必要に応じてそれらを調整することができるように、我々は集中的な店からこれらの小道具を管理するならば、どうですか?
    今、私たちは正しい質問をしています.

    便利なリンク

  • how to make a good grid
  • Making peace between ref and typescript
  • Styled-components with typescript
  • useState and typescript
  • Render Props
  • Render Props - the Return
  • repo
  • 接続する


    ギタブdidof
    リンケディン
    Twitter