i am trying to include my common component in my main.js
this one I did it it successfully.
but in my common component, I am trying to print my redux data values.
so I created a method called handleClickForRedux to print the values.
I have included mapStateToProps and mapDispatchToProps
but still value is not printing at this line. console.log("event reddux props--->", props);
can you tell me how to fix it.
providing my code snippet and sandbox below.
https://codesandbox.io/s/react-redux-example-265sd
scroll.js
import React, { useEffect, useState, Fragment } from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import Card from "#material-ui/core/Card";
//import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import Typography from "#material-ui/core/Typography";
import Drawer from "#material-ui/core/Drawer";
import { bindActionCreators } from "redux";
import * as actionCreators from "../actions/actionCreators";
import { connect } from "react-redux";
import { compose } from "redux";
function SportsMouse(classes, props) {
// const [canEdit, setCanEdit] = useState(false);
function handleClickForRedux(event) {
console.log("event--->", event);
console.log("event reddux props--->", props);
}
return (
<Card>
<div onClick={handleClickForRedux}>I am here </div>
</Card>
);
}
SportsMouse.propTypes = {
classes: PropTypes.object.isRequired
};
function mapStateToProps(state) {
return {
posts: state.posts,
comments: state.comments
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch);
}
export default compose(
connect(
mapStateToProps,
mapDispatchToProps
)
)(SportsMouse);
main.js
import React from "react";
import { Link } from "react-router-dom";
import Scroll from "../commonComponents/scroll";
const Main = props => {
const { children, match, ...rest } = props;
return (
<div>
<h1>
<Scroll />
<Link to="/">Reduxstagram</Link>
</h1>
{React.Children.map(children, child => React.cloneElement(child, rest))}
</div>
);
};
export default Main;
Even when using material-ui, components only accept one argument. classes exists inside props. If you console.log(classes) you'll see that it contains all of your props, including material-ui's styles. It should be this:
function SportsMouse(props) {
Related
I am trying to change the value of a state defined in the store using redux. I defined Slice, store and component according to react redux doc, however, when I trigger the event I obtain the error:
"object(...) is not a function"
This is the slice definition
import { createSlice } from "#reduxjs/toolkit";
export const sliceCambiadorDeVista = createSlice({
name:"cambiadorDeVista",
initialState:{
value:30,
},
reducers:{
cambiarVista:(state, action)=>{
state.value = action.payload
}
}
})
export const cambiarVista = sliceCambiadorDeVista.actions;
export const vistaActual = (state) => state.cambiadorDeVista.value;
export default sliceCambiadorDeVista.reducer;
This is the store definition
import {configureStore} from "#reduxjs/toolkit"
import cambiadorDeVistaReducer from "../redux/actions/SwitchSections/switchSections"
export default configureStore({
reducer:{
cambiadorDeVista:cambiadorDeVistaReducer,
}
})
and this is a part of the component definition.
import * as React from 'react';
import Box from '#mui/material/Box';
import { ThemeProvider } from '#emotion/react';
import theme from "../themeConfig"
import { ListItem, ListItemText, ListSubheader } from '#mui/material';
import AddCircleIcon from "#mui/icons-material/AddCircle"
import WbSunnyIcon from '#mui/icons-material/WbSunny';
import OtherHousesIcon from '#mui/icons-material/OtherHouses';
import ElectricalServicesIcon from '#mui/icons-material/ElectricalServices';
import { ListItemIcon , List} from '#mui/material';
import { makeStyles } from '#mui/styles';
import { useDispatch, useSelector } from 'react-redux';
import { cambiarVista, vistaActual } from '../redux/actions/SwitchSections/switchSections';
const LeftAside = () => {
const dispatch = useDispatch()
const vistaActualState = useSelector(vistaActual)
const changeVistaHandler = ()=>{
dispatch(()=>cambiarVista(3))
}
return (
<ThemeProvider theme = {theme}>
<Box sx={{display:{xs:"none",md:"flex"}}}>
<List
sx={{display:{xs:"none",md:"flex"}, width:"100%", bgcolor:"secondary",flexDirection:"column", borderRight:1}}
subheader ={<ListSubheader>Etapas {vistaActualState}</ListSubheader>}
>
<ListItem>
<ListItemIcon>
<AddCircleIcon />
</ListItemIcon>
<ListItemText id="section-basic-data-label"
primary = "Datos Basicos"
disableTypography ="true"
className={classes.textAsideItems}
onClick={changeVistaHandler}
/>
</ListItem>
Error is generated inside of event handler changeVistaHandler. Problem seens to be related to reducer parameter.
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?
Being a newbie to react native ,I am finding it difficult to connect my redux with react native and make it work. After javascript bundle finishes ,I see an error "can't read property type of undefined" or "could not find store in either the context or props of "connect".Either wrap the root component in a or explicitly pass "store" as prop.I don't see any of the console.log working except for reducer .
Here is the action that I am using
import {ADD_PLACE,DELETE_PLACE,DESELECT_PLACE,SELECT_PLACE} from './actiontypes';
export const addPLace =(placeName) =>{
console.log('addPLace is being dispatched now');
console.log('In addPLace reducer');
return{
type:ADD_PLACE,
payload:{
placeName:placeName
}
};
};
export const deletePlace =()=>{
return{
type:DELETE_PLACE
};
}
export const selectedPlace =(key) =>{
return{
type:SELECT_PLACE,
payload:{
placekey:key
}
};
};
export const deselectPlace =()=>{
return {
type:DESELECT_PLACE
};
};
Here is the reducer part
import {ADD_PLACE,DELETE_PLACE,SELECT_PLACE,DESELECT_PLACE} from '../actions/actiontypes';
import PlaceImage from "../../../src/assets/download.jpeg";
const INITIAL_STATE={
places:[],
selectedPlace:null
}
const reducer =(action,state=INITIAL_STATE) =>{
console.log('INside reducer');
console.log(action);
switch(action.type){
case ADD_PLACE:
return {
...state,
places:state.places.concat({
key:Math.random(),
name:action.payload.placeName,
image:placeImage
})
};
case DELETE_PLACE:
return{
...state,
places:state.places.filter(place =>{
return place.key !== state.selectedPlace.key;
}),
selectPlace:null
};
case SELECT_PLACE:
return{
...state,
selectedPlace:state.places.find(place=>{
return place.key ===action.payload.placekey;
})
};
case DESELECT_PLACE:
return{
...state,
selectPlace:null
};
default:
return state;
}
}
export default reducer;
Here is the App.js
import React, { Component } from "react";
//import { StyleSheet, Text, View, TextInput, Button } from "react-native";
import store from './src/store/reducers/index.js';
import {Provider} from 'react-redux';
//import {createStore} from 'redux';
//import {connect} from 'react-redux';
import Home from './Home.js';
export default class App extends React.Component {
render() {
console.log('inside App');
console.log(store);
return (
<Provider store={store}>
<Home />
</Provider>
);
}
}
Here is the Home.js
import React, { Component } from "react";
import { StyleSheet, Text, View, TextInput, Button } from "react-native";
//import ListItem from './src/components/ListItem';
import PlaceInput from "./src/components/PlaceInput";
import PlaceList from "./src/components/PlaceList";
//import PlaceImage from "./src/assets/download.jpeg";
import PlaceDetail from "./src/components/PlaceDetail";
//import configureStore from './src/store/reducers/index.js';
//import {Provider} from 'react-redux';
//import {createStore} from 'redux';
import {connect} from 'react-redux';
import {addPLace,deletePlace,selectedPlace,deselectPlace} from './src/store/actions';
//const store=configureStore();
class Home extends React.Component {
placeAddedHandler =val=>{
console.log('Val is ',val);
console.log(val);
this.props.onAddPlace(val);
};
placeSelectHandler =id=>{
console.log('id is');
this.props.onSelectPlace(id);
};
placeDeleteHandler =() =>{
console.log('inside delete handler');
this.props.onDeletePlace();
};
modelClosedHandler =() =>{
console.log('iinside close handler');
this.props.onDeslectPlace();
}
render() {
console.log('Inside render function');
return (
<View style={styles.container}>
<PlaceInput onPlaceAdded={this.placeAddedHandler}/>
<PlaceList places={this.props.places} onItemSelected={this.placeSelectHandler}/>
<PlaceDetail
selectedPlace={this.props.selectedPlace}
onItemDeleted={this.placeDeleteHandler}
onModalClosed={this.modelClosedHandler}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding:30,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'flex-start',
},
});
const mapStateToProps=state => {
console.log('Inside mapStateToProps ');
console.log(state );
return {
places:state.places.places,
selectedPlace:state.places.selectPlace
};
}
const mapDispatchToProps = dispatch =>{
return {
onAddPlace:(name)=>dispatch(addPLace(name)),
onDeletePlace:()=>dispatch(deletePlace()),
onSelectPlace:(id)=>dispatch(selectedPlace(id)),
onDeslectPlace:()=>dispatch(deselectPlace())
};
}
export default connect(mapStateToProps,mapDispatchToProps)(Home);
Link to github repo of project at this moment
github link
Looks like you have made a small import/export error.
In your reducers/index.js you are exporting it as a non default value which you are trying to import as default value in App.js.
import store from './src/store/reducers/index.js';
should be
import {store} from './src/store/reducers/index.js';
Let me know if it works.
Currently, I'm working on a small application that utilizes modals. I don't want to use 'ready-to-use' packages like react-modal and instead decided to try to do it on my own.
1) A reducer in src/reducers/modalReducer.js
const modalReducer = (state = {
show: true,
}, action) => {
switch (action.type) {
case 'TOGGLE_MODAL':
console.log('reducer worked out')
state = {...state, show: !state.show }
break
default:
return state
}
}
export default modalReducer
My reducers/index.js
import { combineReducers } from 'redux'
import modalReducer from './modalReducer'
const reducers = combineReducers({
modal: modalReducer
})
export default reducers
2) A store in src/store.js
import { createStore } from 'redux'
import reducer from './reducers/index'
export default createStore(reducer)
3) A Modal component in src/components/Modal.js. I want this component to be reusable and contain input forms which I'll add later.
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { toggleModal } from '../actions/index'
import { bindActionCreators } from 'redux'
import '../css/Modal.css'
class Modal extends Component {
render () {
if(!this.props.show) {
return (<h1>FUC YOU</h1>)
}
console.log('HELLLO' + this.props.show)
return (
<div className='backdrop'>
<div className='my-modal'>
<div className='footer'>
<button className='close-btn' onClick={ () => toggleModal }>
X
</button>
</div>
<h1>{ this.props.title }</h1>
<hr/>
<div>
{ this.props.contents }
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return { show: state.modal.show }
}
const mapDispatchToProps = (dispatch) => {
return {
toggleModal: () => dispatch(toggleModal())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Modal)
My problem is that when I'm pressing the button x, in my modal nothing happens. It means that I did something wrong when was dispatching actions, but I have no idea what I missed...
At this point I just want my empty modal to be closed when the x button is pressed.
In my index.js I have the following structure:
import React from 'react'
import ReactDOM from 'react-dom'
import registerServiceWorker from './registerServiceWorker'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import store from './store.js'
import App from './components/App'
ReactDOM.render(
<Provider store = {store} >
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
, document.getElementById('root'))
registerServiceWorker()
My Modal component is within App
You're not actually calling the toggleModal() action creator. In addition, you're referencing the imported function, not the function you're getting as props:
onClick={ () => toggleModal }
The immediate fix would be: onClick={ () => this.props.toggleModal() }.
Having said that, there's two other ways you can improve this code.
First, you can pass toggleModal directly as the handler for onClick, like:
onClick={this.props.toggleModal}
Second, you can replace the mapDispatch function by using the "object shorthand" syntax supported by connect:
import {toggleModal} from "../actions";
const actions = {toggleModal};
export default connect(mapState, actions)(Modal);
Beyond that, I'd encourage you to read my post Practical Redux, Part 10: Managing Modals and Context Menus, which specifically shows how to implement modal dialogs using React and Redux, and points to additional resources on the topic.
Im studying React-Redux, Material-UI.
Now, Im trying to create Sample App, but not work.
I dont know how to improve my code.
I want to open Drawer , when Material-UI AppBar onLeftIconButtonTouchTap is clicked.
I cant bind my Action to Component, I think.
When following code is running, not fire onLeftIconButtonTouchTap event.
And when I change openDrawer to openDrawer(), JS error 'openDrawer is not a function' is found on Chrome Dev tool.
Header.jsx as a Component
import React, { PropTypes } from 'react';
import AppBar from 'material-ui/AppBar';
import Drawer from 'material-ui/Drawer';
const Header = ({
openDrawer,
open
}) => (
<div>
<AppBar
title='sample'
onLeftIconButtonTouchTap = {() => openDrawer}
/>
<Drawer
docked={false}
open={open}
/>
</div>
)
Header.PropTypes = {
openDrawer: PropTypes.func.isRequired,
open: PropTypes.bool.isRequired
}
export default Header;
HeaderContainer.jsx as a Container
import React from 'react';
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux';
import { header } from '../actions'
import Header from '../components/Header';
const mapStateToProps = (state) => ({open});
const mapDispatchToProps = (dispatch) => (
{openDrawer: bindActionCreators(header, dispatch)}
);
const HeaderContainer = connect(
mapStateToProps,
mapDispatchToProps
)(Header);
export default HeaderContainer;
App.jsx as a RootComponent
import React, { Component, PropTypes } from 'react';
import Header from '../components/Header';
import injectTapEventPlugin from "react-tap-event-plugin";
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
injectTapEventPlugin();
class App extends Component {
constructor(props) {
super(props);
}
getChildContext() {
return { muiTheme: getMuiTheme(baseTheme) };
}
render() {
return (
<div>
<Header />
{this.props.children}
</div>
);
}
};
App.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
export default App;
Thanks in advance.
You are not binding the function correctly. You need to update your code to
<AppBar
title='sample'
onLeftIconButtonTouchTap = { openDrawer.bind(this) }
/>
More about .bind() method here: Use of the JavaScript 'bind' method