mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add example with side effect in render got triggered directly (#38830)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/38830 Changelog: [Internal] - Add example with side effect in render got triggered directly Reviewed By: rshest Differential Revision: D48055836 fbshipit-source-id: 8bf596165741bde93cf44cd96b93fb2efaea1b13
This commit is contained in:
committed by
Facebook GitHub Bot
parent
06d472c05f
commit
970ba05127
+131
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {ItemDataType} from '../components/itemData';
|
||||
|
||||
import * as React from 'react';
|
||||
import {useState, useEffect, useCallback, StrictMode} from 'react';
|
||||
import {Text} from 'react-native';
|
||||
import {generateRandomItems} from '../components/itemData';
|
||||
import ItemList from '../components/ItemList';
|
||||
|
||||
const TIMEOUT = 500;
|
||||
const FETCH_COUNT = 250;
|
||||
const ItemListMemo = React.memo(ItemList);
|
||||
|
||||
function ItemFetcherBadExample(props: {
|
||||
onFetched: (items: ItemDataType[]) => void,
|
||||
count: number,
|
||||
}): React.Node {
|
||||
const {onFetched, count} = props;
|
||||
const fetchMoreItems = async (
|
||||
itemsCount: number,
|
||||
): Promise<ItemDataType[]> => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(generateRandomItems(itemsCount));
|
||||
}, TIMEOUT);
|
||||
});
|
||||
};
|
||||
|
||||
fetchMoreItems(count).then((items: ItemDataType[]) => {
|
||||
onFetched(items);
|
||||
}, console.error);
|
||||
}
|
||||
|
||||
function ItemFetcherGoodExample(props: {
|
||||
onFetched: (items: ItemDataType[]) => void,
|
||||
count: number,
|
||||
}): React.Node {
|
||||
const {onFetched, count} = props;
|
||||
useEffect(() => {
|
||||
const fetchMoreItems = async (
|
||||
itemsCount: number,
|
||||
): Promise<ItemDataType[]> => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(generateRandomItems(itemsCount));
|
||||
}, TIMEOUT);
|
||||
});
|
||||
};
|
||||
|
||||
fetchMoreItems(count).then((items: ItemDataType[]) => {
|
||||
onFetched(items);
|
||||
}, console.error);
|
||||
}, [onFetched, count]);
|
||||
}
|
||||
|
||||
const ItemFetcherBadExampleMemo = React.memo(ItemFetcherBadExample);
|
||||
const ItemFetcherGoodExampleMemo = React.memo(ItemFetcherGoodExample);
|
||||
function EffectInRenderBadExample(): React.Node {
|
||||
const [visibleItems, setVisibleItems] = useState<ItemDataType[]>([]);
|
||||
const [fetchedItems, setFetchedItems] = useState<ItemDataType[]>([]);
|
||||
const onMoreItemFetched = useCallback(
|
||||
(items: ItemDataType[]) => {
|
||||
setFetchedItems(items);
|
||||
},
|
||||
[setFetchedItems],
|
||||
);
|
||||
|
||||
if (fetchedItems.length > 0) {
|
||||
setVisibleItems(visibleItems.concat(fetchedItems));
|
||||
setFetchedItems([]);
|
||||
}
|
||||
|
||||
return (
|
||||
<StrictMode>
|
||||
<Text>{`Items count in list: ${visibleItems.length}`}</Text>
|
||||
<ItemFetcherBadExampleMemo
|
||||
onFetched={onMoreItemFetched}
|
||||
count={FETCH_COUNT}
|
||||
/>
|
||||
<ItemListMemo data={visibleItems} />
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
function EffectInRenderGoodExample(): React.Node {
|
||||
const [visibleItems, setVisibleItems] = useState<ItemDataType[]>([]);
|
||||
const [fetchedItems, setFetchedItems] = useState<ItemDataType[]>([]);
|
||||
const onMoreItemFetched = useCallback(
|
||||
(items: ItemDataType[]) => {
|
||||
setFetchedItems(items);
|
||||
},
|
||||
[setFetchedItems],
|
||||
);
|
||||
|
||||
if (fetchedItems.length > 0) {
|
||||
setVisibleItems(visibleItems.concat(fetchedItems));
|
||||
setFetchedItems([]);
|
||||
}
|
||||
|
||||
return (
|
||||
<StrictMode>
|
||||
<Text>{`Items count in list: ${visibleItems.length}`}</Text>
|
||||
<ItemFetcherGoodExampleMemo
|
||||
onFetched={onMoreItemFetched}
|
||||
count={FETCH_COUNT}
|
||||
/>
|
||||
<ItemListMemo data={visibleItems} />
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
export default {
|
||||
title:
|
||||
'Directly trigger side effect in render may run multiple times and cause error state or re-renders',
|
||||
description:
|
||||
'Trigger a side effect in render method without using effect hook in <StrictMode>. This will force render component two times, and the side effect in bad example caused append items to the list two times unexpectedly.',
|
||||
Bad: EffectInRenderBadExample,
|
||||
Good: EffectInRenderGoodExample,
|
||||
};
|
||||
@@ -14,3 +14,4 @@ export {default as ReRenderWithObjectPropExample} from './ReRenderWithObjectProp
|
||||
export {default as SetStateInWrongEffectExample} from './SetStateInWrongEffectExample';
|
||||
export {default as RenderOffscreenContentExample} from './RenderOffscreenContentExample';
|
||||
export {default as NotMemoizeExpensiveTaskExample} from './NotMemoizeExpensiveTaskExample';
|
||||
export {default as EffectInRenderExample} from './EffectInRenderExample';
|
||||
|
||||
Reference in New Issue
Block a user