EDIT: I think the issue is with my reducers
I only have one reducer called "filmsReducer" where I do this at the end :
export default combineReducers({
films: filmsReducer
});
I'm doing an app in React Native using Redux,
I want to get the initialState values below in a component :
const initialState = {
name: "",
likedFilms: [299534, 49530, 629],
dislikedFilms: [100241, 559969]
};
const filmsReducer = (state = initialState, action) => {
const { likedFilms, dislikedFilms } = state;
switch (action.type) {
case ADD_FILM:
if (action.array === "like") {
const newLikedFilms = [...state.likedFilms, action.payload];
return {
...state,
likedFilms: newLikedFilms
};
} else {
const newDislikedFilms = [...state.dislikedFilms, action.payload];
return {
...state,
dislikedFilms: newDislikedFilms
};
}
default:
return state;
}
};
And here's the component, I want to get likedFilms array from the redux state in the props of this component, but the console log doesn't work :
class LikedScreen extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log(this.props.likedFilms); <-- doesn't work
}
}
const mapStateToProps = state => ({
likedFilms: state.likedFilms
});
export default connect(mapStateToProps)(LikedScreen);
Regarding your comment, you probably have to adapt your code to the following:
Edit Regarding another comment of yours, you need to change it to films instead of FilmsReducer:
const mapStateToProps = state => ({
likedFilms: state.films.likedFilms
});
It will be like, use reducer name as while mapping props in Component
class LikedScreen extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log(this.props.likedFilms); <-- doesn't work
}
}
const mapStateToProps = state => ({
likedFilms: state.films.likedFilms
});
export default connect(mapStateToProps)(LikedScreen);
Related
I am new in redux.
My code :
Home Screen
<Text> {{this.props.mycity}} </Text>
const mapStateToProps = function(state) {
return {
mycity: state.layersFlag.baseDistrictADhabi //consist true/false
}
}
export default connect(mapStateToProps)(HomeScreen);
Sidemenu Screen :
UI
<Switch onValueChange={(flag) => {
this.props.toggleCity();
} value={this.state.city} />
const mapDispatchToProps = dispatch => {
return {
toggleCity: () => {
dispatch({ type: "changeCity" })
}
};
};
export default connect(null, mapDispatchToProps)(SideMenuScreen);
Store and reducer setup :
const initialState = {
city : {
mycity: true
}
};
const reducer = (state = initialState, action)=>{
switch (action.type) {
case "changeCity":
return Object.assign({}, state, {
mycity: action.payload.mycity
})
default:
return state;
}
}
const Store = createStore(reducer);
I am stuck in sidemenu. How to dispach in mapDispatchToProps method:
How to pass action in mapDispatchToProps in sidemenu?
If my assumptions on what your Switch component does is correct, it would trigger the onValueChange event-listener when you pass in this.state.city to the value prop. You end up calling this.props.toggleCity() to dispatch your changeCity action. I think the set-up is correct for here...
However, it looks like your reducer is expecting an action.payload which you never passed in as part of the action.
const reducer = (state = initialState, action)=>{
switch (action.type) {
case "changeCity":
return Object.assign({}, state, {
mycity: action.payload.mycity
})
default:
return state;
}
}
So yes the dispatch is working correctly, but you are not passing all the necessary data for your reducer to return a new piece of state.
You need to update your mapDispatchToProps, your event-handler and your reducer to something like
<Switch onValueChange={(flag) => {
this.props.toggleCity(this.state.city);
} value={this.state.city} />
const mapDispatchToProps = dispatch => {
return {
toggleCity: (myCity) => {
dispatch({ type: "changeCity", payload: myCity })
}
};
};
export default connect(null, mapDispatchToProps)(SideMenuScreen);
Your reducer also seems to have an extra key, you don't need to access the mycity prop in payload if its already the payload. Update to:
const reducer = (state = initialState, action)=>{
switch (action.type) {
case "changeCity":
return Object.assign({}, state, {
mycity: action.payload
})
default:
return state;
}
}
Adding on, if you want your Hone component to re-render with the new data in your redux-state, you can do something like this.
In your HomeScreen component, make use of a state-variable to save your abudhabi or whatever city-value and call componentDidUpdate() to setState and re-render your component.
class HomeScreen extends React.Component{
state = {
abudhabi: false
}
//when the component gets the new redux state this will trigger
componentDidUpdate(prevProps){
if(this.props.abudhabi !== prevProps.abudhabi){
this.setState({
abudhabi: this.props.abudhabi
})
}
}
}
I am trying to pass the state to as props through mapStateToProps(), and even though the state change is being reflected in the state tree (redux tool inspector) and the 'data' being passed down as the action payload is successfully logging in the reducer.js, the state is not being passed down as props in my container.
my reducer.js:
import { fromJS } from 'immutable'
import { GOT_INDUSTRY_DATA } from './constants.js';
const initialState = fromJS({
data: []
})
function industryDataReducer(state = initialState, action){
switch (action.type) {
case GOT_INDUSTRY_DATA: {
const { data } = action
console.log('reducer data',data)
return state.set('data', fromJS(data))
}
default:
return state
}
}
export default industryDataReducer
in my container:
export class IndustryPage extends React.PureComponent {
render(){
const { data } = this.props
console.log(data)
return{
...
}
}
}
function mapStateToProps({data}) {
return {
data
}
}
const withConnect = connect(mapStateToProps, mapDispatchToProps)
const withSaga = injectSaga({ key: 'industry', saga })
const withReducer = injectReducer({ key: 'industry', reducer })
export default compose (
withStyles(styles),
withSaga,
withReducer,
withConnect
)(IndustryPage);
I have this error:
TypeError: Cannot read property 'map' of undefined
And don't know how can this.props.movies be undefined while I have initialState declared as [] and then it must straightly go to render?
So there are files:
Reducer.js
import * as types from "./ActionTypes.js";
const initialState = { movies: [] };
export const reducer = (state = initialState, action) => {
console.log(state.movies);
switch (action.type) {
case types.GET_MOVIES:
return {
...state,
movies: action.value
};
default:
return state;
}
};
Movies.js
import React, { Component } from "react";
import { connect } from "react-redux";
import MovieItem from "./MovieItem";
const mapStateToProps = state => ({
movies: state.movies
});
class Movies extends Component {
render() {
let movieItems = this.props.movies.map(movie => {
return <MovieItem movie={movie} />;
});
return <div className="Movies">{movieItems}</div>;
}
}
export default connect(mapStateToProps, null)(Movies);
And even if I put if-statement like
if (this.props.movies){
...
}else return 1;
it never rerenders
It should be:
const mapStateToProps = state => ({
movies: state.reducer.movies
});
Because your initial state is a object:
initialState = { movies: [] };
And you are using combineReducers like this:
const rootReducer = combineReducers({ reducer: reducer });
Now all the initialState of that reducer will be accessible by state.reducer.propertyName.
Note: Instead of using reducer, better to use some intuitive name like moviesReducer. Later in future if you will add more reducers then it will help to identify the the data.
I am trying to implement auth (sign up/out) using React + Redux (SSR and Thunks). I have no idea why components are not updatating when Redux state updates...
This is the component that should get rerendered:
class Navbar extends React.Component {
constructor(props) {
super(props);
this.state = {
loggedIn: props.authentication.loggedIn
};
}
render() {
let links = null;
if (this.state.loggedIn) {
links = ...
} else {
links = ...
}
return (<Toolbar>{links}</Toolbar>)
}
}
const mapStateToProps = state => {
return {
authentication: state.authentication
}
}
const mapDispatchToProps = dispatch => {
return {
signOut: () => {dispatch(userActions.logout())}
}
}
const AuthNavbar = connect(mapStateToProps, mapDispatchToProps)(Navbar)
export default AuthNavbar;
And that is my reducer:
const reducers = {
authentication,
registration,
alert
}
const todoApp = combineReducers(reducers)
export default todoApp
Authentication reducer:
const authentication = (state = initialState, action) => {
switch (action.type) {
...
case userConstants.LOGIN_SUCCESS:
return Object.assign({}, state, {
loggedIn: true,
loggingIn: false,
user: action.user
});
...
default:
return state;
}
}
And The Action - Login:
function login(email, password) {
return dispatch => {
dispatch({type: userConstants.LOGIN_REQUEST, email});
userService.login(email, password).then(
user => {
dispatch({type: userConstants.LOGIN_SUCCESS, user});
},
error => {
dispatch({ type: userConstants.LOGIN_FAILURE });
dispatch({type: alertActions.error(error)});
}
);
}
}
UserService.login is a function that calls and api witch fetch.
Looks like Action gets fired as it should, Redux state gets updated, but the component does not update:
Double checked Redux Dev Tools - state does get updated, so there must be a problem with the way I am using connect utilities?
You are storing the logedin props in the state inside the constructor, which will run only once in the life time of the component.
When a new prop is coming back you are not updating the state.
Either use the props directly:
if (this.props.authentication.loggedIn) {
links = ...
Or update the state in componentWillReceiveProps
componentWillReceiveProps(nextProps){
// update the state with the new props
this.setState({
loggedIn: nextProps.authentication.loggedIn
});
}
Your render function is dependent on state.loggedIn, but state.loggedIn is not changing; only this.props.authentication.loggedIn is changing in response to the action. Your component, in its current form, does not need state. You can remove it to make this work:
class Navbar extends React.Component {
render() {
let links = null;
if (this.props.authentication.loggedIn) {
links = ...
} else {
links = ...
}
return (<Toolbar>{links}</Toolbar>)
}
}
Ok this is bugging me! In react I had a Test component receiving props to create its initial state, like so:
constructor(props) {
super(props)
const {items} = this.props
this.state = {
items: {...items},
score: 0
}
}
The items passed to it (which become part of the state) are items to test - it starts removing those items when they have been tested on until state.items is empty - wherein the test is completed.
Trying to do this in redux, I have the following reducer:
import * as types from '../actions/action-types'
import Store from '../Store'
const initialState = {
items: {},// I want items to contain the props passed to this component
score: 0
}
const testWrapperReducer = function(state = initialState, action) {
let newState = null
switch(action.type) {
case types.QUESTION_ANSWERED: {
let {items, score} = state
delete items[action.english]
score += action.isCorrect
newState = {...state, items, score}
break
}
default:
newState = state
}
return newState
}
export default testWrapperReducer
How do I set initialState here, using the props given to the test component by its parent? Or is there a better way to do this?
Cheers!
I wouldn't be sendind the items as props from the father, instead i'd send the items from the father to redux and use the connect to receive them in the son.
Code explanation:
- You receive props in the constructor,
- Send items to redux using an action
- Receive them as props
- use the props to render the items
import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions';
const Item = (props) => {
<div>{props.item.name}</div>
}
class List extends React.Component {
constructor(props) {
super(props)
this.props.setItems(this.props.items)
}
render() {
return (
<div>
{this.props.items.map((item) => {
return <Item item={item}></Item>
})}
</div>
)
}
}
CreateChat.propTypes = {
items: PropTypes.array,
setItems: PropTypes.func
};
const mapStateToProps = (state) => {
return {
items: state.items
};
};
const mapDispatchToProps = (dispatch) => {
return {
setItems: (items) => dispatch(actions.setItems(items))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(List);