Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function components in docs #1266

Merged
merged 2 commits into from
Apr 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/about/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ You can use the UMD to run `react-beautiful-dnd` directly in the browser.
const ReactDOM = window.ReactDOM;
const { DragDropContext, Draggable, Droppable } = window.ReactBeautifulDnd;

class App extends React.Component {
//...
function App() {
// ...
}

// You can use JSX if your environment supports it
Expand Down
37 changes: 37 additions & 0 deletions docs/api/drag-drop-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ type Props = {|

## Basic usage

### Using a `class` component

```js
import React from 'react';
import { DragDropContext } from 'react-beautiful-dnd';

class App extends React.Component {
Expand Down Expand Up @@ -59,6 +62,40 @@ class App extends React.Component {
}
```

### Using a `function` component

```js
import React from 'react';
import { DragDropContext } from 'react-beautiful-dnd';

function App() {
const onBeforeDragStart = useCallback(() => {
/*...*/
}, []);

const onDragStart = useCallback(() => {
/*...*/
}, []);
const onDragUpdate = useCallback(() => {
/*...*/
}, []);
const onDragEnd = useCallback(() => {
// the only one that is required
}, []);

return (
<DragDropContext
onBeforeDragStart={onBeforeDragStart}
onDragStart={onDragStart}
onDragUpdate={onDragUpdate}
onDragEnd={onDragEnd}
>
<div>Hello world</div>
</DragDropContext>
);
}
```

## `Responder`s

> `Responders` were previously known as `Hooks`
Expand Down
43 changes: 40 additions & 3 deletions docs/api/droppable.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ const getBackgroundColor = (snapshot: DroppableStateSnapshot): string => {

When a user drags over, or stops dragging over, a `<Droppable />` we re-render the `<Droppable />` with an updated `DroppableStateSnapshot > isDraggingOver` value. This is useful for styling the `<Droppable />`. However, by default this will cause a render of all of the children of the `<Droppable />` - which might be 100's of `<Draggable />`s! This can result in a noticeable frame rate drop. To avoid this problem we recommend that you create a component that is the child of a `<Droppable />` who's responsibility it is to avoid rendering children if it is not required.

Here is an example of how you could do this:
Here is an example of how you could do this using `class` components:

```js
import React, { Component } from 'react';
Expand Down Expand Up @@ -229,7 +229,7 @@ class InnerList extends Component<{ students: Person[] }> {
}
}

class Students extends Component {
class Students extends Component<{ students: Person[] }> {
render() {
return (
<Droppable droppableId="list">
Expand All @@ -251,7 +251,44 @@ class Students extends Component {
}
```

By using the approach you are able to make style changes to a `<Droppable />` when it is being dragged over, but you avoid re-rendering all of the children unnecessarily. Keep in mind that if you are using `React.PureComponent` that your component will [not respond to changes in the context with the legacy context API](https://github.com/facebook/react/issues/2517).
Here is an example of how you could do this using `function` components:

```js
import React from 'react';

function Student (props: { student: Person }) {
// Renders out a draggable student
}

// do not re-render if the students list reference has not changed
const InnerList = React.memo(function InnerList(props: students: Person[]) {
return props.students.map((student: Person) => (
<Student student={student} />
));
});

function Students(props: { students: Person[] }) {
return (
<Droppable droppableId="list">
{(provided: DroppableProvided, snapshot: DroppableStateSnapshot) => (
<div
ref={provided.innerRef}
style={{
backgroundColor: provided.isDragging ? 'green' : 'lightblue',
}}
{...provided.droppableProps}
>
{/* only re-render if the students array reference changes */}
<InnerList students={props.students} />
{provided.placeholder}
</div>
)}
</Droppable>
);
}
```

By using the approach you are able to make style changes to a `<Droppable />` when it is being dragged over, but you avoid re-rendering all of the children unnecessarily.

When moving into a new list, the visible `Draggables` will have their `render` function called directly even with this optimisation. This is because we need to move those `Draggables` out of the way. The `InnerList` optimisation will prevent the `<Droppable />` from calling `render` on the whole list from the top down. This optimisation will prevent the non-visible `Draggables` from having their render function called.

Expand Down
26 changes: 8 additions & 18 deletions docs/guides/combining.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,14 @@ A `combine` result might signify different operations depending on your problem
When combining, a simple operation is to just remove the item that was dragging

```js
class App extends React.Component {
onDragEnd = result => {
// combining item
if (result.combine) {
// super simple: just removing the dragging item
const items: Quote[] = [...this.state.items];
items.splice(result.source.index, 1);
this.setState({ items });
return;
}
};

render() {
return (
<DragDropContext onDragEnd={this.onDragEnd}>
{this.props.children}
</DragDropContext>
);
function onDragEnd(result) {
// combining item
if (result.combine) {
// super simple: just removing the dragging item
const items: Quote[] = [...this.state.items];
items.splice(result.source.index, 1);
setState({ items });
return;
}
}
```
Expand Down
84 changes: 40 additions & 44 deletions docs/guides/drop-animation.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ type DropAnimation = {|
You can use the `DraggableDroppingState` to build up your own `transform` and `transition` properties during a drop.

```js
const getStyle = (style, snapshot): => {
function getStyle(style, snapshot) {
if (!snapshot.isDropAnimating) {
return style;
}
const {moveTo, curve, duration} = snapshot.dropAnimation;
const { moveTo, curve, duration } = snapshot.dropAnimation;
// move to the right spot
const translate = `translate(${moveTo.x}px, ${moveTo.y}px)`;
// add a bit of turn for fun
Expand All @@ -49,27 +49,25 @@ const getStyle = (style, snapshot): => {
// slowing down the drop because we can
transition: `all ${curve} ${duration + 1}s`,
};
};

class TaskItem extends React.Component {
render() {
const task = this.props.task;
return (
<Draggable draggableId={task.id} index={this.props.index}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
isDragging={snapshot.isDragging && !snapshot.isDropAnimating}
style={getStyle(provided.draggableProps.style, snapshot)}
>
{task.content}
</div>
)}
</Draggable>
);
}
}

function TaskItem(props) {
const { task, index } = props;
return (
<Draggable draggableId={task.id} index={index}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
isDragging={snapshot.isDragging && !snapshot.isDropAnimating}
style={getStyle(provided.draggableProps.style, snapshot)}
>
{task.content}
</div>
)}
</Draggable>
);
}
```

Expand All @@ -84,7 +82,7 @@ If you do have use case where it makes sense to remove the drop animation you wi
Do not make the `transition-duration` actually `0s`. It should be set at a near `0s` value such as `0.001s`. The reason for this is that if you set `transition-duration` to `0s` then a `onTransitionEnd` event will not fire - and we use that to know when the drop animation is finished.

```js
const getStyle = (style, snapshot): ?Object => {
function getStyle(style, snapshot) {
if (!snapshot.isDropAnimating) {
return style;
}
Expand All @@ -93,26 +91,24 @@ const getStyle = (style, snapshot): ?Object => {
// cannot be 0, but make it super tiny
transitionDuration: `0.001s`,
};
};

class TaskItem extends React.Component {
render() {
const task = this.props.task;
return (
<Draggable draggableId={task.id} index={this.props.index}>
{(provided, snapshot) => (
<div
innerRef={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={getStyle(provided.draggableProps.style, snapshot)}
>
{task.content}
</div>
)}
</Draggable>
);
}
}

function TaskItem(props) {
const { task, index } = props;
return (
<Draggable draggableId={task.id} index={index}>
{(provided, snapshot) => (
<div
innerRef={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={getStyle(provided.draggableProps.style, snapshot)}
>
{task.content}
</div>
)}
</Draggable>
);
}
```

Expand Down
4 changes: 4 additions & 0 deletions docs/support/media.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ This page contains a list of articles, blogs and newsletters that `react-beautif
- [Dragging React performance forward](https://medium.com/@alexandereardon/dragging-react-performance-forward-688b30d40a33)
- [Grabbing the flame 🔥](https://medium.com/@alexandereardon/grabbing-the-flame-290c794fe852)

## React ecosystem

- [Deep Sea Fishing with React Hooks](https://www.youtube.com/watch?v=MVi17tk3VsI)

## Podcasts

- [React podcast: Fast, Accessible, and Beautiful Drag and Drop with Alex Reardon](https://reactpodcast.simplecast.fm/17)
Expand Down