简体   繁体   English

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

[英]Re-render a sibling component using hooks

I am new to react and I'm trying to get the one component to re-render from another component.我是新来的反应,我试图让一个组件从另一个组件重新渲染。

Here's my code:这是我的代码:

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

What I intend to do is update Child1 when there is some trigger from Child2.我打算做的是在 Child2 有一些触发器时更新 Child1。

One way I can think of is to get the parent component to re-render so both Child1 and Child2 will be updated.我能想到的一种方法是让父组件重新渲染,这样 Child1 和 Child2 都会被更新。 I tried to do this by lifting the state but it doesn't seem to re-render each of the child components.我试图通过提升 state 来做到这一点,但它似乎并没有重新渲染每个子组件。 Here's the code这是代码

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

Edit: The reason why the component(s) needs to be re-rendered is because they are making changes to the API and these changes need to be reflected on the screen.编辑:需要重新渲染组件的原因是因为它们正在对 API 进行更改,并且这些更改需要反映在屏幕上。 It has nothing to do with any state variables.它与任何 state 变量无关。

Your question is an XY problem.你的问题是一个XY问题。 In the example given it does not make sense that Child1 rerenders cause there is no need for it.在给出的示例中, Child1 重新渲染是没有意义的,因为不需要它。 From the comments your real problem is that you update one API, which is supposed to change the response of another API.从评论中,您真正的问题是您更新了一个 API,这应该会改变另一个 API 的响应。 If you however already know how the response will change, and that it will change, this can be reflected in one state that changes for both API calls:但是,如果您已经知道响应将如何变化,并且它会发生变化,这可以反映在一个 state中,该 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} />
   </>;
  }
     

  

From the comments in the post, it sounds like you have Child1 presenting results of a GET request (being done in Child1 ).从帖子中的评论来看,听起来您有Child1呈现GET请求的结果(在Child1中完成)。 Child2 can add or modify that state on the server with some kind of request and you want to trigger a re-render in order to make Child1 refresh the state. Child2可以通过某种请求在服务器上添加或修改 state,并且您希望触发重新渲染以使Child1刷新 state。

The general problem is, that children should only re-render if props or their used contexts change.普遍的问题是,只有当道具或其使用的上下文发生变化时,孩子才应该重新渲染。 I see two options how to approach this:我看到两个选项如何解决这个问题:

  1. Lift the handling of the requests up into the parent.将请求的处理提升到父级。 Put the results of the request as props into the child component you want to refresh.将请求的结果作为 props 放入要刷新的子组件中。

  2. Make the sibling aware of the request having to reload by setting it to "dirty" in some way.通过以某种方式将其设置为“脏”,使兄弟姐妹知道必须重新加载请求。 Either through context or routing state around through the parent.通过上下文或通过父级路由 state。

Usually it's best to go with option 1 if the components are not too deeply nested.如果组件嵌套不太深,通常最好使用选项 1 go。 It could look like this:它可能看起来像这样:

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

As a nice side-effect, Child1 and Child2 now need a lot less logic and can be styled independently of the fetchPosts and sendNewPost functions.作为一个很好的副作用, Child1Child2现在需要更少的逻辑,并且可以独立于fetchPostssendNewPost函数进行样式设置。

Ciao, lets say that Child1 must be re-rendered on handlePost . Ciao,可以说 Child1 必须在handlePost上重新渲染。 Your parent component will be:您的父组件将是:

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

Then, in your Child1 component:然后,在您的 Child1 组件中:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM