使用挂钩重新渲染同级组件

时间:2020-07-21 22:04:39

标签: javascript reactjs react-hooks

我是新来的反应者,我正在尝试从另一个组件重新渲染一个组件。

这是我的代码:

const Parent = () => {
    return (
        <div>
            <Child1 />
            <Child2 />
        </div>
    )
}

我打算做的是在Child2触发某些事件时更新Child1。

我能想到的一种方法是让父组件重新渲染,这样Child1和Child2都将被更新。我试图通过解除状态来做到这一点,但是它似乎并没有重新渲染每个子组件。这是代码

const Parent = () => {
    const [value, setValue] = useState('')

    const handlePost = (newValue) => {
        setValue(newValue)
    }

    return (
        <div>
            <Child1 />
            <Child2 onPost={handlePost} />
        </div>
    )
}

const Child2 = (props) => {
    // This function is executed when there is a trigger. 
    // In this case, when a post request is made to the server
    const onPost() => {
        props.handlePost('new value')
    }
}

编辑: 需要重新渲染组件的原因是因为它们正在对API进行更改,并且这些更改需要反映在屏幕上。它与任何状态变量无关。

3 个答案:

答案 0 :(得分:0)

Ciao,可以说必须在handlePost上重新渲染Child1。您的父组件将是:

const Parent= () => {
const [value, setValue] = useState('')
const [rerender, setrerender] = useState(false)

const handlePost = (newValue) => {
    setValue(newValue);
    let setrerender_temp = rerender;
    setrerender(!setrerender_temp);
}

return (
    <div>
        <Child1 rerender={rerender} />
        <Child2 onPost={handlePost} />
    </div>
)
}

然后,在您的Child1组件中:

import React, { useReducer, useEffect } from 'react';
...

export default function Child1(props) {
   const [,forceRender] = useReducer((s) => s+1, 0);
   useEffect(() => forceRender(), [props.rerender]);
   ...
}

答案 1 :(得分:0)

您的问题是XY问题。在给出的示例中,Child1重新渲染没有意义,因为不需要它。从注释中,您的实际问题是您更新了一个API,这应该会更改另一个API的响应。但是,如果您已经知道响应将如何变化以及将如何变化,则可以在两个API调用都变化的一种状态中反映出来:

 function useEntries() {
   const [entries, setEntries] = useState([]);

   useEffect(() => {
      setEntries(getEntries());
   }, []);

   function addEntry(entry) {
     postEntry(entry);
    setEntries(prev => [...prev, entry]);
   }

   return { entries, addEntry };
 }

 function Parent() {
   const { entries, addEntry } = useEntries();

   return <>
     <Entries entries={entries} />
     <AddEntry addEntry={addEntry} />
   </>;
  }
     

  

答案 2 :(得分:0)

从帖子中的评论看来,您Child1展示了GET请求的结果(已在Child1中完成)。 Child2可以通过某种请求在服务器上添加或修改该状态,并且您想触发重新渲染以使Child1刷新状态。

一般的问题是,只有在道具或其使用的上下文发生变化时,孩子才应该重新渲染。我看到了两种解决方法:

  1. 将对请求的处理提升到父级。将请求的结果作为道具放入您要刷新的子组件中。

  2. 通过以某种方式将其设置为“脏”,使同级节点意识到必须重新加载该请求。通过上下文或通过父级路由状态。

通常,如果组件的嵌套不是太深,则最好使用选项1。看起来可能像这样:

const Parent = () => {
  const [posts, setPosts] = useState([]);
  const fetchNewestPosts = useCallback(async () => {
    const fetched = await fetchPosts();
    setPosts(fetched);
  }, [fetchPosts, setPosts]);
  const handleSubmit = useCallback(async (event) => {
    const newPost = getValuesFromSubmitEvent(event);
    await sendNewPost(newPost);
    // you could even set the posts here to what you think the 
    // send request will result in (see Jonas Wilms answer), like
    // setPosts(posts => [newPost, ...posts]);
    await fetchNewestPosts();
  }, [fetchNewestPosts, getValuesFromSubmitEvent, sendNewPost]);

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

  return (
    <div>
      <Child1 posts={posts} />
      <Child2 submitNewPost={submitNewPost} />
    </div>
  );
);

const Child1 = ({posts}) => {
  return (
    <ul>{posts.map(post => <li key={post.id}>post.title</li>)}</ul>
  );
);

const Child2 = ({submitNewPost}) => {
  return (
    <form onSubmit={submitNewPost}>...</form>
  );
);

作为一个很好的副作用,Child1Child2现在需要少得多的逻辑,并且可以独立于fetchPostssendNewPost函数来设置样式。