【问题标题】:Using memoizing selectors with Hooks in React Native在 React Native 中使用带有 Hooks 的记忆选择器
【发布时间】:2020-05-12 13:00:47
【问题描述】:

我的 react 本机应用程序中的一个组件正在重新渲染多次,导致我的派生数据出现问题。 我正在使用 Redux 来存储我的状态并使用 useSelector 挂钩来检索状态并在渲染期间使用它。我已经阅读了很多关于使用 Reselect 库来避免不必要的渲染和优化性能的文章,但我正在努力使用钩子应用到我的 ES6 代码。

这是我当前的代码

import { useSelector, useDispatch } from "react-redux";
import...

const MovieDetailScreen = (props) => {
  const selectedMovie = useSelector((state) => state.moviemain.moviemain);
  const selectedMovieCast = useSelector((state) => state.moviecast.moviecast);
  const selectedMovieCrew = useSelector((state) => state.moviecast.moviecrew);

  return (
   <View style={styles.container}>
     <View>
        <Text style={styles.description} numberOfLines={3}>
           {selectedMovie.name}
        </Text>            
     </View>
     <View>
        <Text style={styles.description} numberOfLines={3}>
           {selectedMovie.overview}
        </Text>            
     </View>
     <View>
        <Text style={styles.description} numberOfLines={3}>
           {selectedMovie.released_date}
        </Text>            
     </View>
     <View style={styles.textLabelRow}>
         {selectedMovie.genres.map((item, id) => {
           return (
              <Text
                 style={[styles.txtLabel, { backgroundColor: "#404040" }]}
                 key={id}
                 numberOfLines={1}
              >
                 {item.name}
              </Text>
           );
         })}
     </View>
   </View>
   ...
   ...
  );
};

我想将 Reselect 应用于任何派生数据,在随附的示例代码中,它将是 selectedMovie 状态的流派参数的映射处理

         {selectedMovie.genres.map((item, id) => {
           return (
              <Text
                 style={[styles.txtLabel, { backgroundColor: "#404040" }]}
                 key={id}
                 numberOfLines={1}
              >
                 {item.name}
              </Text>
           );
         })}

我还有另外几十个类似的场景,我需要过滤数据或计算总数,并且由于重新渲染,我经常会出错。 我相信使用 Reselect,只有在状态发生变化时才会执行该函数。

我尝试按照here 中的示例,将我的状态选择移到我的组件之外并像这样重组我的代码

import...
import { createSelector } from "reselect";

const getMovie = createSelector(
  (state) => state.moviemain.moviemain,
  (moviemain) => moviemain.moviemain.map((item) => item.genres)
);

export const GenresList = () => {
  const genres = useSelector(getMovie);
  return (
    <Text
      style={[styles.txtLabel, { backgroundColor: "#404040" }]}
      numberOfLines={1}
    >
      {genres}
    </Text>
  );
};

const MovieDetailScreen = (props) => {
  const selectedMovie = useSelector((state) => state.moviemain.moviemain);
  const selectedMovieCast = useSelector((state) => state.moviecast.moviecast);
  const selectedMovieCrew = useSelector((state) => state.moviecast.moviecrew);

  return (
   <View style={styles.container}>
     ....
     ....
     <View>
        <GenresList />            
     </View>
   </View>
   ...
   ...
  );
};

但我在 createSelector 函数中遇到以下错误 undefined 不是对象(正在评估 'moviemain.movi​​emain.map')

我尝试了其他建议的解决方案,所有代码都包含在主要组件中,但我遇到了其他类型的错误。

不胜感激。

【问题讨论】:

    标签: react-native react-redux memoization reselect


    【解决方案1】:

    TLDR; 在下面的代码中,第一个参数返回 moviemian.movi​​emain 属性,下一行您想要获取它的 moviemain 属性 - 意思是:moviemian.movi​​emain.movi​​emain 未定义,因此您无法映射它。

    const getMovie = createSelector(
      (state) => state.moviemain.moviemain,
      (moviemain) => moviemain.moviemain.map((item) => item.genres)
    );
    

    记住:你在选择器中写的内容会在第二个参数中得到结果。

    解决方案:移除多余的moviemain:

    (moviemain) => moviemain.map((item) => item.genres)
    

    Redux 选择器可能很棘手,这里有一个复习

    // you can either use multiple selectors
    // declare these outside of component 
    const getSelectedMovie = (state) => state.moviemain.moviemain;
    const getSelectedMovieCast = (state) => state.moviecast.moviecast;
    const getSelectedMovieCrew = (state) => state.moviecast.moviecrew;
    
    // or use one since its the same object
    const getSelectedMovieAll = (state) => state.moviemain;
    
    // so that you can use them inside component like
    
    const MovieDetailScreen = (props) => {
        const selectedMovie = useSelector(getSelectedMovie);
        const movies = useSelector(getSelectedMovieAll);
    
        // pay attention to the keys, they remain the same
        const { moviecast: selectedMovieCast, moviecrew: selectedMovieCrew } = movies;
    
    }
    

    嗯,关于redux部分,关于reselect,你可以这样使用:

    const example = createSelector(
      [selector1, selector2]
      (resultOfSelector1, resultOfSelector2) => ({ 'return': 'something'})
    );
    
    // so in case moviemain.moviemain is an array you can do the following
    // make sure you reuse the previous selectors
    const getMovie = createSelector(
      [getSelectedMovie]
      (moviemain) => moviemain.map((item) => item.genres)
    );
    
    export const GenresList = () => {
      const genres = useSelector(getMovie);
      return (
    

    【讨论】:

    • 感谢您的反馈,您的解决方案的第一部分(Redux)有效,事实上我现在在组件外部声明状态并从组件内部引用 useSelector 并且所有数据都正确刷新!
    • 至于第二部分,我仍然收到错误 In 'moviemain.map(function (item) { return item.genres; })', 'moviemain.map' is undefined) 组件外代码为:const getSelectedMovie = (state) =&gt; state.moviemain.moviemain; const getMovie = createSelector([getSelectedMovie], (moviemain) =&gt; moviemain.map((item) =&gt; item.genres) ); export const GenresList = () =&gt; { const genres = useSelector(getMovie); return ( &lt;Text&gt;{genres}&lt;/Text&gt; ); };
    • 嗯,这取决于您在 state.movi​​emain 中存储的内容。我不确定您的最终目标是什么,如果您有一系列电影,您只想从中提取类型,那么这应该是正确的。控制台.log(state.movi​​emain); console.log(typeof state.movi​​emain);这应该告诉你内容是什么,如果它不是一个数组,这将不起作用
    • 在我使用{selectedMovie.genres.map((item, id) =&gt; { return ( &lt;Text key={id}&gt; {item.name} &lt;/Text&gt; ); })} 的组件内部,它工作正常。如果我使用 createSelector 在组件之外遵循您的解决方案,我会遇到问题。在 state.movi​​emain.movi​​emain 中,第一个moviemain 是reducer 引用,第二个moviemain 是reducer 中保存数据的实际状态属性,希望对您有所帮助。
    • 终于搞定了。我的错,我应该使用 (moviemain) => moviemain.genres.map((item) => item.genres) 而不是 (moviemain) => moviemain.map((item) => item.genres)。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 2022-06-27
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    • 2019-10-15
    • 1970-01-01
    相关资源
    最近更新 更多