Javascript 当子组件中发生更改时,使用useEffect重新渲染组件

Javascript 当子组件中发生更改时,使用useEffect重新渲染组件,javascript,reactjs,rerender,use-effect,Javascript,Reactjs,Rerender,Use Effect,我有一个应用程序,允许用户在列表中添加任务。任务从API中获取,并与“列表”组件一起显示。当用户从“AddButton”组件添加新任务时,该任务存储在数据库中。 我希望在“AddButton”组件上出现handleSubmit函数并将任务添加到数据库时,重新呈现“List”组件。“addTask”和“getTask”正在从API获取数据。 提前谢谢你的帮助 列表组件 import React, { useState, useEffect } from 'react'; import { make

我有一个应用程序,允许用户在列表中添加任务。任务从API中获取,并与“列表”组件一起显示。当用户从“AddButton”组件添加新任务时,该任务存储在数据库中。 我希望在“AddButton”组件上出现handleSubmit函数并将任务添加到数据库时,重新呈现“List”组件。“addTask”和“getTask”正在从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>
  );
}



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>
  );
}

import React,{useState,useffect}来自“React”;
从'@material ui/styles'导入{makeStyles};
从“@material ui/core/List”导入列表;
从“@material ui/core/ListItem”导入ListItem;
从“@material ui/core/ListItemText”导入ListItemText;
从“反应力矩”导入力矩;
从“./services/getTasks”导入{getTasks};
从“/AddButton”导入AddButton;
导入“/App.css”;
const useStyles=makeStyles(主题=>({
根目录:{
显示:“flex”,
flexDirection:'列',
宽度:“100%”,
justifyContent:'之间的空间',
高度:“100%”,
fontSize:'16px',
},
listItemLinkRoot:{
paddingLeft:主题。间距(3),
宽度:“100%”,
“&:悬停”:{
背景颜色:“#212121”,
颜色:'白色',
},
显示:“flex”,
flexDirection:'列',
alignItems:'flex start',
},
按钮容器:{
显示:“flex”,
宽度:“100%”,
flexDirection:'列',
justifyContent:“柔性端”,
},
名单:{
flexGrow:1,
溢出:“自动”,
},
listItemText:{
marginBottom:8,
//尺寸:20,
},
}));
函数ListItemLink(道具){
返回;
}
导出默认函数任务列表(){
const classes=useStyles();
const[tasks,setTasks]=useState([]);
useffect(()=>{
const fetchData=async()=>{
const result=await getTasks();
设置任务(结果);
};
fetchData();
}, []);
返回(
{tasks.map(task=>(
{task.createdAt}
))}
);
}
添加按钮组件

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>
  );
}



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>
  );
}


从“React”导入React,{useState};
从'@material ui/core/styles'导入{makeStyles};
从“@material ui/core/Fab”导入晶圆厂;
从“@material ui/icons/Add”导入AddIcon;
从“@material ui/core/TextField”导入TextField;
从“./services/postTask”导入{addTask};
const useStyles=makeStyles(主题=>({
续:{
显示:“flex”,
flexDirection:'行',
填充底部:“24px”,
justifyContent:'之间的空间',
背景颜色:'#e0',
宽度:“100%”,
对齐项目:“居中”,
felxGrow:1,
},
晶圆厂:{
marginTop:主题。间距(2),
边缘光:主题。间距(2),
宽度:“100%”,
},
文本字段:{
边缘左侧:主题。间距(3),
玛金托普:0,
marginBottom:0,
flexGrow:1,
},
}));
导出默认函数AddButton(){
const classes=useStyles();
const[task,setTask]=useState({
说明:“”,
已完成:错误,
});
常数handleChange=ev=>{
setTask({…task[ev.target.id]:ev.target.value});
};
常量handleSubmit=()=>{
添加任务(task);
};
返回(
添加
);
}

在列表组件中,您可以使用handleSubmit函数并将其传递给子AddButton组件:

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

我能想到的一个解决方案是将
fetchData
函数移到
useffect
挂钩之外,并将其作为道具传递给按钮:


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

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

...

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

尽管在父组件中处理所有状态功能可能更有意义。

我将使用名称而不是id作为输入,因为id对于整个文档必须是唯一的,并且没有任何组件可以或应该保证某个id已经被另一个组件使用。如果列表管理任务,为什么不将addTask传递给按钮,并将其设置为添加任务时的状态?您好,谢谢您的时间。你能澄清你的第二条评论吗?关于你的第一条评论,你的意思是在handleChange函数中使用name而不是id吗?再次谢谢你,谢谢你的回答。如果列表组件中有handleSubmit函数,那么既然handleChange函数位于另一个组件中,现在如何才能确定要添加到列表中的任务?您好,谢谢您的回复。我也想到了这一点,但我想处理列表组件中的状态,正如您所提到的。我想在按钮组件中处理它会变得更复杂。无论如何,谢谢你抽出时间。