Hi everyone, Im doing this project and I am stuck on task 9:
Task 9 is saying:
Next, you’ll need to hook the new topic form up to the action creators your slice generates. In src/components/NewTopicForm.js , import
addTopic
and dispatch it from the event handler that runs when the new topic form is submitted.Verify that your code is working by filling out the form and submitting it. You should be redirected to the
/topics
page and should see your newly created topic there.
I should be able to see the topic I have written after this stage but Instead I am getting this error:
× TypeError: Cannot read property ‘topics’ of undefined
on this line
> 27 | export const selectTopics = (state) => state.topics.topics;
Here is my code where am I going wrong?
topicsSlice.js
import { createSlice } from '@reduxjs/toolkit';
export const topicsSlice = createSlice({
name: 'topics',
initialState: {
topics: {}
},
reducers: {
addTopic: (state, action) => {
const { id, name, icon } = action.payload;
state.topics[id] = {
id: id,
name: name,
icon: icon,
quizIds: []
}
},
}
})
// console.log(topicsSlice);
export const {addTopic} = topicsSlice.actions
export const selectTopics = (state) => state.topics.topics;
// console.log(selectTopics)
export default topicsSlice.reducer;
Topics.js
import React from "react";
import NewTopicForm from "../../components/NewTopicForm";
import { Link } from "react-router-dom";
import ROUTES from "../../app/routes";
import { useSelector } from 'react-redux';
import { selectTopics } from './topicsSlice.js'
export default function Topics() {
const topics = useSelector(selectTopics); // replace this with a call to your selector to select all the topics in state
return (
<section className="center">
<h1>Topics</h1>
<ul className="topics-list">
{Object.values(topics).map((topic) => (
<li className="topic" key={topic.id}>
<Link to={ROUTES.topicRoute(topic.id)} className="topic-link">
<div className="topic-container">
<img src={topic.icon} alt="" />
<div className="text-content">
<h2>{topic.name}</h2>
<p>{topic.quizIds.length} Quizzes</p>
</div>
</div>
</Link>
</li>
))}
</ul>
<Link
to={ROUTES.newTopicRoute()}
className="button create-new-topic-button"
>
Create New Topic
</Link>
</section>
);
}
NewTopicForm.js
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import { v4 as uuidv4 } from "uuid";
import ROUTES from "../app/routes";
import { ALL_ICONS } from "../data/icons";
import { useDispatch } from 'react-redux';
import { addTopic } from '../features/topics/topicsSlice.js'
export default function NewTopicForm() {
const dispatch = useDispatch();
const [name, setName] = useState("");
const [icon, setIcon] = useState("");
const history = useHistory();
const handleSubmit = (e) => {
e.preventDefault();
if (name.length === 0) {
return;
}
// dispatch your add topic action here
// dispatch(addTopic({id: uuidv4(), name: name, icon: icon}));
dispatch(addTopic({ id: uuidv4(), name: name, icon: icon }));
history.push(ROUTES.topicsRoute());
};
return (
<section>
<form onSubmit={handleSubmit}>
<h1 className="center">Create a new topic</h1>
<div className="form-section">
<input
id="topic-name"
type="text"
value={name}
onChange={(e) => setName(e.currentTarget.value)}
placeholder="Topic Name"
/>
<select
onChange={(e) => setIcon(e.currentTarget.value)}
required
defaultValue="default"
>
<option value="default" disabled hidden>
Choose an icon
</option>
{ALL_ICONS.map(({ name, url }) => (
<option key={url} value={url}>
{name}
</option>
))}
</select>
</div>
<button className="center">Add Topic</button>
</form>
</section>
);
}
store.js
import { configureStore } from "@reduxjs/toolkit";
import topicsReducer from '../features/topics/topicsSlice'
// console.log(topicsReducer)
export default configureStore({
reducer: {
topicsSlice: topicsReducer,
},
});