Javascript 如何在React中的事件后触发效果

Javascript 如何在React中的事件后触发效果,javascript,reactjs,events,material-ui,Javascript,Reactjs,Events,Material Ui,我正在构建一个React应用程序,它基本上加载博客帖子,并为每个帖子添加评论 呈现博客文章时,也会获取该博客文章的评论。我还有一个组件,允许提交评论 单击submit按钮时,我希望注释刷新其数据源,并立即显示新注释。 如何向我们的comments组件发送某种事件,告诉它发送另一个获取请求 这个问题的核心似乎是: 我如何习惯性地将事件发送到将触发效果的其他React组件 编辑-一般解决方案: 将状态提升到最近的部件 创建包含状态更新函数的回调函数。将此回调作为道具传递给将触发事件的组件。事件发生时

我正在构建一个React应用程序,它基本上加载博客帖子,并为每个帖子添加评论

呈现博客文章时,也会获取该博客文章的评论。我还有一个组件,允许提交评论

单击submit按钮时,我希望注释刷新其数据源,并立即显示新注释。 如何向我们的comments组件发送某种事件,告诉它发送另一个获取请求

这个问题的核心似乎是:

我如何习惯性地将事件发送到将触发效果的其他React组件

编辑-一般解决方案:

  • 将状态提升到最近的部件
  • 创建包含状态更新函数的回调函数。将此回调作为道具传递给将触发事件的组件。事件发生时,在处理程序中运行回调
  • Post.js
    从“React”导入React;
    从“react”导入{useState、useEffect、useContext};
    从“减价到jsx”导入减价;
    从“@material ui/core/Container”导入容器;
    从“@material ui/core/Typography”导入排版;
    从“/SendComment”导入SendComment;
    从“/Comments”导入注释;
    从“/URL”导入{POST_URL};
    从“./UserContext”导入UserContext;
    //从“/CommentListContainer”导入CommentListContainer;
    导出默认功能帖子(道具){
    const user=useContext(UserContext);
    const[post,setPost]=useState({
    内容:“”,
    评论:[],
    });
    useffect(()=>{
    const UNIQUE_POST_URL=[POST_URL,props.location.state.id].join('/');
    const fetchPost=async()=>{
    const result=等待获取(唯一的发布URL);
    const json=wait result.json();
    setPost(json);
    };
    fetchPost();
    },[props.location.state.id]);
    返回(
    {post.title}
    {post.content}
    {post.content.length!==0&&(
    评论
    )}
    );
    }
    
    SendComment.js组件
    从“React”导入React;
    从“@material ui/core/TextField”导入TextField;
    从“@material ui/core/Grid”导入网格;
    从“@material ui/core/Button”导入按钮;
    从“@material ui/core/Paper”导入纸张;
    从“/URL”导入{COMMENT_SUBMIT_URL};
    导出默认函数SendComment(道具){
    异步函数handleSubmit(e){
    const comment=document.querySelector(“#comment”);
    //跳过空评论
    如果(comment.value==''){
    返回;
    }
    异步函数sendComment(url){
    试一试{
    const res=等待获取(url{
    方法:“POST”,
    正文:JSON.stringify({
    comment:comment.value,
    users\u id:props.user.users\u id,
    posts\u id:props.posts\u id,
    }),
    标题:{
    接受:'application/json',
    “内容类型”:“应用程序/json”,
    “接受语言”:“en-US”,
    },
    });
    comment.value='';
    返回res;
    }捕获(e){
    控制台日志(e);
    }
    }
    const res=wait sendcoment(COMMENT\u SUBMIT\u URL);
    如果(res.ok){
    //重新加载我们的评论组件!
    //这是我们要发送“事件”的地方
    //或者不管解决方案是什么
    }
    }
    返回(
    提交
    );
    }
    
    Comments.js
    从“React”导入React;
    从“react”导入{useState,useEffect};
    从“@material ui/core/List”导入列表;
    从“@material ui/core/ListItem”导入ListItem;
    从“@material ui/core/ListItemText”导入ListItemText;
    从“@material ui/core/ListItemAvatar”导入ListItemAvatar;
    从“@material ui/core/Avatar”导入化身;
    从“@material ui/core/Divider”导入分隔器;
    从“/utils”导入{timeAgo};
    从“/URL”导入{COMMENT_URL};
    导出默认函数注释(道具){
    const[comments,setComments]=useState({
    对象:[],
    });
    useffect(()=>{
    异步函数getComments(posts\u id){
    const filter=JSON.stringify({
    筛选器:[{name:'posts\u id',op:'equals',val:posts\u id}],
    });
    试一试{
    注释\u URL.searchParams.set('q',过滤器);
    const res=等待获取(注释URL{
    方法:“GET”,
    标题:{
    接受:'application/json',
    “内容类型”:“应用程序/json”,
    },
    });
    const json=await res.json();
    setComments(json);
    }捕获(e){
    控制台日志(e);
    }
    }
    getComments(道具、帖子和id);
    },[props.posts_id]);
    const commentList=comments.objects.map(comment=>(
    ));
    返回{commentList};
    }
    
    此代码目前有效,但新注释仅在重新加载页面时显示,而不是在提交后立即显示。

    这里有一个想法:

    你应该在帖子中对状态变量发表评论

    像这样
    const[comments,setComments]=useState([])

    您可以在
    sendcoment
    中收到一个名为
    onCommentSent
    的道具。 在代码中,当发送注释时,执行
    onCommentSent()

    因此,在POST中,当发送注释时,可以重新加载注释的数据,并使用
    setComments(newData)
    将其设置为
    comments
    。 当状态重新加载时,注释将重新蚀刻


    一个更好的方法是不要在每个comment POST请求中检索所有注释,您可以动态更新状态变量
    comments
    中的数据,知道下次获取服务器时,注释会出现

    希望有帮助

    这里有一个想法:

    你应该在帖子中对状态变量发表评论

    像这样
    const[comments,setComments]=useState([])

    你可以
    import React from 'react';
    import {useState, useEffect, useContext} from 'react';
    import Markdown from 'markdown-to-jsx';
    import Container from '@material-ui/core/Container';
    import Typography from '@material-ui/core/Typography';
    import SendComment from './SendComment';
    import Comments from './Comments';
    import {POST_URL} from './urls';
    import UserContext from './UserContext';
    //import CommentListContainer from './CommentListContainer';
    
    export default function Post(props) {
      const user = useContext(UserContext);
    
      const [post, setPost] = useState({
        content: '',
        comments: [],
      });
    
      useEffect(() => {
        const UNIQUE_POST_URL = [POST_URL, props.location.state.id].join('/');
    
        const fetchPost = async () => {
          const result = await fetch(UNIQUE_POST_URL);
          const json = await result.json();
          setPost(json);
        };
        fetchPost();
      }, [props.location.state.id]);
    
      return (
        <div>
          <Container>
            <Typography
              variant="h4"
              color="textPrimary"
              style={{textDecoration: 'underline'}}>
              {post.title}
            </Typography>
            <Markdown>{post.content}</Markdown>
            {post.content.length !== 0 && (
              <div>
                <Typography variant="h4">Comments</Typography>
                <SendComment user={user} posts_id={props.location.state.id} />
                <Comments user={user} posts_id={props.location.state.id} />
              </div>
            )}
          </Container>
        </div>
      );
    }
    
    import React from 'react';
    import TextField from '@material-ui/core/TextField';
    import Grid from '@material-ui/core/Grid';
    import Button from '@material-ui/core/Button';
    import Paper from '@material-ui/core/Paper';
    import {COMMENT_SUBMIT_URL} from './urls';
    
    export default function SendComment(props) {
      async function handleSubmit(e) {
        const comment = document.querySelector('#comment');
    
        // Skip empty comments
        if (comment.value === '') {
          return;
        }
    
        async function sendComment(url) {
          try {
            const res = await fetch(url, {
              method: 'POST',
              body: JSON.stringify({
                comment: comment.value,
                users_id: props.user.users_id,
                posts_id: props.posts_id,
              }),
              headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'Accept-Language': 'en-US',
              },
            });
            comment.value = '';
            return res;
          } catch (e) {
            console.log(e);
          }
        }
        const res = await sendComment(COMMENT_SUBMIT_URL);
        if (res.ok) {
          // Reload our comment component !
          // Here is where we want to send our "event"
          // or whatever the solution is
        }
      }
    
      return (
        <Grid container justify="space-evenly" direction="row" alignItems="center">
          <Grid item xs={8}>
            <TextField
              id="comment"
              fullWidth
              multiline
              rowsMax="10"
              margin="normal"
              variant="filled"
            />
          </Grid>
          <Grid item xs={3}>
            <Button variant="contained" color="primary" onClick={handleSubmit}>
              Submit
            </Button>
          </Grid>
        </Grid>
      );
    }
    
    import React from 'react';
    import {useState, useEffect} from 'react';
    import List from '@material-ui/core/List';
    import ListItem from '@material-ui/core/ListItem';
    import ListItemText from '@material-ui/core/ListItemText';
    import ListItemAvatar from '@material-ui/core/ListItemAvatar';
    import Avatar from '@material-ui/core/Avatar';
    import Divider from '@material-ui/core/Divider';
    import {timeAgo} from './utils';
    import {COMMENT_URL} from './urls';
    
    export default function Comments(props) {
      const [comments, setComments] = useState({
        objects: [],
      });
    
      useEffect(() => {
        async function getComments(posts_id) {
          const filter = JSON.stringify({
            filters: [{name: 'posts_id', op: 'equals', val: posts_id}],
          });
    
          try {
            COMMENT_URL.searchParams.set('q', filter);
    
            const res = await fetch(COMMENT_URL, {
              method: 'GET',
              headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
              },
            });
            const json = await res.json();
            setComments(json);
          } catch (e) {
            console.log(e);
          }
        }
        getComments(props.posts_id);
      }, [props.posts_id]);
    
      const commentList = comments.objects.map(comment => (
        <ListItem key={comment.id} alignItems="flex-start">
          <ListItemAvatar>
            <Avatar alt={comment.users.name} src={comment.users.picture} />
          </ListItemAvatar>
          <ListItemText
            primary={`${comment.users.name} - ${timeAgo(comment.created_at)}`}
            secondary={comment.comment}></ListItemText>
          <Divider />
        </ListItem>
      ));
    
      return <List>{commentList}</List>;
    }
    
    export default function Post(props) {
      const user = useContext(UserContext);
    
      const [content, setContent] = useState('')
      const [title, setTitle] = useState('')
      const [comments, setComments] = useState([])
    
      const onNewComment = useCallback((text) => {
        // I'm not sure about your comment structure on server. 
        // So here you need to create an object that your `Comments` component 
        // will be able to display and then do `setComments(comments.concat(comment))` down below
        const comment = { 
          comment: text,
          users_id: user.users_id,
          posts_id: props.location.state.id,
        };
        async function sendComment(url) {
          try {
            const res = await fetch(url, {
              method: 'POST',
              body: JSON.stringify(comment),
              headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'Accept-Language': 'en-US',
              },
            });
            return res;
          } catch (e) {
            console.log(e);
          }
        }
        const res = await sendComment(COMMENT_SUBMIT_URL);
        if (res.ok) {
          setComments(comments.concat(comment));
        }
      }, [comments]);
    
      useEffect(() => {
        const UNIQUE_POST_URL = [POST_URL, props.location.state.id].join('/');
    
        const fetchPost = async () => {
          const result = await fetch(UNIQUE_POST_URL);
          const { content, comments, title } = await result.json();
          setContent(content);
          setComments(comments);
          setTitle(title);
        };
        fetchPost();
      }, [props.location.state.id]);
    
      return (
        <div>
          <Container>
            <Typography
              variant="h4"
              color="textPrimary"
              style={{textDecoration: 'underline'}}>
              {title}
            </Typography>
            <Markdown>{content}</Markdown>
            {content.length !== 0 && (
              <div>
                <Typography variant="h4">Comments</Typography>
                <SendComment user={user} onNewComment={onNewComment} />
                <Comments user={user} comments={comments} />
              </div>
            )}
          </Container>
        </div>
      );
    }
    
    export default function SendComment(props) {
      const [text, setText] = useState('');
      const handleSubmit = useCallback(() => {
        // Skip empty comments
        if (comment.value === '') {
          return;
        }
        if(props.onNewComment) {
          props.onNewComment(text);
          setText('');
        }
      }, [props.onNewComment, text]);
    
      return (
        <Grid container justify="space-evenly" direction="row" alignItems="center">
          <Grid item xs={8}>
            <TextField
              id="comment"
              onChange={setText}
              fullWidth
              multiline
              rowsMax="10"
              margin="normal"
              variant="filled"
            />
          </Grid>
          <Grid item xs={3}>
            <Button variant="contained" color="primary" onClick={handleSubmit}>
              Submit
            </Button>
          </Grid>
        </Grid>
      );
    }
    
    export default function Comments(props) {
      const commentList = props.comments.map(comment => (
        <ListItem key={comment.id} alignItems="flex-start">
          <ListItemAvatar>
            <Avatar alt={comment.users.name} src={comment.users.picture} />
          </ListItemAvatar>
          <ListItemText
            primary={`${comment.users.name} - ${timeAgo(comment.created_at)}`}
            secondary={comment.comment}></ListItemText>
          <Divider />
        </ListItem>
      ));
    
      return <List>{commentList}</List>;
    }
    
    export default function SendComment(props) {
      const [comments, setComments] = useState({
        objects: [],
      });
    
      async function getComments(posts_id) {
        const filter = JSON.stringify({
          filters: [{name: 'posts_id', op: 'equals', val: posts_id}],
        });
    
        try {
          COMMENT_URL.searchParams.set('q', filter);
    
          const res = await fetch(COMMENT_URL, {
            method: 'GET',
            headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json',
            },
          });
          const json = await res.json();
          setComments(json);
        } catch (e) {
          console.log(e);
        }
      }
    
      useEffect(() => {
        getComments(props.posts_id);
      }, [props.posts_id]);
    
      async function handleSubmit(e) {
        const comment = document.querySelector('#comment');
    
        // Skip empty comments
        if (comment.value === '') {
          return;
        }
    
        async function sendComment(url) {
          try {
            const res = await fetch(url, {
              method: 'POST',
              body: JSON.stringify({
                comment: comment.value,
                users_id: props.user.users_id,
                posts_id: props.posts_id,
              }),
              headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'Accept-Language': 'en-US',
              },
            });
            comment.value = '';
            return res;
          } catch (e) {
            console.log(e);
          }
        }
        const res = await sendComment(COMMENT_SUBMIT_URL);
        if (res.ok) {
          getComments(props.posts_id);
        }
      }
    
      return (
        <>
          <Grid
            container
            justify="space-evenly"
            direction="row"
            alignItems="center">
            <Grid item xs={8}>
              <TextField
                id="comment"
                fullWidth
                multiline
                rowsMax="10"
                margin="normal"
                variant="filled"
              />
            </Grid>
            <Grid item xs={3}>
              <Button variant="contained" color="primary" onClick={handleSubmit}>
                Submit
              </Button>
            </Grid>
          </Grid>
          <Grid container justify="space-left">
            <Grid item justify="flex-start">
              <Comments comments={comments} />
            </Grid>
          </Grid>
        </>
      );
    }