Redux store value set in callback - javascript

new to react-redux.I am facing a problem while working with redux store.
Data for store is loaded from API.Flow of my code is as follows:
app.js:
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import Schema from './components/Schema';
import './styles/bootstrap.css';
import './styles/main.css';
export default class App{
constructor(props) {
super(props);
this.state = { store: {}};
}
componentWillMount(){
store(storeObject => {
this.setState({store: storeObject});
});
}
render(){
return <Provider store={ this.state.store }><Schema /></Provider>
}
}
store/index.js:
export default function(next) {
getInitialState(function(initialState) {
store = createStore(Reducers, initialState, compose(applyMiddleware(...middleware), extension));
console.log(store);//returning correct store value
next(store);
});
};
main.js:
import React from 'react';
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import App from './app.js';
const dom = document.getElementById('root');
render(
<AppContainer>
<App />
</AppContainer>,
dom
);
it is giving following error.

The store function which I guess is a reference to the getStore function doesn't return anything which means that App doesn't return anything hence the exception.
Because getStore does an async operation, you'll have to do something like this:
export default class App extends Component{
componentWillMount(){
store(storeObject => {
this.setState({store: storeObject});
});
}
render(){
return <Provider store={ this.state.store }><Schema /></Provider>
}
}

Related

Uncaught (in promise) TypeError: Cannot read property 'map' of undefined

So, when I am trying to access my news props to display news title to my page I am receiving and error like this one:
Error Msg
import React, { Component } from 'react';
import Search from './Search';
import { connect } from 'react-redux';
import NewsItem from './NewsItem';
class NewsResults extends Component {
render() {
return (
<div>
<Search />
{this.props.news.map(item => {
return <NewsItem new={item} key={item.objectID} showButton={true}/>
})
}
</div>
)
}
}
function mapStateToProps(state) {
console.log(state)
return {
news: state.news
}
}
export default connect(mapStateToProps, null)(NewsResults);
NewsItem.js is just a component through which I will display the results on my application.
import React, { Component } from 'react';
class NewsItem extends Component {
render(){
return(
<div className="col-sm-12 col-sm-3">
<div className="thumbnail">
<div className="caption">
<h3>{this.props.new.title}</h3>
</div>
</div>
</div>
)
}
}
export default NewsItem;
This is where I'm fetching my information from an api and then I want to display on my page using maps
class Search extends Component {
constructor(props) {
super(props);
this.state = {
query: ''
};
}
search(){
console.log('Search button clicked', this.state.query);
let url = `http://hn.algolia.com/api/v1/search_by_date?query=${this.state.query}`;
// console.log(url);
fetch(url, {
method: 'GET'
}).then(response=> response.json())
.then(jsonObject => {this.props.news(jsonObject.results)});
}
This is my redux action code in action.js file
export const NEWS = "NEWS";
export function news(items) {
const action = {
type: NEWS,
items
}
return action;
}
This is the reducer file
import { NEWS } from '../actions';
const initialState = {
news: []
}
export default function (state= initialState, action) {
switch(action.type) {
case NEWS:
console.log("News are ",action.items);
return {
...state,
news: action.items
};
default:
return state;
}
};
So now I have changed my reducer to be in 2 seperate files I will post below. Also by doing that error message changed to this:
This is the new Error I am getting now
My reducer files are below:
import { NEWS } from '../actions';
export default function news(state = [], action) {
switch(action.type) {
case NEWS:
console.log("News are ",action.items);
return action.items;
default:
return state;
}
}
Second Reducer File:
import news from './news_reducer';
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
news
});
export default rootReducer;
Then I am importing my rootReducer from reducer folder in index.js outside of source folder where my redux store is.
This is how I am creating my store in index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
import registerServiceWorker from './registerServiceWorker';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root'));
registerServiceWorker();
Now, My problem is that I am trying to send data from actions but reducer isn't recieving it for some reason.
Another Error popped up now. Another Error

ReactIntl work only when refreshing browser.

