I am new to react and redux and trying to dispatch states from store but unable to do so,
Please anyone help me to resolve the problem...
App.js
import React from "react";
import store from './reduxStore/store';
import { Provider } from 'react-redux';
import Sidebar from './Sidebar';
function App() {
return (
<div>
<Provider store={store}>
<Sidebar ></Sidebar>
</Provider>
</div>
);
}
export default (App);
This is my sidebar.js Component
import React, { useEffect } from 'react';
import { updatePageLinkActions } from "../../reduxStore/actions/updatePageLinkActions";
import { connect } from "react-redux";
const Sidebar = () =>{
useEffect(() => {
return updatePageLinkActions
}, [])
return (
<>
<ListItem button onClick={updatePageLinkActions}>
<ListItemIcon><Home></Home></ListItemIcon>
<ListItemText primary="Dashboard" />
</ListItem>
<ListItem button onClick={() => handleOpenPage("contact")}>
<ListItemIcon><AcUnit></AcUnit></ListItemIcon>
<ListItemText primary="Contact" />
</ListItem>
</>
)
}
const mapStateToProps = (state) => ({
updatePage: state.updatePage.pgLink
})
export default connect(mapStateToProps, { updatePageLinkActions })(SidebarItems);
Store Store.js
import { createStore, applyMiddleware, compose } from "redux";
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = {};
const middleWare = [thunk]
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleWare),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
)
)
export default store;
Root Reducer rootReducer.js
import { combineReducers } from 'redux';
import updatePageLinkReducer from './updatePageLinRreducer';
export default combineReducers({
updatePage: updatePageLinkReducer
});
Action updatePageLinkActions.js
import { UPDATE_PAGE_LINK } from "../actionTypes";
//import store from "../store";
export const updatePageLinkActions = dispatch => {
console.log("actions log ", dispatch.payload)
return dispatch({
type: UPDATE_PAGE_LINK,
payload: {pageLink : "Action_pageLink" }
})
};
Reducer updatePageLinkReducer.js
import { UPDATE_PAGE_LINK } from '../actionTypes';
const initialState = {
pgLink: []
};
// eslint-disable-next-line import/no-anonymous-default-export
export default function(state = initialState, action) {
switch (action.type) {
case UPDATE_PAGE_LINK:
console.log("Action called ")
return { ...state, pgLink: action.payload }
default:
return state;
}
}
I am unable to dispatch values from store,
Please somebody help me...
If you are using functional components I strongly recommend getting rid of using connect.
To get state from Redux store, you can use useSelector hook, and to dispatch an action, you can use useDispatch hook.
import { useDispatch, useSelector } from 'react-redux'
...
const dispatch = useDispatch()
const updatePage = useSelector(state => state.updatePage.pgLink)
const updatePageLinkActions = () => {
dispatch({
type: UPDATE_PAGE_LINK,
payload: {pageLink : "Action_pageLink" }
})
}
...
Your action creator is not defined properly.
It should be this:
export const updatePageLinkActions = () => dispatch => {
console.log("actions log ", dispatch.payload)
return dispatch({
type: UPDATE_PAGE_LINK,
payload: {pageLink : "Action_pageLink" }
})
};
Related
My toolbar component dispatches an action abortGame(). I see in the console that it reaches the action creator (text "ONE!" displayed on the console) but never the reducer (text "TWO!" never displayed).
What is wrong?
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import App from './App';
import reducer from './store/reducers/reducer';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(
applyMiddleware(thunk)
));
const app = (
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</React.StrictMode>
);
ReactDOM.render(app, document.getElementById('root'));
reducer.js
import * as actionTypes from '../actions/actionTypes';
const initialState = {
score: 0
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.ABORT_GAME:
console.log('TWO');
return {
...state,
score: 0,
};
default:
return state;
}
};
export default reducer;
actionTypes.js
export const ABORT_GAME = 'ABORT_GAME';
actions.js
import * as actionTypes from './actionTypes';
export const abortGame = () => {
console.log('ONE!');
return {
type: actionTypes.ABORT_GAME
};
};
Toolbar.js (component)
import React from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { abortGame } from '../../store/actions/actions';
const toolbar = (props) => (
<div>
<div onClick={props.onAbortGame}><Link to="/">MyApp</Link></div>
</div>
);
const mapDispatchToProps = dispatch => {
return {
onAbortGame: () => dispatch(abortGame)
};
};
export default connect(null, mapDispatchToProps)(toolbar);
You have just missed the function brackets while dispatching the action
const mapDispatchToProps = dispatch => {
return {
onAbortGame: () => dispatch(abortGame)
};
};
Just change this line onAbortGame: () => dispatch(abortGame) to onAbortGame: () => dispatch(abortGame())
abortGame is a action creator which is basically a function. So you need to call the function inside dispatch
You just passing the function name in dispatch not calling it exactly.
Just convert the dispatch(abortGame())
sandbox working link
My component is not rerendering after the store is changing.
I make sure that the store is actually changing by dropping him to the console with
store.subscribe() and console.log(store.getState()) but still the component is not rerendering again.
I will appreciate your help.
configureStore.js
import { createStore, combineReducers } from 'redux';
import home from '../reducers/home';
import favorites from '../reducers/favorites';
export default () => {
const store = createStore(combineReducers({
home,
favorites
}))
return store;
}
App.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import configureStore from './redux/store/configureStore';
import AppRouter from './router/AppRouter';
const store = configureStore();
const jsx = (
<Provider store={store}>
<AppRouter />
</Provider>
);
ReactDOM.render(jsx, document.querySelector('#root'));
home.js (reducer)
const homeDefaultState = {
name: 'someName'
}
export default (state = homeDefaultState, action) => {
switch (action.type) {
case 'CHANGE_NAME':
return {
...state,
name: 'otherName'
}
default:
return state;
}
}
home.js (action)
export const changeName = () => ({
type: 'CHANGE_NAME'
})
Home.js (component)
import React from 'react';
import configureStore from '../../redux/store/configureStore';
import { changeName } from '../../redux/actions/home';
import { connect } from 'react-redux';
const store = configureStore();
const handleName = () => {
store.dispatch(changeName())
}
const Home = (props) => (
<div className="home">
<button onClick={handleName}>
change name
</button>
{props.home.name}
</div>
);
const mapStateToProps = (state) => ({
home: state.home
});
export default connect(mapStateToProps)(Home);
In your Home component you initialize store for second time. And bound action to this second store
const store = configureStore();
const handleName = () => {
store.dispatch(changeName())
}
At the same time with connect() you access store declared in App.jsx
Read from first but update second. Just remove second store and use mapDispatchToProps(second parameter passed to connect()) instead:
const mapStateToProps = (state) => ({
home: state.home
});
export default connect(mapStateToProps, { handleName: changeName })(Home);
Need some help.
As I am trying to get some understanding of React/REdux global state I made some simple get request.
This is done with Axios, thunk, Redux, but i can't get this working
I have Post.js file, nothing fancy
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import PostForm from './PostForm';
export class Post extends Component {
static propTypes = {
posts: PropTypes.any,
fetchPosts: PropTypes.func,
};
componentDidMount() {
const { fetchPosts } = this.props;
fetchPosts();
}
render() {
const { posts } = this.props;
return (
<div>
<PostForm addPost={this.onSubmit} />
<br />
<div>
{posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
))}
</div>
</div>
);
}
}
export default Post;
Next i have my PostContainer.js
import { connect } from 'react-redux';
import Post from './Post';
import { fetchFromApi } from '../reducers/postReducers';
const mapStateToProps = state => ({
posts: state.posts,
});
const mapDispatchToProps = dispatch => ({
fetchPosts: () => dispatch(fetchFromApi()),
});
export default connect(mapStateToProps, mapDispatchToProps)(Post);
My reducer
import Axios from 'axios';
/* action type */
const FETCH_POSTS = 'FETCH_POSTS';
/* action creator */
export const fetchStarted = payload => ({ payload, type: FETCH_POSTS });
/* thunk */
export const fetchFromApi = () => {
return (dispatch, getState) => {
Axios.get('https://jsonplaceholder.typicode.com/posts?_limit=5').then(res =>
dispatch(fetchStarted(res.data))
);
};
};
/* reducer */
export default function reducer(state = [], action = {}) {
switch (action.type) {
case FETCH_POSTS: {
return {
...state,
data: action.payload,
};
}
default:
return state;
}
}
and my store
import { combineReducers, applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import postReducer from './reducers/postReducers';
const initialState = {
posts: {
data: {},
},
};
const reducers = {
posts: postReducer,
};
Object.keys(initialState).forEach(item => {
if (typeof reducers[item] == 'undefined') {
reducers[item] = (state = null) => state;
}
});
const combinedReducers = combineReducers(reducers);
const store = createStore(
combinedReducers,
initialState,
composeWithDevTools(applyMiddleware(thunk))
);
export default store;
All of that is doing not much. My map method is trying to map empty posts object. And for some reason my fetchPosts is not dispatched. I have reade some old posts here but still can't get this working
Thanks
Edit
this is my app.js file with container
import React from 'react';
import './App.css';
import Post from './components/PostContainer';
import { Provider } from 'react-redux';
import store from './store';
function App() {
return (
<Provider store={store}>
<div className='App'>
<Post />
</div>
</Provider>
);
}
export default App;
I managed to get this working.
Data was not there when my posts array was render. After passing simple if statemante all is working
I don't know how to load the data of the fetchLatestAnime action in the react app.js file.
My mission is to show the endpoint data that I am doing fetch.
I have already implemented the part of the reducers and action, which you can see in the part below. The only thing I need is to learn how to display the data.
App.js
import React from 'react';
import './App.css';
function App() {
return (
<div className="App">
</div>
);
}
export default App;
actions/types.js
export const FETCHING_ANIME_REQUEST = 'FETCHING_ANIME_REQUEST';
export const FETCHING_ANIME_SUCCESS = 'FETCHING_ANIME_SUCCESS';
export const FETCHING_ANIME_FAILURE = 'FETCHING_ANIME_FAILURE';
actions/animesActions.js
import{
FETCHING_ANIME_FAILURE,
FETCHING_ANIME_REQUEST,
FETCHING_ANIME_SUCCESS
} from './types';
import axios from 'axios';
export const fetchingAnimeRequest = () => ({
type: FETCHING_ANIME_REQUEST
});
export const fetchingAnimeSuccess = (json) => ({
type: FETCHING_ANIME_SUCCESS,
payload: json
});
export const fetchingAnimeFailure = (error) => ({
type: FETCHING_ANIME_FAILURE,
payload: error
});
export const fetchLatestAnime = () =>{
return async dispatch =>{
dispatch(fetchingAnimeRequest());
try{
let res = await axios.get('https://animeflv.chrismichael.now.sh/api/v1/latestAnimeAdded');
let json = await res.data;
dispatch(fetchingAnimeSuccess(json));
}catch(error){
dispatch(fetchingAnimeFailure(error));
}
};
};
reducers/latestAnimeReducers.js
import {
FETCHING_ANIME_FAILURE,
FETCHING_ANIME_REQUEST,
FETCHING_ANIME_SUCCESS
} from '../actions/types';
const initialState = {
isFetching: false,
errorMessage: '',
latestAnime: []
};
const latestAnimeReducer = (state = initialState , action) =>{
switch (action.type){
case FETCHING_ANIME_REQUEST:
return{
...state,
isFetching: true,
}
case FETCHING_ANIME_FAILURE:
return{
...state,
isFetching: false,
errorMessage: action.payload
}
case FETCHING_ANIME_SUCCESS:
return{
...state,
isFetching: false,
latestAnime: action.payload
}
default:
return state;
}
};
export default latestAnimeReducer;
reducers/index.js
import latestAnimeReducers from './latestAnimeReducers'
import {combineReducers} from 'redux';
const reducers = combineReducers({
latestAnimeReducers
});
export default reducers;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import resolvers from './redux/reducers/index';
import {createStore , applyMiddleware} from 'redux';
import {Provider} from 'react-redux';
import thunk from 'redux-thunk';
const REDUX_DEV_TOOLS = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(resolvers , REDUX_DEV_TOOLS)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
Ideally, this is how your app.js should look like. I created a working codesandbox for you here. Your initial latestAnime state was an empty array but the action payload you set to it is an object, so remember to pass payload.anime like i have done in the sandbox.
import React, { useEffect } from "react";
import { connect } from "react-redux";
import { fetchLatestAnime } from "./redux/actions/animesActions";
const App = props => {
const { fetchLatestAnime, isFetching, latestAnime, errorMessage } = props;
useEffect(() => {
fetchLatestAnime();
}, [fetchLatestAnime]);
console.log(props);
if (isFetching) {
return <p>Loading</p>;
}
if (!isFetching && latestAnime.length === 0) {
return <p>No animes to show</p>;
}
if (!isFetching && errorMessage.length > 0) {
return <p>{errorMessage}</p>;
}
return (
<div>
{latestAnime.map((anime, index) => {
return <p key={index}>{anime.title}</p>;
})}
</div>
);
};
const mapState = state => {
return {
isFetching: state.latestAnimeReducers.isFetching,
latestAnime: state.latestAnimeReducers.latestAnime,
errorMessage: state.latestAnimeReducers.errorMessage
};
};
const mapDispatch = dispatch => {
return {
fetchLatestAnime: () => dispatch(fetchLatestAnime())
};
};
export default connect(
mapState,
mapDispatch
)(App);
When console.log'ing state or attempting to render in component, my store returns as undefined. However, in React devtools, the store is showing as expected.
index.js with dummy dispatch calls
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { addItem } from "./actions/actions";
import configureStore from "./store/configure-store";
import DashboardPage from "./components/DashboardPage";
const store = configureStore();
store.dispatch(addItem({ description: "item 1" }));
store.dispatch(addItem({ description: "item 2" }));
store.dispatch(addItem({ description: "item 3" }));
const jsx = (
<Provider store={store}>
<DashboardPage />
</Provider>
);
ReactDOM.render(jsx, document.getElementById('root'));
config-store.js
import { createStore } from 'redux';
import reducer from "../reducers/reducer";
export default () => {
const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
return store;
};
DashboardPage.js
import React from "react";
import { connect } from "react-redux";
const DashboardPage = (props) => {
console.log(props.items); // for debugging
return (
<div>
<h1>Items:</h1>
<p>{props.items}</p>
</div>
)
};
const mapStateToProps = (state) => {
return { items: state.items };
};
export default connect(mapStateToProps)(DashboardPage);
reducer.js
const reducerDefaultState = [];
export default (state = reducerDefaultState, action) => {
switch (action.type) {
case 'ADD_ITEM':
return [
...state,
action.item
];
default:
return state;
}
};
actions.js
export const addItem = (description = "") => ({
type: 'ADD_ITEM',
item: { description }
});
I have studied many resources online relating to this issue, however I can't see where I am differing from suggested implementation.
Your state is an Array which doesn't have items property.
Try using this code:
const mapStateToProps = (state) => {
return { items: state };
};
Or change your reducer/createStore to something like this
import { createStore, combineReducers } from 'redux';
import reducer from "../reducers/reducer";
export default () => {
const store = createStore(
combineReducers({items: reducer}),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
return store;
};
https://redux.js.org/api/combinereducers