当我将“ react.ement”作为道具时,如何避免运行多次使用效应?
我有一个list
组件可以控制列表的同一逻辑。 我将渲染的React元素作为道具传递给list
组件。
但是,在状态更改时,每次都会运行子女组件的使用效应。
简化的代码如下所示:
saga
export function* fetchPosts(action) {
try {
const res = yield call_api(action.url);
yield put(actions.appendPosts(res.data.posts); // state.posts = state.posts.concat(action.payload.posts)
} finally {
yield put(actions.setLoading(false)); // state.meta.loading = false;
yield put(actions.setFetched(true)); // state.meta.fetched = true;
}
}
posts.jsx
export const Posts = (props) => {
const { meta, posts } = useSelector((state) => state.postState);
const ListItems = () => {
return (
posts.map(d => (
<Post
...
/>
))
)
}
return (
<List
itemsElement={ <ListItems />} // $$typeof: Symbol(react.element)
...
/>
)
}
list.jsx
export const List = (props) => {
return (
<>
...
{ props.itemsElement }
...
</>
);
}
export default List
post.jsx
export const Post = (props) => {
useEffect(() => {
// This code runs every time when the state changed
}, [])
return (
...
);
}
export default Post
以及如果我更改帖子代码像下面一样,使用效率仅运行一次。
posts.jsx
export const Posts = (props) => {
return (
posts.map(d => (
<Post
...
/>
))
)
}
如何避免这种情况?
我正在考虑立即改变状态,
setData: (state, action) => {
state.posts = state.posts.concat(action.payload.posts)
state.meta.loading = action.payload.loading
state.meta.fetched = action.payload.fetched
},
但我认为也许有更好的方法。 如果您可以指出更好的方法,我会很感激。
I have a List
component to control same logic for list.
And I'm passing rendered react element as a props to the List
component.
But, useEffect in child component runs every time when the state changed.
Simplified code is like below:
saga
export function* fetchPosts(action) {
try {
const res = yield call_api(action.url);
yield put(actions.appendPosts(res.data.posts); // state.posts = state.posts.concat(action.payload.posts)
} finally {
yield put(actions.setLoading(false)); // state.meta.loading = false;
yield put(actions.setFetched(true)); // state.meta.fetched = true;
}
}
Posts.jsx
export const Posts = (props) => {
const { meta, posts } = useSelector((state) => state.postState);
const ListItems = () => {
return (
posts.map(d => (
<Post
...
/>
))
)
}
return (
<List
itemsElement={ <ListItems />} // $typeof: Symbol(react.element)
...
/>
)
}
List.jsx
export const List = (props) => {
return (
<>
...
{ props.itemsElement }
...
</>
);
}
export default List
Post.jsx
export const Post = (props) => {
useEffect(() => {
// This code runs every time when the state changed
}, [])
return (
...
);
}
export default Post
And if I change Posts code like below, useEffect runs only once.
Posts.jsx
export const Posts = (props) => {
return (
posts.map(d => (
<Post
...
/>
))
)
}
How can I avoid this?
I'm thinking of changing the state at once like below,
setData: (state, action) => {
state.posts = state.posts.concat(action.payload.posts)
state.meta.loading = action.payload.loading
state.meta.fetched = action.payload.fetched
},
But I think maybe there is a better way.
I'd appreciate it if you could point me to a better way.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我解决了这个问题。
在这种情况下,更新
此功能似乎更好,因为我不必使用
usecallback
。我没有意识到这两个是不同的,但是它们是不同的。
posts.jsx
原始答案
我需要在
usecallback
中包装listItems
函数。posts.jsx
I solved this issue.
Update
This seems better for me in this case because I don't have to use
useCallback
.I didn't realize these two were different, but they are different.
Posts.jsx
Original Answer
I need to wrap
ListItems
function inuseCallback
.Posts.jsx
这是您要遇到的问题:
&lt; listItems/&gt;
react component 每次posts
rece> recre renders。listItems
的孩子&lt; post/&gt;
然后被卸下并重新安装,因此效果始终运行。相反,您应该是“在react中思考” 这将
帖子
作为A prop 而不是在闭合中定义它(又称您的posts
component)。每个
post < / code>仍将重新渲染,但它不是完整的卸载 /重新启动,因此效果不会再运行。如果您想完全防止渲染,可以用
React.memo
。
这是一个简化的示例,不使用萨加斯,但假装 fetch 来生成一些“帖子”数据:
Here is the problem you are running into:
<ListItems />
React Component each time thatPosts
re-renders.ListItems
's children<Post />
then are unmounted and remounted, hence the effect always running.Instead, you should be "thinking in a react" and make a new component that accepts the
posts
as a prop rather than defining it within a closure (aka yourPosts
component).Each
Post
will still re-render, but its not a full unmount / remount, so the effect won't run again. If you'd like to prevent the render altogether, you can memoize the component withReact.memo
.Here's a simplified example that doesn't use sagas but fakes a fetch call to generate some "posts" data: