Matching Memory

hello everyone, I cannot figure out what is wrong with my code. I have backtracked my steps and found that somewhere around step 9-10 my code does not show any output. There were no error codes so I went on to finish the rest of the project. I think I have some sort of syntax error but nothing is showing up.

1 Like

Hello,
Doing a quick scan of your gist I notice that you have

import { useSelector,useDispach } from ‘react-redux’

which has a syntax error it should be useDispatch

I have also just completed step 10 and created a Gist if you want to compare to see what is different as well

Did this actually solve the problem for you? I am also at step 10 and nothing is rendering. I compared with the code above and found one mistake, which I corrected, but still nothing.

1 Like

Hi, I’ve been able to complete the project up to line 21. But when I add the line of code

const cardsMatched = useSelector(selectMatchedIDs())

to Score.js, the app crashes with an “Uncaught TypeError: state is undefined” error. Any clues on what might be going on?

Your useSelector call looks weird to me because you’re passing it a function invocation.
The common usage of useSelector would be to import a state, in your case ‘selectMatchedIDs’ – which wouldn’t be a function – like
import { selectMatchedIDs } from '{yourSlice}';
This state would need to be exported from your slice.
Then you’d just pass that state to useSelector();

Yeah, I figured it out a second ago. Thanks! (I was confusing action creators with selectors)

I’m having the same problem on step 10… I made it all the way through step 9 with no problems but upon completing step 10 nothing is rendering. Since two other people reported this issue and were apparently unable to resolve it I’m thinking this is… yet another bug… in… yet another important project… Frustrating.

Anyone else having this problem?

1 Like

Can you share your code? You can copy-paste your files here OR you can include a link to github. Perhaps, it may help figure out if there is a mistake in the code OR if the problem lies at Codecademy’s end.

To preserve code formatting in forum posts, see: [How to] Format code in posts

import {createSlice} from ‘@reduxjs/toolkit’;

export const CATEGORIES = [‘housing’, ‘food’, ‘transportation’, ‘utilities’, ‘clothing’, ‘healthcare’, ‘personal’, ‘education’, ‘entertainment’];
const initialState = CATEGORIES.map(category => ({ category: category, amount: 0 }))

const budgetsSlice = createSlice({
name: ‘budgets’,
initialState: initialState,
reducers: {
editBudget: (state, action) => {
const category = action.payload.category;
const amount = action.payload.amount;
state.find(budget => budget.category === category).amount = amount
}
},
});

const budgetsReducer = (state = initialState, action) => {
switch (action.type) {
case ‘budgets/editBudget’:
const newBudgets = state.map(budget => {
if (budget.category === action.payload.category) {
return action.payload;
}
return budget;
})
return newBudgets;
default:
return state;
}
}

export const { editBudget } = budgetsSlice.actions;
export const selectBudgets = (state) => state.budgets;

export default budgetsSlice.reducer;

import { createSlice } from ‘@reduxjs/toolkit’;

export const CATEGORIES = [‘housing’, ‘food’, ‘transportation’, ‘utilities’, ‘clothing’, ‘healthcare’, ‘personal’, ‘education’, ‘entertainment’];
const initialState = Object.fromEntries(CATEGORIES.map(category => [category, ]))

const transactionsSlice = createSlice({
name: ‘transactions’,
initialState: initialState,
reducers: {
addTransaction: (state, action) => {
const category = action.payload.category;
state[category].push(action.payload);
},
deleteTransaction: (state, action) => {
const id = action.payload.id;
const category = action.payload.category;
state[category] = state[category].filter(transaction => transaction.id !== id)
}
},
});

export const selectTransactions = (state) => state.transactions;
export const selectFlattenedTransactions = (state) => Object.values(state.transactions).reduce((a,b) => […a, …b], );

