【问题标题】:Tracking redux state跟踪 redux 状态
【发布时间】:2021-06-14 16:03:10
【问题描述】:

我在使用 redux 时遇到了问题。我有两个包含对象的数组,最初它们是空的。 其中一个数组包含被用户标记为“收藏”的对象。

const INITIAL_STATE = {
  favorites: [],
  recipes: [],
};

我用于添加项目的减速器:

const reducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case "TOGGLE_FAVORITES":
      if (!state.favorites.includes(action.payload)) {
        return { ...state, favorites: [...state.favorites, action.payload] };
      }
      return {
        ...state,
        favorites: state.favorites.filter(
          (recipe) => recipe.id !== action.payload.id
        ),
      };
    case "REMOVE_FROM_FAVORITES":
      return {
        ...state,
        favorites: state.favorites.filter(
          (recipe) => recipe.id !== action.payload
        ),
      };
    case "GET_RECIPES":
      return {
        ...state,
        recipes: action.payload,
      };
    default:
      return state;
  }
};

如果用户决定添加然后从收藏夹中删除,我为同一个按钮设置了这种“切换”类型。

问题是 当我将项目添加到数组时,它不会立即更新。我的意思是,在第一次“添加”时单击我的 favorites 数组是空的,但是当我添加另一个项目时,它显示里面有一个项目,依此类推。

有没有办法在我添加一些内容以显示当前状态时更新状态?

检查是否喜欢这样:

const [isFavorite, setIsFavorite] = useState(false);
  // Checking if recipe is favorite when rendered
  useEffect(() => {
    const checkIfIsFavorite = (id) => {
      for (let i = 0; favorites.length > 1; i++) {
        if (id === favorites[i].id) {
          return true;
        }
        return false;
      }
    };
    setIsFavorite(checkIfIsFavorite(recipe.id));
  }, [favorites, recipe.id]);

【问题讨论】:

  • 您能分享一下您希望如何使用状态吗?
  • 对不起,我想检查项目是否在数组中以将按钮颜色更改为绿色(最喜欢时)或在不喜欢时将其保留为灰色。将项目添加到数组并显示它是有效的。但我不知道如何让它在渲染按钮颜色时读取状态。
  • 请您向我们展示而不是描述它?
  • 当然,编辑了问题 - 注意,我是新手
  • 嗨,你能分享一下 redux 操作以及你在哪里调用它们吗?谢谢!

标签: javascript reactjs redux


【解决方案1】:

以下内容令人困惑:

const [isFavorite, setIsFavorite] = useState(false);
  // Checking if recipe is favorite when rendered
  useEffect(() => {
    const checkIfIsFavorite = (id) => {
      for (let i = 0; favorites.length > 1; i++) {
        if (id === favorites[i].id) {
          return true;
        }
        return false;
      }
    };
    setIsFavorite(checkIfIsFavorite(recipe.id));
  }, [favorites, recipe.id]);

它没有显示favorites 是什么以及它的定义位置,我在任何地方都看不到分派TOGGLE_FAVORITES 的代码,但可以假设您的reducer 已执行。

如果您有一个收藏夹的 id 数组和一个 id 或一个项目,并且想知道该项目是否是最喜欢的项目,那么您可以计算/推导出这个。派生数据通常在selectors 中计算,而不是在组件中。

下面提供了一个使用选择器获取项目的收藏信息的示例。

const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;

const initialState = {
  favorites: [],
  recipes: [{ id: 1 }, { id: 2 }, { id: 3 }],
};
//action types
const TOGGLE_FAVORITES = 'TOGGLE_FAVORITES';
//action creators
const toggleFavorite = (id) => ({
  type: TOGGLE_FAVORITES,
  payload: id,
});
const reducer = (state, { type, payload }) => {
  if (type === 'TOGGLE_FAVORITES') {
    if (!state.favorites.includes(payload)) {
      return {
        ...state,
        favorites: [...state.favorites, payload],
      };
    }
    return {
      ...state,
      favorites: state.favorites.filter(
        (id) => id !== payload
      ),
    };
  }
  return state;
};
//selectors
const selectRecipes = (state) => state.recipes;
const selectFavorites = (state) => state.favorites;
const createSelectIsFavorite = (id) =>
  createSelector([selectFavorites], (favorites) =>
    favorites.includes(id)
  );
//creating store with redux dev tools
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  initialState,
  composeEnhancers(
    applyMiddleware(
      () => (next) => (action) => next(action)
    )
  )
);
const Recipe = React.memo(function Recipe({ recipe }) {
  const { id } = recipe;
  const selectIsFavorite = React.useMemo(
    () => createSelectIsFavorite(id),
    [id]
  );
  const isFavorite = useSelector(selectIsFavorite);
  const dispatch = useDispatch();
  const toggle = () => dispatch(toggleFavorite(recipe.id));
  return (
    <li>
      {recipe.id} {String(isFavorite)}
      <button onClick={toggle}>toggle favorite</button>
    </li>
  );
});
const App = () => {
  const recipes = useSelector(selectRecipes);
  return (
    <ul>
      {recipes.map((recipe) => (
        <Recipe key={recipe.id} recipe={recipe} />
      ))}
    </ul>
  );
};

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>

<div id="root"></div>

在以后的问题中,我建议您提供已调度的操作以及它们对状态所做的更改(redux devtools 或登录 reducer)。其他至关重要的信息是如何从 redux 状态中选择信息。通过这种方式,您可以查明它“不起作用”的位置,是设置状态不起作用还是获取信息?以这种方式发布相关代码会更容易。

如果你真的卡住了,那么你可以尝试创建一个演示问题的最小项目并分享code sandbox,你甚至可以从github repo创建一个沙箱

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-16
    • 2011-11-14
    • 1970-01-01
    • 2018-06-11
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多