Как обновить множественное состояние, используя useState? - PullRequest
1 голос
/ 04 мая 2020

Я использую TabView из React-Native и как часть этого я использую два состояния для двух разных объектов, как показано ниже.

const [routes, setRoutes] = React.useState([]);
const [sceneMap, setSceneMap] = React.useState({});

Я вызываю функцию внутри хука useEffect всякий раз, когда TabView получает фокус. Также внутри этого хука я изменяю / переназначаю оба состояния с новыми значениями, как показано ниже

React.useEffect(() => {
        // Return the function to unsubscribe from the event so it gets removed on unmount
        return navigation.addListener('focus', async () => {
            const dynamicTabsResponse = await getTabsDynamically();
            let response;
            if (dynamicTabsResponse != null) {
                response = await getRoutes(dynamicTabsResponse);
                **setRoutes(response);**

                const scenes = await getScenes(dynamicTabsResponse)
                newSceneMap = await getSceneMap(response, scenes)

                **setSceneMap({...newSceneMap});**
            }
        });
    }, []);

Это моя функция возврата:

if (routes.length > 0 && Object.keys(newSceneMap).length > 0) {
        return (
            <TabView
                navigationState={{index, routes}}
                renderScene={SceneMap(sceneMap)}
                onIndexChange={setIndex}
                initialLayout={initialLayout}
            />
        );
    } else {
      console.log( Object.keys(newSceneMap))
        console.log("routes length", routes.length)
        return null
    }

Проблема в том, как только первое состояние обновляется, происходит повторная визуализация пользовательского интерфейса, которая вызывает ошибку, поскольку моему пользовательскому интерфейсу также требуется обновленное состояние второго. Как я могу сообщить React-Native, чтобы он не рендерился, пока оба состояния не получат обновление? Есть ли способ сделать это или я неправильно внедряю? Пожалуйста, предложите

Просто, чтобы объяснить больше, рассмотрите вывод ниже:

Когда я перезапускаю приложение, значения Routes и Array будут такими, как показано ниже:

1. routes length inside if 2

2. inside if Array [
  "NEWS",
  "CRIME",
]

Когда go другой экран и установите флажок и перейдите на вкладку. Вывод будет следующим:

1. routes length inside if 3

2. inside if Array [
  "NEWS",
  "CRIME",
]

Как видно из 2-го выхода, состояние маршрутов было обновлено до 3 (что вызывая повторную визуализацию), но не состояние массива. Из-за чего TabView отображает / выдает ошибку

Ошибка:

Check the render method of `SceneComponent`., 
    in SceneComponent (created by SceneView)
    in RCTView (created by SceneView)
    in SceneView (created by Pager)
    in RCTView (at createAnimatedComponent.js:233)
    in AnimatedComponent(Component) (created by PanGestureHandler)
    in PanGestureHandler (created by Pager)
    in Pager (created by TabView)
    in RCTView (created by TabView)
    in TabView (at NewsScreen.js:73)
    in NewsScreen (at SceneView.tsx:98)
    in StaticContainer
    in StaticContainer (at SceneView.tsx:89)
    in EnsureSingleNavigator (at SceneView.tsx:88)
    in SceneView (at useDescriptors.tsx:125)
    in RCTView (at BottomTabView.tsx:38)
    in SceneContent (at BottomTabView.tsx:122)
    in RCTView (at ResourceSavingScene.tsx:44)
    in RCTView (at ResourceSavingScene.tsx:27)
    in ResourceSavingScene (at BottomTabView.tsx:117)
    in RCTView (at screens.native.js:132)
    in ScreenContainer (at BottomTabView.tsx:101)
    in RCTView (at BottomTabView.tsx:100)
    in SafeAreaProviderCompat (at BottomTabView.tsx:99)
    in BottomTabView (at createBottomTabNavigator.tsx:41)
    in BottomTabNavigator (at BottomTabNavigator.js:22)
    in BottomTabNavigator (at SceneView.tsx:98)
    in StaticContainer
    in StaticContainer (at SceneView.tsx:89)
    in EnsureSingleNavigator (at SceneView.tsx:88)
    in SceneView (at useDescriptors.tsx:125)
    in RCTView (at CardContainer.tsx:190)
    in RCTView (at CardContainer.tsx:189)
    in RCTView (at Card.tsx:526)
    in RCTView (at createAnimatedComponent.js:151)
    in AnimatedComponent (at Card.tsx:508)
    in PanGestureHandler (at Card.tsx:501)
    in RCTView (at createAnimatedComponent.js:151)
    in AnimatedComponent (at Card.tsx:497)

Ответы [ 2 ]

1 голос
/ 04 мая 2020
const Hello = () => {
 let response = [{one:"two"}]
 let newSceneMap = {
    name:"sdfvsdf"
 }
 const [routesAndsceneMap, setIt] = React.useState({
 routes:[{one:"three"}],
 sceneMap:{
   name:"sdfvds"
 }
});
const changeit = () => {
        setIt({...routesAndsceneMap,routes:[...response],sceneMap:  {...newSceneMap}})
 }
return (
<div>
  <h1>Hello {routesAndsceneMap.routes[0].one} {routesAndsceneMap.sceneMap.name}!</h1>
  <button onClick={changeit}>Click</button>
</div>
)};

Вы можете проверить здесь, как это работает. Для работы смотрите эту ссылку https://stackblitz.com/edit/react-p7jrjv?file=Hello.js

Вы добавили два разных useState, вместо этого попробуйте объединить его в один, как я сделал и измените его вместе всего лишь одной установленной функцией при нажатии кнопки, чтобы изменить два свойства вместе

0 голосов
/ 04 мая 2020

«Как я могу сообщить React-Native, что не нужно выполнять повторную визуализацию, пока оба состояния не получат обновление?»

Вы не можете остановить повторную визуализацию после изменения состояния. Но то, что вы можете сделать, это не обновлять состояние, пока вы не будете готовы к визуализации.

Если вы перемещаете два обновления состояния вместе, чтобы они обновлялись одновременно и между ними не было асинхронных c выборок, все должно работать так, как вы ожидаете.

        if (dynamicTabsResponse != null) {
            response = await getRoutes(dynamicTabsResponse);

            const scenes = await getScenes(dynamicTabsResponse)
            newSceneMap = await getSceneMap(response, scenes)

            // Update both states together, after all awaits are done.
            setRoutes(response);
            setSceneMap({...newSceneMap});
        }
...