const transactionsReducer = (state = initialState, action) => {
let newTransactionsForCategory;
switch (action.type) {
case ‘transactions/addTransaction’:
newTransactionsForCategory = […state[action.payload.category].slice(), action.payload]
return { …state, [action.payload.category]: newTransactionsForCategory}
case ‘transactions/deleteTransaction’:
const deletedIndex = state[action.payload.category].findIndex(transaction => transaction.id === action.payload.id);
newTransactionsForCategory = state[action.payload.category].filter((item, index) => index !== deletedIndex)
return { …state, [action.payload.category]: newTransactionsForCategory}
default:
return state;
}
}

export { addTransaction, deleteTransaction } = transactionsSlice.action;

export default transactionsSlice.reducer;

import React from ‘react’;
import ReactDOM from ‘react-dom’;
import App from ‘./App’;

import { store } from ‘./app/store.js’;
// Add import statement below
import { Provider } from ‘react-redux’;

ReactDOM.render(
// Implement Provider component with store below


,
document.getElementById(‘root’)
);

const initialState = [
{id: 0, contents: ‘Provider’, visible: true, matched: true},
{id: 1, contents: ‘Provider’, visible: true, matched: true},
{id: 2, contents: ‘selector’, visible: true, matched: true},
{id: 3, contents: ‘selector’, visible: true, matched: true},
{id: 4, contents: ‘useSelector()’, visible: true, matched: true},
{id: 5, contents: ‘useSelector()’, visible: true, matched: true},
{id: 6, contents: ‘useDispatch()’, visible: true, matched: true},
{id: 7, contents: ‘useDispatch()’, visible: true, matched: true},
{id: 8, contents: ‘Pure Function’, visible: true, matched: true},
{id: 9, contents: ‘Pure Function’, visible: true, matched: true},
{id: 10, contents: ‘react-redux’, visible: true, matched: true},
{id: 11, contents: ‘react-redux’, visible: true, matched: true},
];

export const boardReducer = (state = initialState, action) => {
switch (action.type) {
case ‘board/setBoard’:
let setState = ;
action.payload.forEach((element, index) =>
setState.push({id: index,
contents: element,
visible: false,
matched: false})
);
return setState;
case ‘board/flipCard’:
let flipState = […state];
const cardID = action.payload;
flipState[cardID] = {…state[cardID], visible:true}

const [index1, index2] = flipState
.filter(card => card.visible)
.map(card => card.id);
if (index2 !== undefined){
const card1 = flipState[index1];
const card2 = flipState[index2];
if (card1.contents === card2.contents) {
flipState[index1] = {…card1, visible: false, matched: true}
flipState[index2] = {…card2, visible: false, matched: true}
}
}

return flipState;
case ‘board/resetCards’:
return state.map(card => ({…card, visible: false}));
default:
return state;
}
}

const wordPairs = [
‘Provider’, ‘Provider’,
‘selector’, ‘selector’,
‘useSelector()’, ‘useSelector()’,
‘useDispatch()’, ‘useDispatch()’,
‘Pure Function’, ‘Pure Function’,
‘react-redux’, ‘react-redux’,
]

const randomWords = () => {
let words =
let newWordPairs = […wordPairs]
const reps = newWordPairs.length
for (let i=0; i<reps; i++) {
const wordIndex = Math.floor(Math.random()*newWordPairs.length);
words.push(newWordPairs[wordIndex])
newWordPairs.splice(wordIndex, 1)
}

return words;
}

// action creators
export const setBoard = () => {
const words = randomWords()
return {
type: ‘board/setBoard’,
payload: words
}
}

export const flipCard = (id) => {
return {
type: ‘board/flipCard’,
payload: id
}
}

export const resetCards = (indices) => {
return {
type: ‘board/resetCards’
}
}

// Add selector export statments below
export const selectBoard = state => state.board.map(card => ({id:card, contents:card.contents}));

export const selectVisibleIDs = state =>
state.board
.filter(card => card.visible )
.map(card => card.id);

