Can't access state using 'useStoreState in react easy-peasy - reactjs

I recently decided to learn about state management with easy-peasy, and followed along the basic tutorials, but i can't seem to access the state.
Here is the App component :-
import model from './model';
import Todo from './components/Todo.tsx';
import { StoreProvider, createStore } from 'easy-peasy';
const store = createStore(model);
function App() {
return (
<StoreProvider store={store}>
<div className="App">
<Todo />
</div>
</StoreProvider>
);
}
export default App;
Here is the model file 'model.js'
export default {
todos: [
{
id: 1
},
{
id: 2
},
{
id: 3
}
]
};
And this is the Todo file:-
import React from 'react';
import {useStoreState } from 'easy-peasy';
const Todo = () => {
//The line below does not work for me, when i do 'state.todos' i get an error that todos does not exist on type
const todos = useStoreState(state=>state.todos);
return (
<div>
</div>
);
}
export default Todo;

Try removing the .todos so that
const todos = useStoreState(state=>state.todos);
turns into:
const todos = useStoreState(state=>state);

import React from 'react'
import { useStoreState } from 'easy-peasy';
import Feed from './Feed'
const Home = ({isLoading,fetchError}) => {
const { searchResults} = useStoreState((state)=>state.searchResults)
return (
{isLoading && Loading Posts ...};
{fetchError && <p className='statusMsg' style={{ color: "red" }}>{ fetchError }};
{!isLoading && !fetchError && (searchResults.length ? : No posts to display)}
)
}
export default Home;

Related

RTK Query documentation example throws error

I am pretty much using the documentation example for fetching some data from a json file and I am getting this particular error:
react-dom.development.js:22839 Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
at Object.performAction (<anonymous>:1:31530)
at $ (<anonymous>:1:33343)
at Object.e (<anonymous>:1:37236)
at dispatch (<anonymous>:1:55003)
at buildHooks.ts:768:27
at commitHookEffectListMount (react-dom.development.js:23150:26)
at commitPassiveMountOnFiber (react-dom.development.js:24926:13)
at commitPassiveMountEffects_complete (react-dom.development.js:24891:9)
at commitPassiveMountEffects_begin (react-dom.development.js:24878:7)
at commitPassiveMountEffects (react-dom.development.js:24866:3)
Here is the code:
The create API endpoint:
import { createApi, fetchBaseQuery } from '#reduxjs/toolkit/dist/query/react';
export const widgetConfigApi = createApi( {
reducerPath: 'widgetconfig',
baseQuery: fetchBaseQuery( { baseUrl: '/' } ),
endpoints: ( builder ) => ( {
widgetConfig: builder.query<any[], void>( {
query: () => 'widgetconfig.json',
} ),
} ),
} );
export const { useWidgetConfigQuery } = widgetConfigApi;
The store:
const store = configureStore( {
reducer: {
widgets,
[ widgetConfigApi.reducerPath ]: widgetConfigApi.reducer
},
middleware: ( getDefaultMiddleware ) => getDefaultMiddleware().concat( widgetConfigApi.middleware ),
enhancers: composeEnhancers,
} );
And inside the component I am using the hook:
import { Layout, theme } from 'antd';
import React, { useEffect, useState, lazy } from 'react';
import { v4 } from 'uuid';
import './assets/styles/main.css';
import lineChart from './components/mock/chart-data/lineChart';
import { sideMenuItems } from './components/mock/side-menu/items';
import SideMenu from './components/side-menu/SideMenu';
import { Widget } from '#babilon/babilon-ui-components';
import { useWidgetConfigQuery } from './redux/api/widgetApi';
function App () {
const { Header, Content, Footer } = Layout;
const {
token: { colorBgLayout },
} = theme.useToken();
const [ widgetConfig, setWidgetConfig ] = useState( [] );
const { data, isLoading } = useWidgetConfigQuery();
useEffect( () => {
console.log( data );
!isLoading && setWidgetConfig( data );
}, [] );
return (
<Layout style={ { height: '100vh' } }>
<SideMenu items={ sideMenuItems } />
<Layout style={ { overflow: 'auto', position: 'relative' } }>
<Header style={ { padding: 0, background: colorBgLayout } } />
<Content style={ { margin: '0 16px' } }>
{ widgetConfig.map( ( config: any ) => {
const X = lazy( () => import( config.path ) );
const Y = lazy( () => import( config?.drawer.path ) );
return (
<React.Suspense key={ config.id }>
<Widget styles={ { height: 350 } } className="h-350" { ...structuredClone( config ) } uuid={ v4() }>
<X content series={ lineChart.series } />
</Widget>
</React.Suspense> );
} ) }
</Content>
<Footer style={ { textAlign: 'center' } }>Ant Design ©2018 Created by Ant UED</Footer>
</Layout>
</Layout>
);
}
export default App;
Just for context, I am using vite.
I don't know what am I doing wrong here. I checked the docs like 10 times. The ApiProvider works but it should work with the default provider as well.
Update:
I started a new clean project. In vite+react and in create-react-app version of the project I have the same error.
Here is a condesanbox to try and tinker. Maybe I am setting this poorly.
Sandbox
The problem are the enhancers: composeEnhancers.
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
The configureStore function enables the redux dev tools by itself and it's a bad match with the RTK Query package.
import { configureStore } from "#reduxjs/toolkit";
import { API } from "./api";
export const store = configureStore( {
reducer: {
[ API.reducerPath ]: API.reducer
},
middleware: ( getDefaultMiddleware ) => getDefaultMiddleware().concat( API.middleware ),
} );
store.dispatch;
Here is the sample code of the updated store. The codesandbox is updated as well.