The translation only work on refresh. It seems because i have used a wrapper around the App.js that why its not working.
Also i tried to add a key to intlprovider the translation worked but now all my inner components get refresh.
Could there be a way to used reactintl when using an app wrapper without refreshing all inner components??
Below you can find the app.js, index.js and the app wrapper:
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import './styles/global.css';
import registerServiceWorker from './registerServiceWorker';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import rootReducer from './redux/rootReducers';
import AppWrapperContainer from './containers/appWrapperContainer/appWrapperContainer';
import {localeSet} from './redux/actions/localeActions';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducer, /* preloadedState, */ composeEnhancers(
applyMiddleware(thunk)
));
if(localStorage.H24Lang)
{
store.dispatch(localeSet(localStorage.H24Lang));
}
ReactDOM.render((
<Provider store={store}>
<AppWrapperContainer/>
</Provider>
),
document.getElementById('root'));
registerServiceWorker();
AppWrapperContainer.js
import React, { Component } from 'react';
import { IntlProvider, addLocaleData} from "react-intl";
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import messages from '../../messages';
import en from "react-intl/locale-data/en";
import fr from "react-intl/locale-data/fr";
import App from "../../App";
addLocaleData(en);
addLocaleData(fr);
class AppWrapperContainer extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
const {lang} = this.props
let locale =
(navigator.languages && navigator.languages[0])
|| navigator.language
|| navigator.userLanguage
|| lang
return (
// <IntlProvider locale={lang} messages={messages[lang]} key={lang}></IntlProvider>
<IntlProvider locale={lang} messages={messages[lang]} >
<App/>
</IntlProvider>
);
}
}
AppWrapperContainer.propTypes = {
lang: PropTypes.string.isRequired
}
//what reducer you need
function mapStateToProps(state) {
console.log("State is", state);
return {
lang: state.locale.lang
};
}
export default connect(mapStateToProps,null)(AppWrapperContainer);
App.js
import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Home from './screens/home/home';
import { connect } from 'react-redux';
import { BrowserRouter as Router, Route,Redirect, Switch } from 'react-router-dom';
class App extends Component {
constructor(props) {
super(props);
this.state = {
};
}
componentWillMount() {
}
componentDidMount() {
}
render() {
return (
<div className="App">
<Router>
<div className = "app-main-content">
<Route exact path='/' component={Home} />
</Router>
</div>
);
}
}
//what reducer you need
function mapStateToProps(state) {
return {
};
}
function mapDispatchToProps(dispatch) {
return {
};
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
The key prop in IntlProvider forces React to remount the component (and all its children), but you just want them to be re-rendered (not remounted).
First confirm that your stored state is changing its locale/lang value as expected and that this change goes thougth mapStateToProps to your AppWrapperContainer component.
Then, make sure it is received in componentWillReceiveProps method and that a re-render is fired when its value changes. Then, all children will be re-rendered (if not blocked by shouldComponentUpdate method).
By the way, what is locale variable in AppWrapperContainer for?

Why my Component is not receiving updated props from Redux Store?

My Component is not receiving the props from the redux store. I am calling the Action by an onClick event which is this. On Click the name "wrapper" is changed to "wrapper slide-menu" in the Redux Store, however, the Props are not updating when I do console.log(). , but when I check Redux dev tools, the store is shown to be updated.
<a onClick={ ()=> this.props.setName("wrapper")} ><i className="zmdi zmdi-menu ti-align-right"></i></a>
This is a part of my Component which is console logging siderbarname which is updated from the redux store.
import React, { Component } from "react";
import "../App.css";
import { Link } from "react-router-dom";
class Index extends Component {
constructor(props) {
super(props);
this.state = {
sidebarname: this.props.sidebarname
};
}
render() {
const sidebarName = this.props.sidebarname;
console.log("sidebarname is " + sidebarName);
console.log(this.props);
This is my Action.
import { connect } from "react-redux";
import * as Actions from "./indexActionTypes";
import App from "../../_layouts";
const mapStateToProps = state => ({
sidebarname: state.sidebarReducer.sidebarname
});
const mapDispatchToProps = dispatch => ({
setName: sidebarname => {
//console.log('setName is called');
//console.log('togglemargin is'.togglemargin);
if (sidebarname !== "wrapper slide-menu") {
dispatch({
type: Actions.TOGGLE_SIDEBAR,
sidebarname: sidebarname
});
}
if (sidebarname === "wrapper") {
console.log("this is called if2");
dispatch({
type: Actions.TOGGLE_SIDEBAR,
sidebarname: "wrapper slide-menu"
});
}
}
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
And this is my Reducer.
import * as Actions from "../../actions/indexToggle/indexActionTypes";
//const sidebarname = "wrapper slide-menu";
let initialState = { sidebarname: "wrapper" };
const sidebarReducer = (state = initialState, action) => {
switch (action.type) {
case Actions.TOGGLE_SIDEBAR:
console.log("reducer called");
console.log(state);
//console.log('action',action);
return Object.assign({}, state, {
sidebarname: action.sidebarname
});
default:
return state;
}
};
export default sidebarReducer;
This is my Store.
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from "../reducers/rootreducer";
//const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export default store;
This is my App.js File.
import React, { Component } from 'react';
import './App.css';
import { Provider } from 'react-redux';
import store from './store/store';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import App from './actions/indexToggle/indexActions';
import FirstDashboard from './_layouts/views/firstDashboard';
import SecondDashboard from './_layouts/views/secondDashboard';
import ThirdDashboard from './actions/dashboardToggle/thirdDashboardToggleAction';
import FourthDashboard from './_layouts/views/fourthDashboard';
class Main extends Component {
render() {
return (
<Provider store={store}>
<Router>
<div>
<App />
<Route path='/overview1' exact strict component={FirstDashboard} />
<Route path='/overview2' exact strict component={SecondDashboard} />
<Route path='/overview3' exact strict component={ThirdDashboard} />
<Route path='/overview4' exact strict component={FourthDashboard} />
</div>
</Router>
</Provider>
);
}
}
export default Main;
I am really getting confused why it is not rendering inside the component.
However, it is getting updated in the store.
#codemt Please add below method in your code it will receive the updated props
componentWillReceiveProps(nextProps) {
const {sidebarname} = nextProps;
this.setState({sidebarname});
}
Please put inside your relative component in your case is Index

Uncaught TypeError: this.props.*** is not a function in React-redux app while calling a function from redux container

I have a react app with redux implemented and I'm getting this error
Uncaught TypeError: this.props.updateDimensions is not a function
while executing the App.js:-
class App extends Component {
componentDidMount() {
this.updateWindowDimensions();
window.addEventListener("resize", this.updateWindowDimensions);
}
componentWillUnmount() {
window.removeEventListener("resize", this.updateWindowDimensions);
}
updateWindowDimensions() {
this.props.updateDimensions(window.innerWidth, window.innerHeight);
}
render() { .....
The AppContainer.js file:-
import { connect } from "react-redux";
import App from "./App";
import { UPDATE_DIMENSIONS } from "../actions";
const mapStateToProps = (state, ownProps) => {
return {
screenWidth: state.screenSize.screenWidth,
screenHeight: state.screenSize.screenHeight
};
};
const mapDispatchToProps = (dispatch, ownProps) => {
return {
updateDimensions: (screenWidth, screenHeight) => {
dispatch({ type: UPDATE_DIMENSIONS, screenWidth, screenHeight });
}
};
};
const AppContainer = connect(mapStateToProps, mapDispatchToProps)(App);
export default AppContainer;
This is the index.js, where the AppContainer is being called:-
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import rootReducer from "./reducers";
import { BrowserRouter as Router, Route } from "react-router-dom";
import "./index.css";
import AppContainer from "./App";
import registerServiceWorker from "./registerServiceWorker";
import "semantic-ui-css/semantic.min.css";
let store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<Router>
<Route component={AppContainer} />
</Router>
</Provider>,
document.getElementById("root")
);
registerServiceWorker();
I believe this is a common error and I have looked everywhere and there seems to be no obvious flaw in the code. Not sure where the issue is.
Figured it out.
in index.js:-
import AppContainer from "./App";
should be
import AppContainer from "./AppContainer";
ugh! This would have been so much easier if React threw an error saying 'AppContainer not found in ./App.js'
Update:-
I also had another error that was fixed by adding the following:-
constructor(props) {
super(props);
this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
}
I think you forgot :
constructor(props) {
super(props);
}

--How do I get access to my container/store in this top level file?

I'm just getting started with React/Redux and have everthing working fine with Redux when I test it.
However, I am not able to connect it into my actual application.
I assume I should use connect(), but I don't know how/where to.
// libraries
import React from 'react';
import ReactDOM from 'react-dom';
// redux
import { Provider } from 'react-redux';
import store from './redux/store';
import './redux/test.js';
import {connect} from 'react-redux'
class App extends React.Component {
constructor(props, test) {
super(props);
}
render () {
return (
<div id = 'contents'>
</div>
)
}
}
const app = document.getElementById('app');
ReactDOM.render(
<Provider store={store}>
<App></App>
</Provider>
, app);
You need to connect your component App.
By example let's assume you have value in your reducer named reducer in your store :
// libraries
import React from 'react';
import ReactDOM from 'react-dom';
// redux
import { Provider } from 'react-redux';
import store from './redux/store';
import './redux/test.js';
import {connect} from 'react-redux'
class App extends React.Component {
constructor(props, test) {
super(props);
}
render () {
// You can use data from props
return (
<div id = 'contents'>
{this.props.data}
</div>
)
}
}
const mapStateToProps = (state, ownProps) => {
// Bind your store state to the component data
return {
date: state.reducer.value,
};
}
const mapDispatchToProps = (dispatch) => {
// Bind actions to your component
}
const ConnectedApp = connect(mapStateToProps, mapDispatchToProps)(App);
const app = document.getElementById('app');
ReactDOM.render(
<Provider store={store}>
<ConnectedApp></ConnectedApp >
</Provider>
, app);
so what you need is to wrap App with the function returned by connect:
const AppWithRedux = connect()(App);
ReactDOM.render(
<Provider store={store}>
<AppWithRedux/>
</Provider>,
app);
But you can find a good example about how to integrate redux with react in the following link:
http://redux.js.org/docs/basics/UsageWithReact.html

Categories