export const selectMatchedIDs = state =>
state.board
.filter(card => card.matched)
.map(card => card.id);

import React from ‘react’;
import { CardRow } from ‘./cardRow/CardRow.js’;
// Add import statements below
import { useSelector } from ‘react-redux’;
import { selectBoard } from ‘./boardSlice.js’;

export const Board = () => {
// Add selected data variable and implement below
const currentBoard = useSelector(selectBoard);

const numberOfCards = currentBoard.length;
const columns = 3;
const rows = Math.floor(numberOfCards / columns);

const getRowCards = (row) => {
const rowCards = ;
for (let j = 0; j < columns; j++) {
const cardIndex = row * columns + j;
// Implement selected data below
rowCards.push(currentBoard[cardIndex]);
}
return rowCards;
};

let content = ;
for (let row = 0; row < rows; row++) {
const rowCards = getRowCards(row);
content.push(

);
}
return

{content}
;
};

import React from ‘react’;
// Add import statements below
import { useSelector, useDispatch } from ‘react-redux’;
import { selectVisibleIDs, flipCard, selectMatchedIDs } from ‘…/…/boardSlice.js’;

let cardLogo = “https://static-assets.codecademy.com/Courses/Learn-Redux/matching-game/codecademy_logo.png”;

export const Card = ({ id, contents }) => {
// Add selected data and dispatch variables below
visibleIDs = useSelector(selectVisibleIDs);
dispatch = useDispatch();
matchedIDs = useSelector(selectMatchedIDs);
// flip card action
const flipHandler = (id) => {
// Add action dispatch below
dispatch(flipCard(id))
};

let cardStyle = ‘resting’
let click = () => flipHandler(id);

let cardText = (
Card option
);

import ‘./App.css’;
import React from ‘react’;
import { Score } from ‘./features/score/Score.js’;
import { Board } from ‘./features/board/Board.js’;
// Add import statements below
import { useDispatch } from ‘react-redux’;
import { setBoard, resetCards } from ‘./features/board/boardSlice.js’;

const App = () => {
// Add dispatch variable below
const dispatch = useDispatch();

const startGameHandler = () => {
// Add action dispatch below
dispatch(setBoard())
};

const tryAgainHandler = () => {
// Add action dispatch below
dispatch(resetCards())
};

return (

Start Game Try New Pair
); };

export default App;

import React from ‘react’;
// Add import statement below
import { useSelector } from ‘react-redux’;
import { selectMatchedIDs } from ‘…/board/boardSlice.js’;

export const Score = () => {
// Add selected data variable below
const cardsMatched = useSelector(selectMatchedIDs);

return (
// implement selected data inside

Matched: {cardsMatched.length}
); };

Unfortunately, you didn’t format the code properly ([How to] Format code in posts), so it is difficult to try and follow the code.

One thing that may be of interest:

// You wrote:
export const selectBoard = state => state.board.map(
card => ({id:card, contents:card.contents}));

// Consider changing it to:
export const selectBoard = state => state.board.map(
card => ({id: card.id, contents: card.contents}));

I’ve made the suggested change but the end result is the same…

Can you copy/paste the instructions for Step 10?

Also, what code did you write just for Step 10 specifically?

By default each Card component displays the Codecademy logo which means its contents are not visible. With the visible card IDs now known by each Card component, each card can show its contents if it is one of the visible cards or remain hidden otherwise. This logic is handled by the first if statement in the Card component definition.

Inside the Card component definition:

  1. Remove the false in the first if statement. Instead, check that the Card component’s id prop is included in visibleIDs array.
    You should now see all the cards in their initialized order.

// 1st if statement
// implement card id array membership check
if (visibleIDs.includes(id) || matchedIDs.includes(id)) {
cardText = contents;
click = () => {};
}

But, this if statement is not present in the code posted by you in the earlier posts.

What is your complete code in the Card.js file?