From 779fe7823639624c13349292dd1e5afe23d6dc3b Mon Sep 17 00:00:00 2001 From: Alex Reardon Date: Thu, 14 Mar 2019 14:56:27 +1100 Subject: [PATCH] adding example for function components (#1167) --- .eslintrc.js | 15 +++- docs/about/examples.md | 3 +- docs/patterns/using-a-portal.md | 2 +- package.json | 1 + stories/35-function-component.stories.js | 9 ++ stories/src/function-component/quote-app.jsx | 90 ++++++++++++++++++++ test/unit/docs/content.spec.js | 21 ++--- yarn.lock | 5 ++ 8 files changed, 132 insertions(+), 14 deletions(-) create mode 100644 stories/35-function-component.stories.js create mode 100644 stories/src/function-component/quote-app.jsx diff --git a/.eslintrc.js b/.eslintrc.js index 57eb2b1271..092fc9541c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,7 +9,15 @@ module.exports = { 'plugin:prettier/recommended', ], parser: 'babel-eslint', - plugins: ['prettier', 'flowtype', 'emotion', 'react', 'import', 'jest'], + plugins: [ + 'prettier', + 'flowtype', + 'emotion', + 'react', + 'react-hooks', + 'import', + 'jest', + ], env: { es6: true, browser: true, @@ -92,5 +100,10 @@ module.exports = { // Allowing importing from dev deps (for stories and tests) 'import/no-extraneous-dependencies': 'off', + + // Enforce rules of hooks + 'react-hooks/rules-of-hooks': 'error', + // Second argument to hook functions + 'react-hooks/exhaustive-deps': 'warn', }, }; diff --git a/docs/about/examples.md b/docs/about/examples.md index 9cfe2c7d5f..97340f00cc 100644 --- a/docs/about/examples.md +++ b/docs/about/examples.md @@ -19,8 +19,7 @@ We have created some basic examples on `codesandbox` for you to play with direct - [Simple vertical list](https://codesandbox.io/s/k260nyxq9v) - [Simple horizontal list](https://codesandbox.io/s/mmrp44okvj) +- [Using with function components](https://codesandbox.io/s/zqwz5n5p9x) - [Simple DnD between two lists](https://codesandbox.io/s/ql08j35j3q) [← Back to documentation](/README.md#documentation-) - -[← Back to documentation](/README.md#documentation-) diff --git a/docs/patterns/using-a-portal.md b/docs/patterns/using-a-portal.md index 614f3cf5cf..fcaecbca04 100644 --- a/docs/patterns/using-a-portal.md +++ b/docs/patterns/using-a-portal.md @@ -30,4 +30,4 @@ We have created a [working example](https://react-beautiful-dnd.netlify.com/?sel If you are doing drag and drop reordering within a `` we have created a portal section inside our [table guide](/docs/patterns/tables.md) -[← Back to documentation](/README.md#documentation-). +[← Back to documentation](/README.md#documentation-) diff --git a/package.json b/package.json index 88a96f2ed9..165b4bbf7c 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "eslint-plugin-jsx-a11y": "^6.2.1", "eslint-plugin-prettier": "^3.0.1", "eslint-plugin-react": "^7.12.4", + "eslint-plugin-react-hooks": "^1.5.0", "flow-bin": "0.94.0", "fs-extra": "^7.0.1", "globby": "^9.1.0", diff --git a/stories/35-function-component.stories.js b/stories/35-function-component.stories.js new file mode 100644 index 0000000000..b3a65a6626 --- /dev/null +++ b/stories/35-function-component.stories.js @@ -0,0 +1,9 @@ +// @flow +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import QuoteApp from './src/function-component/quote-app'; + +storiesOf('Function component usage', module).add( + 'using rbd with function components and hooks', + () => , +); diff --git a/stories/src/function-component/quote-app.jsx b/stories/src/function-component/quote-app.jsx new file mode 100644 index 0000000000..3212e2dfec --- /dev/null +++ b/stories/src/function-component/quote-app.jsx @@ -0,0 +1,90 @@ +// @flow +import React, { useState } from 'react'; +import styled from '@emotion/styled'; +import { DragDropContext, Droppable, Draggable } from '../../../src'; +import type { + DropResult, + DraggableProvided, + DroppableProvided, +} from '../../../src'; +import type { Quote as QuoteType } from '../types'; +import { quotes as initial } from '../data'; +import reorder from '../reorder'; +import { grid } from '../constants'; + +type QuoteProps = {| + quote: QuoteType, + index: number, +|}; + +const QuoteItem = styled.div` + width: 200px; + border: 1px solid grey; + margin-bottom: ${grid}px; + background-color: lightblue; + padding: ${grid}px; +`; + +function Quote({ quote, index }: QuoteProps) { + return ( + + {(provided: DraggableProvided) => ( + + {quote.content} + + )} + + ); +} + +type QuoteListProps = {| + quotes: QuoteType[], +|}; + +// Ensuring the whole list does not re-render when the droppable re-renders +const QuoteList = React.memo(function QuoteList({ quotes }: QuoteListProps) { + return quotes.map((quote: QuoteType, index: number) => ( + + )); +}); + +function QuoteApp() { + const [quotes, setQuotes] = useState(initial); + + function onDragEnd(result: DropResult) { + if (!result.destination) { + return; + } + + if (result.destination.index === result.source.index) { + return; + } + + const newQuotes = reorder( + quotes, + result.source.index, + result.destination.index, + ); + + setQuotes(newQuotes); + } + + return ( + + + {(provided: DroppableProvided) => ( +
+ + {provided.placeholder} +
+ )} +
+
+ ); +} + +export default QuoteApp; diff --git a/test/unit/docs/content.spec.js b/test/unit/docs/content.spec.js index d80872eb5f..b7882fca4a 100644 --- a/test/unit/docs/content.spec.js +++ b/test/unit/docs/content.spec.js @@ -9,22 +9,23 @@ it('should end all nested docs with a link back to the documentation root', asyn const files: string[] = await globby('docs/**/*.md'); expect(files.length).toBeGreaterThan(0); const backLink: string = - '[← Back to documentation](/README.md#documentation-)\n'; + '[← Back to documentation](/README.md#documentation-)'; for (const file of files) { const contents: string = await fs.readFile(file, 'utf8'); - const isValid: boolean = contents.endsWith(backLink); - if (isValid) { - expect(isValid).toBe(true); - return; + // Printing a nice message to allow for quick fixing + const endsWithBacklink: boolean = contents.trim().endsWith(backLink); + + if (!endsWithBacklink) { + expect(` + File: "${file}" + Did not end with back link + `).toBe(true); } - // Printing a nice message to allow for quick fixing - expect(` - File: "${file}" - Did not end with back link - `).toBe(true); + // need at least one assertion + expect(true).toBe(true); } }); diff --git a/yarn.lock b/yarn.lock index e1baff5e95..03580643b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4720,6 +4720,11 @@ eslint-plugin-prettier@^3.0.1: dependencies: prettier-linter-helpers "^1.0.0" +eslint-plugin-react-hooks@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.5.0.tgz#cdd958cfff55bd5fa4f84db90d1490fb5ca4ae2b" + integrity sha512-iwDuWR2ReRgvJsNm8fXPtTKdg78IVQF8I4+am3ntztPf/+nPnWZfArFu6aXpaC75/iCYRrkqI8nPCYkxJstmpA== + eslint-plugin-react@^7.12.4: version "7.12.4" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz#b1ecf26479d61aee650da612e425c53a99f48c8c"