Перерисовать компонент с помощью useEffect, когда что-то изменится в дочернем компоненте - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть приложение, которое позволяет пользователю добавлять задачи в список. Задачи извлекаются из API и отображаются с помощью компонента «Список». Когда пользователь добавляет новую задачу из компонента «AddButton», задача сохраняется в базе данных. Я хочу, чтобы повторно визуализировать компонент «Список», когда функция handleSubmit происходит на компоненте «AddButton» и добавляет задачу в базу данных. «AddTask» и «getTasks» извлекают данные из API. Заранее спасибо за помощь.

Компонент списка

import React, { useState, useEffect } from 'react';
import { makeStyles } from '@material-ui/styles';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import Moment from 'react-moment';
import { getTasks } from './services/getTasks';
import AddButton from './AddButton';
import './App.css';

const useStyles = makeStyles(theme => ({
  root: {
    display: 'flex',
    flexDirection: 'column',
    width: '100%',
    justifyContent: 'space-between',
    height: '100%',
    fontSize: '16px',
  },
  listItemLinkRoot: {
    paddingLeft: theme.spacing(3),
    width: '100%',
    '&:hover': {
      backgroundColor: '#212121',
      color: 'white',
    },
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'flex-start',
  },

  buttonContainer: {
    display: 'flex',
    width: '100%',
    flexDirection: 'column',
    justifyContent: 'flex-end',
  },

  list: {
    flexGrow: 1,
    overflow: 'auto',
  },

  listItemText: {
    marginBottom: 8,
    // fontSize: 20,
  },
}));

function ListItemLink(props) {
  return <ListItem button component="a" {...props} />;
}

export default function TaskList() {
  const classes = useStyles();
  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const result = await getTasks();
      setTasks(result);
    };

    fetchData();
  }, []);

  return (
    <div className={classes.root}>
      <List classes={{ root: classes.list }}>
        {tasks.map(task => (
          <ListItemLink
            divider
            key={task.id}
            classes={{ root: classes.listItemLinkRoot }}
            href="simple-list"
          >
            <ListItemText
              classes={{ root: classes.listItemText }}
              primary={task.description}
            />
            <Moment
              classes={{ root: classes.listItemDate }}
              format="DD/MM/YYYY"
            >
              {task.createdAt}
            </Moment>
          </ListItemLink>
        ))}
      </List>
      <div className={classes.buttonContainer}>
        <AddButton classes={{ root: classes.add }} />
      </div>
    </div>
  );
}


Компонент AddButton


import React, { useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Fab from '@material-ui/core/Fab';
import AddIcon from '@material-ui/icons/Add';
import TextField from '@material-ui/core/TextField';
import { addTask } from './services/postTask';

const useStyles = makeStyles(theme => ({
  cont: {
    display: 'flex',
    flexDirection: 'row',
    paddingBottom: '24px',
    justifyContent: 'space-between',
    backgroundColor: '#e0e0e0',
    width: '100%',
    alignItems: 'center',
    felxGrow: 1,
  },
  fab: {
    marginTop: theme.spacing(2),
    marginRight: theme.spacing(2),
    width: '100%',
  },

  textField: {
    marginLeft: theme.spacing(3),
    marginTop: 0,
    marginBottom: 0,
    flexGrow: 1,
  },
}));

export default function AddButton() {
  const classes = useStyles();
  const [task, setTask] = useState({
    description: '',
    completed: false,
  });

  const handleChange = ev => {
    setTask({ ...task, [ev.target.id]: ev.target.value });
  };

  const handleSubmit = () => {
    addTask(task);
  };

  return (
    <div className={classes.cont}>
      <TextField
        onChange={handleChange}
        id="description"
        label="Add a task"
        rowsMax="4"
        className={classes.textField}
        margin="normal"
      />
      <Fab
        onClick={handleSubmit}
        variant="extended"
        size="small"
        color="primary"
        aria-label="add"
        className={classes.fab}
      >
        <AddIcon />
        Add
      </Fab>
    </div>
  );
}

Ответы [ 2 ]

1 голос
/ 01 ноября 2019

В вашем компоненте списка вы можете использовать функцию handleSubmit и передавать ее вашему дочернему компоненту AddButton:

<AddButton classes={{ root: classes.add }} handleSubmit={handleSubmit} />
0 голосов
/ 01 ноября 2019

Единственное решение, которое я могу придумать, - это переместить функцию fetchData за пределы вашего useEffect крюка и передать ее кнопке в качестве опоры:


const fetchData = async () => {
     const result = await getTasks();
     setTasks(result);
 };

useEffect(() => {
    fetchData();
  }, []);

...

<AddButton classes={{ root: classes.add }} refetch={fetchData}/>

Затем в AddButton (при условии addTask() is async).

const handleSubmit = () => {
    addTask(task)
      .then(res => props.refetch())
  };

Хотя может иметь смысл обрабатывать все функции состояния в родительском компоненте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...