使用上下文将类组件重构为功能组件

时间:2019-11-09 03:07:09

标签: reactjs react-hooks

我正在尝试将一些代码从类重构为功能组件,以使其与我的应用程序的其余部分保持一致。这些类正在更新状态,在应用程序中,它们将需要更新名为cardContext.js的上下文。我要做的第一件事是将类重新编写为功能组件,以便更新上下文而不是内部状态。

我的网站大部分都通过带有挂钩的功能组件工作,而我正在使用上下文。

每个上下文都有3个文件;

  • ExampleState.js
  • exampleContext.js
  • exampleReducer.js

到目前为止,该应用程序的代码在https://codesandbox.io/s/infshot-978on?fontsize=14处)(预览不起作用,因为我不认为codeandbox可以完成完整的堆栈应用程序,但是您可以通过client> src>组件查看相关的代码>卡和客户端> src>组件>上下文>卡。

我正在尝试将一些编码为类的组件集成到我的应用中,以便以相同的方式工作,以便可以对其进行集成。首先,我需要重构它们,以使其成为功能组件并以与我的应用程序其余部分相同的形式使用上下文。新组件使用的是称为React Beautiful DND的框架,我使用创建类组件的教程来创建它们。

我一直在研究如何重构它们。

我要重构的第一个文件如下

// files in context/dnd editor are placeholders
import React from 'react';
import ReactDOM from 'react-dom';
import '@atlaskit/css-reset';
import 'materialize-css/dist/css/materialize.min.css';
import '../../index.css'

import styled from 'styled-components';
import { DragDropContext } from 'react-beautiful-dnd';
import initialData from './initialData';
import Column from './column';


const Container = styled.div`
  display: flex;
`;

export default class dndEditor extends React.Component {
  state = initialData;

  onDragEnd = result => {
    document.body.style.color = 'inherit';
    const { destination, source, draggableId } = result;
    if (!destination) {
      return;
    }
    if (
      destination.droppableId === source.droppableId &&
      destination.index === source.index
    ) {
      return;
    }

    const start = this.state.columns[source.droppableId];
    const finish = this.state.columns[destination.droppableId];

    if (start === finish) {
      const newTaskIds = Array.from(start.taskIds);
      newTaskIds.splice(source.index, 1);
      newTaskIds.splice(destination.index, 0, draggableId);

      const newColumn = {
        ...start,
        taskIds: newTaskIds
      };
      const newState = {
        ...this.state,
        columns: {
          ...this.state.columns,
          [newColumn.id]: newColumn
        }
      };
      this.setState(newState);
      return;
    }
    //Start and finnish columns are different
    const startTaskIds = Array.from(start.taskIds);
    startTaskIds.splice(source.index, 1);
    const newStart = {
      ...start,
      taskIds: startTaskIds
    };

    const finishTaskIds = Array.from(finish.taskIds);
    finishTaskIds.splice(source.index, 0, draggableId);
    const newFinish = {
      ...finish,
      taskIds: finishTaskIds
    };

    const newState = {
      ...this.state,
      columns: {
        ...this.state.columns,
        [newStart.id]: newStart,
        [newFinish.id]: newFinish
      }
    };
    this.setState(newState);
    return;
  };

  render() {
    return (
      <Container>
        <DragDropContext onDragEnd={this.onDragEnd}>
          {this.state.columnOrder.map(columnId => {
            const column = this.state.columns[columnId];
            const tasks = column.taskIds.map(
              taskId => this.state.tasks[taskId]
            );

            return <Column key={column.id} column={column} tasks={tasks} />;
          })}
        </DragDropContext>

      </Container>
    );
  }
}


这是initialData.js文件(初始状态)在下面

const InitialData = {
  tasks: {
    'task-1': {
      id: 'task-1',
      content: 'Take out the trash and another thing also'
    },
    'task-2': { id: 'task-2', content: 'another link' },
    'task-3': { id: 'task-3', content: 'clear desk' },
    'task-4': { id: 'task-4', content: 'do pushups' }
  },
  columns: {
    'column-1': {
      id: 'column-1',
      title: 'FACTS',
      taskIds: ['task-2', 'task-3', 'task-4']
    },
    'column-2': {
      id: 'column-2',
      title: 'PROS',
      taskIds: ['task-1']
    },
    'column-3': {
      id: 'column-3',
      title: 'CONS',
      taskIds: []
    }
  },
  columnOrder: ['column-1', 'column-2', 'column-3']
};
export default InitialData;

(我要重构的所有文件都在下面的功能代码和框中) https://codesandbox.io/s/react-beautiful-dnd-trello-example-ohxsi?fontsize=14

1 个答案:

答案 0 :(得分:0)

我不遵循确切的挑战。将setState + this.state重构为useState应该可以。该组件提供上下文,而不是消耗。因此,与上下文相关的所有内容都保持不变。

export default function DndEditor() {
  const [state, setState] = useState(initialData);

  onDragEnd = result => {
    document.body.style.color = 'inherit';
    const { destination, source, draggableId } = result;
    if (!destination) {
      return;
    }
    if (
      destination.droppableId === source.droppableId &&
      destination.index === source.index
    ) {
      return;
    }

    const start = state.columns[source.droppableId];
    const finish = state.columns[destination.droppableId];

    if (start === finish) {
      const newTaskIds = Array.from(start.taskIds);
      newTaskIds.splice(source.index, 1);
      newTaskIds.splice(destination.index, 0, draggableId);

      const newColumn = {
        ...start,
        taskIds: newTaskIds
      };
      const newState = {
        ...this.state,
        columns: {
          ...state.columns,
          [newColumn.id]: newColumn
        }
      };
      setState(newState);
      return;
    }
    //Start and finnish columns are different
    const startTaskIds = Array.from(start.taskIds);
    startTaskIds.splice(source.index, 1);
    const newStart = {
      ...start,
      taskIds: startTaskIds
    };

    const finishTaskIds = Array.from(finish.taskIds);
    finishTaskIds.splice(source.index, 0, draggableId);
    const newFinish = {
      ...finish,
      taskIds: finishTaskIds
    };

    const newState = {
      ...state,
      columns: {
        ...state.columns,
        [newStart.id]: newStart,
        [newFinish.id]: newFinish
      }
    };
    setState(newState);
    return;
  };

  return (
    <Container>
      <DragDropContext onDragEnd={onDragEnd}>
        {state.columnOrder.map(columnId => {
          const column = state.columns[columnId];
          const tasks = column.taskIds.map(
            taskId => state.tasks[taskId]
          );
           return <Column key={column.id} column={column} tasks={tasks} />;
        })}
      </DragDropContext>
     </Container>
  );
}

您还可能希望将state分成独立的

const [columns, setColumns] = useState(initialData.columns);
const [tasks, setTasks] = useState(initialData.tasks);

具有更好的可读性,但是首先尝试[state, setState]是重构的最简单方法。