Отслеживание состояния восстановления

#javascript #reactjs #redux

Вопрос:

Я столкнулся с проблемой при использовании 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;
  }
};
 

У меня есть этот тип «переключения» для той же кнопки, если пользователь решит добавить, а затем удалить из избранного.

Проблема в том, что когда я добавляю элемент в массив, он не обновляется сразу. Я имею в виду, что при первом нажатии «добавить» мой массив избранного пуст, но когда я добавляю другой элемент, он показывает, что внутри есть один элемент, и так далее, и так далее.

Есть ли способ обновлять состояние всякий раз, когда я что-то добавляю, чтобы показать мне действительно текущее состояние?

Проверяю, нравится ли фавориту это:

 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]);
 

Комментарии:

1. Можете ли вы поделиться тем, как вы хотите использовать государство?

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

3. Пожалуйста, не могли бы вы показать нам , а не описывать это?

4. Конечно, отредактировал вопрос — примечание, я новичок

5. Привет, можете ли вы поделиться действиями 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 , но мог бы предположить, что ваш редуктор выполнен.

Если у вас есть массив идентификаторов, которые являются избранными, и идентификатор или элемент, и вы хотите знать, является ли элемент избранным, вы можете рассчитать/вывести это. Производные данные обычно вычисляются в селекторах, а не в компоненте.

Пример использования селектора для получения информации о избранном элементе приведен ниже.

 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 или редуктор входа в систему). Другая информация, которая имеет решающее значение, — это то, как вы выбираете информацию из состояния redux. Таким образом, вы можете точно определить, где это «не работает», не работает ли настройка состояния или получение информации? Таким образом, было бы проще разместить соответствующий код.

Если вы действительно застряли, вы можете попробовать создать минимальный проект, демонстрирующий проблему, и поделиться песочницей кода, вы даже можете создать песочницу из репозитория github