简体   繁体   English

反应钩子 state - 不更新组件

[英]React hook state - does not update component

So I'm running an app with the following setup:所以我正在运行一个具有以下设置的应用程序:

  • Hook - provides state and setter to update the state Hook - 提供statesetter来更新 state
  • Component A - only uses the state from the hook and displays data from it组件 A - 仅使用挂钩中的state并显示其中的数据
  • Component B - only uses the setter and updates the state of the hooks state组件 B - 仅使用设置器并更新钩子 state 的 state

However with my current setup Component A does not rerender when the hook state does get a new item in the array, any ideas why this is happening?但是,在我当前的设置中,当钩子 state 确实在数组中获得一个新项目时,组件 A 不会重新呈现,有什么想法为什么会发生这种情况? Im providing some code for clearification:我提供了一些代码进行澄清:

Hook

const initialValue = [];

function getLocalStorageItem() {
  const item = window.localStorage.getItem("queries");
  return item ? JSON.parse(item) : initialValue;
}

function useLocalStorageQueryHistory() {
  const { dispatch } = useAlertContext();

  const [recentQueries, setRecentQueries] = useState(() => {
    try {
      return getLocalStorageItem();
    } catch (error) {
      dispatch(receiveMessageInterceptor(error));
      return initialValue;
    }
  });

  const setValue = (value) => {
    try {
      const recentQueries = getLocalStorageItem();
      if (recentQueries.length >= 6) {
        recentQueries.shift();
      }

      if (!recentQueries.some((query) => query.params === value.params)) {
        window.localStorage.setItem(
          "queries",
          JSON.stringify([...recentQueries, value])
        );
        setRecentQueries([...recentQueries, value]);
      }
    } catch (error) {
      dispatch(receiveMessageInterceptor(error));
    }
  };

  return { recentQueries, setValue };
}

Component A组分 A

function RecentQueriesContainer() {
  const { recentQueries } = useLocalStorageQueryHistory();

  return (
    <Container disableGutters>
        {recentQueries.length ? (
          recentQueries.map((item) => (
            <Card key={`${item.params}`}>
              <CardHeader
                title={item.description}
              />
                  <Typography variant={"body2"}>
                    Mode: {item.params.split("&visualization=")[1]}
                  </Typography>
                  <Typography variant={"body2"}>Unit: {item.unit}</Typography>
            </Card>
          ))
        ) : (
          <Typography
            variant={"subtitle2"}
            color={"secondary"}
            align={"center"}
            mt={2}
          >
            No recent queries available
          </Typography>
        )}
    </Container>
  );
}

Component B B组份

Simply uses the setter in useEffect只需在 useEffect 中使用 setter

useEffect(() => {
    const {
      features,
      description,
      unit,
      amountOfCountries,
    } = geoJsonFromSelectedStatistic;
    if (features) {
      setValue({
        description,
        unit,
        amountOfCountries,
        params: window.location.search,
      });
    }
  }, [geoJsonFromSelectedStatistic]);

I believe that is because you're not creating a context.我相信这是因为您没有创建上下文。 Hooks don't share state by default, they only share state logic .默认情况下,钩子不共享 state,它们只共享 state逻辑

So component A and B are using the same hook, but the state between them is different.所以组件 A 和 B 使用相同的钩子,但是它们之间的 state 是不同的。

Try creating a context and then using that to share the state.尝试创建一个上下文,然后使用它来共享 state。 It should work fine:)它应该可以正常工作:)

const AuthContext = createContext({});

export const AuthProvider = ({ children }) => {
  const [isAuthenticated, setIsAuthenticated] = useState();

  return (
    <AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
      {children}
    </AuthContext.Provider>
  );
};

export function useAuth(){
  const context = useContext(AuthContext);

  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
}

Something like this, where AuthProvider acts like your custom hook, whose values are the values exported by your hook.像这样的东西,其中 AuthProvider 就像您的自定义挂钩,其值是您的挂钩导出的值。 These will be available for any component in which the context is used with useAuth这些将可用于上下文与useAuth一起使用的任何组件

Don't forget to wrap your app with the <AuthProvider />不要忘记使用<AuthProvider />包装您的应用程序

I followed the approach of @thales-kenne and used the react context I already had a UI-context set up and extended it as follows:我遵循@thales-kenne 的方法并使用我已经设置了 UI 上下文的反应上下文并将其扩展如下:

UI-context.js UI-context.js

const initialState = {
  sidebarOpen: false,
  ...
  recentQueries: getLocalStorageItem(),
};

function uiReducer(state = initialState, action) {
  switch (action.type) {
    case SIDEBAR: {
      return {
        ...state,
        sidebarOpen: action.sidebarOpen,
      };
    }
    ...
    case RECENT_QUERIES: {
      return {
        ...state,
        recentQueries: action.recentQueries,
      };
    }
    default:
      return state;
  }
}

UI-actions.js UI-actions.js

export function getLocalStorageItem() {
  const initialValue = [];
  try {
    const item = window.localStorage.getItem("queries");
    return item ? JSON.parse(item) : initialValue;
  } catch (error) {
    console.error(error);
    return initialValue;
  }
}

export const setRecentQueries = (value) => {
  try {
    const recentQueries = getLocalStorageItem();
    if (recentQueries.length >= 5) {
      recentQueries.shift();
    }

    if (!recentQueries.some((query) => query.uri === value.uri)) {
      window.localStorage.setItem(
        "queries",
        JSON.stringify([...recentQueries, value])
      );
      return {
        type: RECENT_QUERIES,
        recentQueries: [...recentQueries, value],
      };
    }
  } catch (error) {
    console.error(error);
  }
};

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

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