EditorJS is not showing in NextJS even it is loaded through SSR:false

so I am integrating EditorJs with the NextJs app I have done the initialization in the console it shows Editojs is ready but on the screen, it is not visible
can anyone please tell me what I am doing wrong I am sharing my code below
Editor.js
import { createReactEditorJS } from 'react-editor-js'
import { EditorTools } from './EditorTools';
import React, { useEffect } from 'react'
const Editor = () => {
const ReactEditorJS = createReactEditorJS();
return (
<div>
<ReactEditorJS holder="customEditor" tools={EditorTools}>
<div id="customEditor" />
</ReactEditorJS>
</div>
)
}
export default Editor
EditorTools.js
import Header from '#editorjs/header';
export const EditorTools = {
header: {
class: Header,
config: {
placeholder: 'Let`s write an awesome story! ✨',
},
},
};
Create.js
import React from 'react'
import dynamic from 'next/dynamic';
const EditorJSNoSSRWrapper = dynamic(import('../../../components/Editor/Editor'), {
ssr: false,
loading: () => <p>Loading ...</p>,
});
const create = () => {
return (
<div>
<EditorJSNoSSRWrapper />
</div>
)
}
export default create

Map an array in an object Typescript/React

I'm new on typescript and React. The project idea is to catch some information from a JSon file I created (back) and to display them on cards (front).
I try to pass props from the cards?.items.map only I don't know what is the right one to get the information from cards.items (cards.items is declared in the file cards.decl.ts)
cards.decl.ts :
export type ICards = {
title: string;
items: ICardItems;
urlSuffixe: string;
};
export type ICardItem = {
id: number;
img: string;
gender: string;
name: string;
};
export type ICardItems = ICardItem[];
Home.tsx :
import React, { useState, useEffect } from "react";
import axios from "axios";
import Cards from "../Cards/Cards";
import { ICardItems, ICards } from "../../decl";
import { getCards } from "../../api";
import "./Home.css";
interface AppState {
cards: ICards | undefined;
}
const Home = () => {
const [appCards, setAppCards] = useState<AppState>();
const fetchCards = async () => {
const cardsPages = await getCards();
setAppCards({ cards: cardsPages });
};
console.log(appCards);
useEffect(() => {
fetchCards();
}, []);
return (
<div className="home">
<Cards cards={appCards} />
</div>
);
};
export default Home;
Cards.tsx
import React, { FC, useState } from "react";
import ListCard from "../ListCard/ListCard";
import { getCards } from "../../api/index";
import { ICardItems, ICards } from "../../decl";
import "./Cards.css";
export interface CardsProps {
cards: ICards | undefined;
}
const Cards = ({ cards }: CardsProps) => {
return (
<section className="section cards">
<div className="cards__wrap container">
<div className="section__title">
<h1>{cards?.title}</h1>
</div>
{cards?.items.map((card: ICardItem) => {
<ListCard
key={card.id}
id={card.id}
img={card.img}
gender={card.gender}
name={card.name}
/>;
})}
</div>
</section>
);
};
export default Cards;
ListCard.tsx
import React, { FC, useState } from "react";
import { useGlobalContext } from "../../context";
import { ICardItems, ICards } from "../../decl";
import "./ListCard.css";
export interface CardsProps {
cards: ICards | undefined;
}
const ListCard: React.FC<CardsProps> = () => {
I'm not super clear on what you're asking here, but I do see a problem with your map function - it doesn't return anything!
Change
{cards?.items.map((card: ICardItem) => {
<ListCard
key={card.id}
id={card.id}
img={card.img}
gender={card.gender}
name={card.name}
/>;
})}
to
{cards?.items.map((card: ICardItem) => {
return <ListCard
key={card.id}
id={card.id}
img={card.img}
gender={card.gender}
name={card.name}
/>;
})}
You might have been confused by arrow function syntax, which would look like
{cards?.items.map((card: ICardItem) => <ListCard key={card.id} id={card.id} img={card.img} gender={card.gender} name={card.name}/>)}

React - useContext is returning undefined

I trying to use React context to manage state in my project, but I cannot seem to figure out why it's returning undefined. I copied the example from another project I was working on, and it seems as if everything should be working properly. I just can't seem to pin down why it is not.
Here is where I am creating the context.
import React, { useState } from "react";
const initialTodos = [
{
id: 1,
title: "Setup development environment",
completed: true,
},
{
id: 2,
title: "Develop website and add content",
completed: false,
},
{
id: 3,
title: "Deploy to live server",
completed: false,
},
];
export const TodoContext = React.createContext({
todos: initialTodos,
onChange: () => {},
});
const TodoContextProvider = (props) => {
const [todos, setTodos] = useState(initialTodos);
const handleChange = () => {
console.log("clicked");
};
return (
<TodoContext.Provider value={{ todos: todos, onChange: handleChange }}>
{props.children}
</TodoContext.Provider>
);
};
export default TodoContextProvider;
Here is where I am wrapping the app.
import React from "react";
import ReactDOM from "react-dom";
import TodoContainer from "./components/TodoContainer";
import TodoContextProvider from "./context/TodoContext";
ReactDOM.render(
<TodoContextProvider>
<TodoContainer />
</TodoContextProvider>,
document.getElementById("root")
);
Here is my TodoContainer.
import React, { useContext } from "react";
import TodosList from "./TodosList";
import Header from "./Header";
import TodoContext from "../context/TodoContext";
const TodoContainer = (props) => {
const todoContext = useContext(TodoContext);
console.log("todoContext", todoContext);
return (
<div>
<Header />
<TodosList />
</div>
);
};
export default TodoContainer;
And here is where I am attempting to use the context.
import React, { useContext } from "react";
import TodoItem from "./TodoItem";
import TodoContext from "../context/TodoContext";
const TodosList = (props) => {
const todoContext = useContext(TodoContext);
console.log(todoContext);
return (
<div>
{todoContext.todos.map((todo) => (
<TodoItem key={todo.id} todo={todo.title} />
))}
</div>
);
};
export default TodosList;
Finally, here is the error I receive.
TypeError: Cannot read property 'todos' of undefined
TodosList
C:/Users/Stacey/repos/simple-todo-app/src/components/TodosList.js:11
8 | console.log(todoContext);
9 |
10 | return (
> 11 | <div>
| ^ 12 | {todoContext.todos.map((todo) => (
13 | <TodoItem key={todo.id} todo={todo.title} />
14 | ))}
You are importing the TodoContext as a default import but it must be a named import.
change in the TodosList.js:
import TodoContext from "../context/TodoContext";
to:
import { TodoContext } from "../context/TodoContext";
and it will work

Implementing React Redux

I am slowly learning React and also learning to implement it with Redux. But I seem to have hit a road block. So this is what I have so far.
/index.jsx
import './main.css'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App.jsx'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import ShoppingList from './reducers/reducer'
let store = createStore(ShoppingList)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app')
)
/actions/items.js
import uuid from 'node-uuid'
export const CREATE_ITEM = 'CREATE_ITEM'
export function createItem(item) {
return {
type: CREATE_ITEM,
item: {
id: uuid.v4(),
item,
checked: false
}
}
}
/reducers/reducer.js
import * as types from '../actions/items'
import uuid from 'node-uuid'
const initialState = []
const items = (state = initialState, action) => {
switch (action.type) {
case types.CREATE_ITEM:
return {
id: uuid.v4(),
...item
}
default:
return state;
}
}
export default items
/reducers/index.js
UPDATE:
import { combineReducers } from 'redux'
import items from './reducer'
const ShoppingList = combineReducers({
items
})
export default ShoppingList
/components/Item.jsx
import React from 'react';
import uuid from 'node-uuid'
export default class Item extends React.Component {
constructor(props) {
super(props);
this.state = {
isEditing: false
}
}
render() {
if(this.state.isEditing) {
return this.renderEdit();
}
return this.renderItem();
}
renderEdit = () => {
return (
<input type="text"
ref={(event) =>
(event ? event.selectionStart = this.props.text.length : null)
}
autoFocus={true}
defaultValue={this.props.text}
onBlur={this.finishEdit}
onKeyPress={this.checkEnter}
/>
)
};
renderDelete = () => {
return <button onClick={this.props.onDelete}>x</button>;
};
renderItem = () => {
const onDelete = this.props.onDelete;
return (
<div onClick={this.edit}>
<span>{this.props.text}</span>
{onDelete ? this.renderDelete() : null }
</div>
);
};
edit = () => {
this.setState({
isEditing: true
});
};
checkEnter = (e) => {
if(e.key === 'Enter') {
this.finishEdit(e);
}
};
finishEdit = (e) => {
const value = e.target.value;
if(this.props.onEdit) {
this.props.onEdit(value);
this.setState({
isEditing: false
});
}
};
}
/components/Items.jsx
import React from 'react';
import Item from './Item.jsx';
export default ({items, onEdit, onDelete}) => {
return (
<ul>{items.map(item =>
<li key={item.id}>
<Item
text={item.text}
onEdit={onEdit.bind(null, item.id)}
onDelete={onDelete.bind(null, item.id)}
/>
</li>
)}</ul>
);
}
// UPDATE: http://redux.js.org/docs/basics/UsageWithReact.html
// Is this necessary?
const mapStateToProps = (state) => {
return {
state
}
}
Items = connect(
mapStateToPros
)(Items) // `SyntaxError app/components/Items.jsx: "Items" is read-only`
//////////////////////////////////////
// Also tried it this way.
//////////////////////////////////////
Items = connect()(Items)
export default Items // same error as above.
Tried this as well
export default connect(
state => ({
items: store.items
})
)(Items) // `Uncaught TypeError: Cannot read property 'items' of undefined`
UPDATE:
After many attempts #hedgerh in Gitter pointed out that it should be state.items instead. so the solution was
export default connect(
state => ({
items: state.items
})
)(Items)
credits to #azium as well.
/components/App.jsx
export default class App extends React.Component {
render() {
return (
<div>
<button onClick={this.addItem}>+</button>
<Items />
</div>
);
}
}
What am I missing here in order to implement it correctly? Right now it breaks saying that Uncaught TypeError: Cannot read property 'map' of undefined in Items.jsx. I guess it makes sense since it doesn't seem to be hooked up correctly. This is the first part of the app, where the second will allow an user to create a many lists, and these lists having many items. I will probably have to extract the methods from Item.jsx since the List.jsx will do pretty much the same thing. Thanks
You're missing connect. That's how stuff gets from your store to your components. Read the containers section from the docs http://redux.js.org/docs/basics/UsageWithReact.html
import React from 'react'
import Item from './Item.jsx'
import { connect } from 'react-redux'
let Items = ({items, onEdit, onDelete}) => {
return (
<ul>{items.map(item =>
<li key={item.id}>
<Item
text={item.text}
onEdit={onEdit.bind(null, item.id)}
onDelete={onDelete.bind(null, item.id)}
/>
</li>
})
</ul>
)
}
export default connect(
state => ({
items: state.items
})
)(Items)
Also you seem to be expecting onEdit and onDelete functions passed from a parent but you're not doing that so those functions will be undefined.

Resources