I am trying to setup a loader. But the code is never going through the if blocks.
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import LoadingPage from './LoadingPage';
import { usersFetchData, addFollower, addFollowing, removeFollower,
removeFollowing, resetUser} from '../actions/users';
class UserProfile extends React.Component{
constructor(props){
super(props);
this.state = {
isFollowed: false,
content: undefined
}
}
componentDidMount(){
this.props.fetchData(`http://localhost:5000/api/user/
${this.props.match.params.uid}`);
(Object.keys(this.props.user).length !== 0) &&
(this.props.user.followers.includes(this.props.currentUser.uid)) &&
this.setState({isFollowed: true});
}
openContentModal = (post) => {
this.setState({content:post});
console.log(this.state);
}
closeContentModal = () =>{
this.setState(() => ({ content: undefined }));
console.log(this.state);
}
render(){
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
console.log('loading...');
return <LoadingPage />;
}
console.log(this.props.isLoading);
return(
<div className="userProfile">
<div>
{console.log(this.props.user)}
{ Object.keys(this.props.user).length !== 0 &&
<div className="user__details">
<div className="user__dp">
<div className="dp__container">
<img src={this.props.user.avatar} alt=
{this.props.user.name}/>
</div>
</div>
<div className="user__description">
<p className="user__name">
{this.props.user.name}</p>
<div className="user__button">
{(this.props.currentUser.uid ===
this.props.user.uid) ?
</div>
</div>
</div>
}
</div>
<div className="user__bio">
<p>{this.props.user.bio}</p>
</div>
<div>
{/* <h3>Posts</h3> */}
<div className="userContent">
{this.props.user.posts &&
this.props.user.posts.map((post) =>{
return(
<div className="userPost">
<Link to=
{`/p/${this.props.user.name}/${post._id}`}>
<img src={post.content}/></Link>
</div>
);
})
}
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state) =>{
console.log(state.usersIsLoading); //getting undefined
return{
currentUser: state.auth,
user: state.users,
hasErrored: state.usersHasErrored,
isLoading: state.usersIsLoading
}
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(usersFetchData(url))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);
Action
export const userIsLoading = (bool) => ({
type: 'USER_IS_LOADING',
isLoading: bool
});
export const usersFetchDataSuccess = (users) => ({
type: 'USERS_FETCH_DATA_SUCCESS',
users
});
export const usersFetchData = (url) => {
return (dispatch) => {
dispatch(userIsLoading(true));
console.log('hi');
axios
.get(url)
.then(res => {
if(!res){
throw Error(res.statusText)
}
dispatch(userIsLoading(false));
console.log(res.data);
return res.data;
})
.then(users => {
console.log('users',users);
dispatch(usersFetchDataSuccess(users))
})
.catch(() => dispatch(userHasErrored(true)));
}
}
reducer
export const userIsLoading = (state = false, action) => {
switch (action.type) {
case 'USER_IS_LOADING':{
return action.isLoading;
}
default:
return state;
}
}
export const users = (state = {}, action) => {
switch (action.type) {
case 'USERS_FETCH_DATA_SUCCESS':{
return action.users;
}
i have consoled the state. then i am getting a valid boolean value from userIsLoading. But when i am consoling the state.userIsLoading, I am getting undefined. This is very peculiar.can anyone tell me where am i getting it wrong?
Related
I am learning React/Redux and I am trying to refactor this code from class-based to functional/hooks-based code. The application is an exercise I am working on, it has three components Posts.js where I fetch a list of posts from typicode.com. Each post from the fetched list has a button attacked.
On onClick, it should show details for each post (PostDetails.js and Comments.js):
At the moment, both Posts and Comments are class-based components. I need to:
Step 1: Change them to be functional components and use React Hooks but still keep connect(), mapStateToProps and mapDispatchToProps;
Step 2: Implement React-Redux hooks (UseSelector, useDispatch)
App.js
//imports...
const App = () => {
return (
<div className="container">
<div><Posts /></div>
<div><PostDetails /></div>
</div>
)
}
export default App;
actions
import jsonPlaceholder from '../apis/jsonPlaceholder';
export const fetchPosts = () => async dispatch => {
const response = await jsonPlaceholder.get('/posts');
dispatch({type: 'FETCH_POSTS', payload: response.data})
};
export const selectPost = post => {
return ({
type: 'POST_SELECTED',
payload: post
})
}
export const fetchComments = (id) => async dispatch => {
const response = await jsonPlaceholder.get(`/comments?postId=${id}`);
dispatch({type: 'FETCH_COMMENTS', payload: response.data})
}
reducers
export default (state = [], action) => {
switch (action.type) {
case 'FETCH_POSTS':
return action.payload;
default:
return state;
}
}
export default (selectedPost = null, action) => {
if (action.type === 'POST_SELECTED') {
return action.payload;
}
return selectedPost;
}
export default (state = [], action) => {
switch (action.type) {
case 'FETCH_COMMENTS':
return action.payload;
default:
return state;
}
}
export default combineReducers({
posts: postsReducer,
selectedPost: selectedPostReducer,
comments: commentsReducer
})
components/Posts.js
import React from 'react';
import { connect } from 'react-redux';
import { fetchPosts, selectPost } from '../actions';
import '../styles/posts.scss';
class Posts extends React.Component {
componentDidMount() {
this.props.fetchPosts()
}
renderPosts() {
return this.props.posts.map(post => {
if (post.id <= 10)
return (
<div className='item' key={post.id}>
<div className="title">
<h4>{post.title}</h4>
</div>
<button
onClick={() => {
this.props.selectPost(post)
console.log(post)
}
}>Open</button>
<hr/>
</div>
)
})
}
render() {
return(
<div className="list">
{ this.renderPosts() }
</div>
)
}
}
const mapStateToProps = state => {
return {
posts: state.posts,
selectedPost: state.post
}
};
const mapDispatchToProps = {
fetchPosts,
selectPost
}
export default connect(mapStateToProps, mapDispatchToProps)(Posts);
components/PostDetails.js
import React from 'react';
import { connect } from 'react-redux';
import Comments from './Comments'
const PostDetails = ({ post }) => {
if (!post) {
return <div>Select a post</div>
}
return (
<div className="post-details">
<div className="post-content">
<h3>{post.title}</h3>
<p>{post.body}</p>
<hr/>
</div>
<div className="comments-detail">
<Comments postId={post.id}/>
</div>
</div>
)
}
const mapStateToProps = state => {
return {post: state.selectedPost}
}
export default connect(mapStateToProps)(PostDetails);
components/Comments.js
import React from 'react';
import { connect } from 'react-redux';
import { fetchComments } from '../actions'
class Comments extends React.Component {
componentDidUpdate(prevProps) {
if (this.props.postId && this.props.postId !== prevProps.postId){
this.props.fetchComments(this.props.postId)
}
}
renderComments() {
console.log(this.props.comments)
return this.props.comments.map(comment => {
return (
<div className="comment" key={comment.id}>
<div className="content">
<h5>{comment.name}</h5>
<p>{comment.body}</p>
</div>
<hr />
</div>
)
})
}
render() {
return (
<div className="comments">
{this.renderComments()}
</div>
)
}
}
const mapStateToProps = state => {
return {comments: state.comments}
}
export default connect(mapStateToProps, {fetchComments})(Comments);
This could be a way to create Posts component:
I am assuming that when you dispatch fetchPosts() action, you are saving its response using reducers in Redux.
And, you don't need fetchedPosts in local component state as you already have this data in your Redux state.
const Posts = () => {
const posts = useSelector((state) => state.posts)
const dispatch = useDispatch()
// const [fetchedPosts, setFetchedPosts] = useState([]) // NOT needed
useEffect(() => {
dispatch(fetchPosts())
// setFetchedPosts(posts) // NOT needed
// console.log(posts) // NOT needed, its value may confuse you
}, [])
// Do this, if you want to see `posts` in browser log
useEffect(() => {
console.log(posts)
}, [posts])
/* NOT needed
const renderPosts = () => {
posts.map((post) => {
console.log(post)
})
} */
return (
<>
{posts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</>
)
}
export default Posts
I'm having some problems with deleting the post in my app. So, after deleting the post, the state should update and the component should re-render, right? So, after deleting my post, component re-renders with the same data. If I refresh, then only the updated data is shown on the page. For example, if I have 3 posts in my app when I delete ONE post, the component re-renders, but still it shows 3 posts. I don't know why this is happening.
Here's my code.
UserFeed
import React, { Component } from "react"
import { getUserPosts, getCurrentUser } from "../actions/userActions"
import { connect } from "react-redux"
import Cards from "./Cards"
class UserFeed extends Component {
componentDidMount() {
const authToken = localStorage.getItem("authToken")
if (authToken) {
this.props.dispatch(getCurrentUser(authToken))
if (this.props && this.props.userId) {
this.props.dispatch(getUserPosts(this.props.userId))
} else {
return null
}
}
}
render() {
console.log("render called")
const { isFetchingUserPosts, userPosts } = this.props
console.log(isFetchingUserPosts, userPosts)
return isFetchingUserPosts ? (
<p>Fetching....</p>
) : (
<div>
{userPosts &&
userPosts.map(post => {
return <Cards key={post._id} post={post} />
})}
</div>
)
}
}
const mapStateToPros = state => {
return {
isFetchingUserPosts: state.userPosts.isFetchingUserPosts,
userPosts: state.userPosts.userPosts.userPosts,
userId: state.auth.user._id
}
}
export default connect(mapStateToPros)(UserFeed)
Cards
import React, { Component } from "react"
import { connect } from "react-redux"
import { deletePost } from "../actions/userActions"
class Cards extends Component {
handleDelete = (_id) => {
this.props.dispatch(deletePost(_id))
}
render() {
const { _id, title, description } = this.props.post
return (
<div className="card">
<div className="card-content">
<div className="media">
<div className="media-left">
<figure className="image is-48x48">
<img
src="https://bulma.io/images/placeholders/96x96.png"
alt="Placeholder image"
/>
</figure>
</div>
<div className="media-content" style={{border: "1px grey"}}>
<p className="title is-5">{title}</p>
<p className="content">{description}</p>
<button onClick={() => {this.handleDelete(_id)}} className="button is-success">Delete</button>
</div>
</div>
</div>
</div>
)
}
}
const mapStateToProps = state => {
return state
}
export default compose(withRouter, connect(mapStateToProps))(Cards)
deletePost action
export const deletePost = (id) => {
return async dispatch => {
dispatch({ type: "DELETING_POST_START" })
try {
const res = await axios.delete(`http://localhost:3000/api/v1/posts/${id}/delete`)
dispatch({
type: "DELETING_POST_SUCCESS",
data: res.data
})
} catch(error) {
dispatch({
type: "DELETING_POST_FAILURE",
data: { error: "Something went wrong" }
})
}
}
}
userPosts reducer
const initialState = {
isFetchingUserPosts: null,
isFetchedUserPosts: null,
userPosts: [],
fetchingUserPostsError: null,
isDeletingPost: false,
isDeletedPost: false,
deletingError: false,
}
const userPosts = (state = initialState, action) => {
switch (action.type) {
case "FETCHING_USER_POSTS_START":
return {
...state,
isFetchingUserPosts: true,
fetchingUserPostsError: null,
}
case "FETCHING_USER_POSTS_SUCCESS":
return {
...state,
isFetchingUserPosts: false,
isFetchedUserPosts: true,
userPosts: action.data,
fetchingUserPostsError: null,
}
case "FETCHING_USER_POSTS_ERROR":
return {
...state,
isFetchingUserPosts: false,
isFetchedUserPosts: false,
fetchingUserPostsError: action.data.error,
}
case "DELETING_POST_START":
return {
...state,
isDeletingPost: true,
deletingError: null,
}
case "DELETING_POST_SUCCESS":
const filteredPostList = state.postList.filter((post) => post._id !== action.data._id)
return {
...state,
isDeletingPost: false,
isDeletedPost: true,
userPosts: filteredPostList,
deletingError: null,
}
case "DELETING_POST_ERROR":
return {
...state,
isDeletingPost: false,
deletingError: action.data.error,
}
default:
return state
}
}
export default userPosts
Delete post action needs to pass on id to the reducer upon success.
Delete post action
export const deletePost = (id) => {
return async dispatch => {
dispatch({ type: "DELETING_POST_START" })
try {
const res = await axios.delete(`http://localhost:3000/api/v1/posts/${id}/delete`)
dispatch({
type: "DELETING_POST_SUCCESS",
data: res.data,
id
})
} catch(error) {
dispatch({
type: "DELETING_POST_FAILURE",
data: { error: "Something went wrong" }
})
}
}
}
Access action.id in user posts reducer
case "DELETING_POST_SUCCESS":
return {
...state,
isDeletingPost: false,
isDeletedPost: true,
userPosts: state.postList.filter(post => post._id !== action.id),
deletingError: null,
}
I am having trouble passing an object from the Parent to Child component.
I have read various similar posts but none of the solutions did work.
Error message: TypeError: Cannot read property 'map' of undefined
Parent: (App.js)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchData } from '../actions/actions';
class App extends Component {
constructor(props) {
super(props);
this.state = {
filter: "",
data: [],
filteredData: []
};
}
componentDidMount() {
this.props.dispatch(fetchData());
};
render() {
const { filter, data } = this.state;
const lowercasedFilter = filter.toLowerCase();
const filteredData = data.filter(item => {
return Object.keys(item).some(key =>
item[key].toString().toLowerCase().includes(lowercasedFilter)
);
});
return (
<div>
<UserList filteredData={filteredData}/>
{console.log(this.props.myData.Brastlewark)}
</div>
);
}
}
const mapStateToProps = ({ things: { myData, isFetching } }) => ({
myData,
isFetching
});
export default connect(mapStateToProps)(App);
Child: (Userlist.js)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchData } from '../actions/actions';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../layout.css'
class UserList extends Component {
constructor(props) {
super(props);
this.state = {
filter: "",
data: [],
filteredData: {}
};
}
componentDidMount() {
this.props.dispatch(fetchData());
};
handleChange = event => {
this.setState({ filter: event.target.value });
this.setState((state, props) => ({
data: this.props.myData.Brastlewark
}))
};
render() {
const {filteredData} = this.props;
return (
<div className="container-fluid">
<div className="jumbotron">
<h2>
<input value={this.props.filter} onChange={this.handleChange} placeholder="please search" />
</h2>
{!this.props.isFetching && <div> You may start searching for Orcs in the vilage by typing into the search box above. </div>}
</div>
<div className="container">
<div className="row">
{filteredData.map(item => (
<div className="col-md-4 col-xs-6" key={item.id}>
<div className="card">
<img className="card-img-top img-fluid" src={item.thumbnail} alt={item.age}/>
<div className="card-block">
<h5 className="card-title">{item.professions.toString().split(', ')}</h5>
<p className="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
<p className="card-text"><small className="text-muted">Last updated 1 sec ago</small></p>
</div>
</div>
</div>
))}
</div>
</div>
{console.log(this.props.myData.Brastlewark)}
</div>
);
}
}
const mapStateToProps = ({ things: { myData, isFetching } }) => ({
myData,
isFetching
});
export default connect(mapStateToProps)(UserList);
Action.js
export const REQUEST_DATA = 'REQUEST_DATA'; // action to represent waiting for response
export const GET_DATA_FIRST = 'GET_DATA_FIRST'; // action to represent receiving of data
export const requestData = () => ({ type: REQUEST_DATA });
export const getDataFirst = myData => ({ type: GET_DATA_FIRST, myData });
export const fetchData = () => dispatch => {
dispatch(requestData());
return getData().then(things => {
// simulated delay
setTimeout(() => {
return dispatch(getDataFirst(things))
}, 1000);
});
};
const getData = async () => {
const res = await fetch('https://raw.githubusercontent.com/rrafols/mobile_test/master/data.json');
return await res.json();
}
Reducer (reducer.js)
import { combineReducers } from 'redux';
import { GET_DATA_FIRST, REQUEST_DATA } from '../actions/actions';
const initialState = {
isFetching: false,
myData: []
};
const things = (state = initialState, action) => {
switch (action.type) {
case REQUEST_DATA:
return {
...state,
isFetching: true
};
case GET_DATA_FIRST:
return {
...state,
isFetching: false,
myData: action.myData
};
default:
return state;
}
};
const rootReducer = combineReducers({
things // this key can be called anything, 'things' is just an example
});
export default rootReducer;
Perhaps somebody could help me converting this part to redux or just the simplest way, getting filtedData defined by input text?
Thanks in advance
The problem is probably that the .map function is running before the data is passed. This error usually appears when you try to go through an undefined object.
Try this code:
<div className="row">
{filteredData && filteredData.map(item => (
// do stuff with your item
))}
</div>
Mentioning the name of a variable before actually doing something with it checks whether is is undefined/null or not. If it's not, it will go on and do what you have programmed it to do.
I have to set a value on from a API into a newly created <button> component handled by Redux, but I don't know if I can use setState for this. I created a reducer and an action SET_VOTE_COUNT but I'm not seeing how this is done. This is my first Redux project, so here is the code:
// ./src/js/components/CounterList.js
import React from 'react';
import { connect } from 'react-redux';
import { increment, decrement } from '../actions/reducer';
import Counter from './Counter';
const CounterList = ({
counters,
onIncrement,
onDecrement
}) => (
<ul>
{counters.map(counter =>
<Counter style={{div: "voting"}}
key={counter.id}
value={counter.count}
onIncrement={() => onIncrement(counter.id)}
onDecrement={() => onDecrement(counter.id)}
/>
)}
</ul>
);
const mapStateToProps = (state) => {
return {
counters: state
};
};
const mapDispatchToProps = (dispatch) => {
return {
onIncrement: (id) => dispatch(increment(id)),
onDecrement: (id) => dispatch(decrement(id))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(CounterList);
// ./src/js/components/Counter.js
import React, { Component } from 'react';
class Counter extends Component {
render() {
return (
<div className="voting">
<span>{this.props.value}</span>
<button
onClick={() => this.props.onIncrement()}>
+
</button>
<button
onClick={() => this.props.onDecrement()}>
-
</button>
</div>
);
}
}
export default Counter;
import React, {Component} from 'react';
import logo from '../../logo.svg';
import '../../App.css';
import AddButton from './AddButton'
class Posts extends Component {
constructor(props) {
super(props);
this.state = {
response: ''
};
}
componentDidMount() {
fetch(
"/posts"
).then(response => response.json())
.then(data => this.setState({ response: data }))
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
{Array.isArray(this.state.response) &&
this.state.response.map(resIndex => <>
{ resIndex.voteScore}
<AddButton className="voting"/>
<p> { resIndex.title }, by { resIndex.author } </p>
<p> { resIndex.body } </p>
<p> {resIndex.category} </p>
</>
)}
</header>
</div>
)
}
}
export default Posts;
import React from 'react';
import { add_counter, setVoteCount } from '../actions/reducer';
import { connect } from 'react-redux';
const AddButton = ({dispatch}) => (
<div className="voting">
<button
onClick={() => {
dispatch(setVoteCount())
// dispatch(add_counter());
}}>
Vote
</button>
</div>
);
export default connect()(AddButton);
The reducer:
// ./src/js/actions/counters.js
export const setVoteCount = (id) => {
return {
type: "SET_VOTE_COUNT",
id
};
}
export const increment = (id) => {
return {
type: "INCREMENT",
id
};
};
export const decrement = (id) => {
return {
type: "DECREMENT",
id
};
};
export const add_counter = () => {
return {
type: "ADD_COUNTER"
};
};
store action:
import { createStore, applyMiddleware, compose } from 'redux';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const change_counter = (state = {}, action) => {
switch (action.type) {
case "SET_VOTE_COUNT":
if (state.id !== action.id) {
return state;
}
return {
...state,
count : 37
}
case "INCREMENT":
if (state.id !== action.id) {
return state;
}
return {
...state,
count: state.count+1
};
case "DECREMENT":
if (state.id !== action.id) {
return state;
}
return {
...state,
count: state.count - 1
};
default:
return state;
}
};
let nextId = 0;
const counters = (state = [], action) => {
switch (action.type) {
case "ADD_COUNTER":
return [...state, {id: nextId++, count: 0}];
case "SET_VOTE_COUNT":
return [...state, {id: nextId++, count: action.count}];
case "INCREMENT":
return state.map(counter => change_counter(counter, action));
case "DECREMENT":
return state.map(counter => change_counter(counter, action));
default:
return state;
}
}
export default createStore(counters, composeEnhancers(applyMiddleware()));
I can upload it to GitHub if necessary. Many thanks.
In the AddButton component,the actions should be wrapped in mapDispatchToProps and passed to the connect function. You are calling the raw action in your example, but you need to wrap it with dispatch for it to update the store.
However, I'm not sure what you are trying to update the store with exactly. The action payload is empty in your example, and the reducer has 37 hardcoded as the state.count in response the SET_VOTE_COUNT action type. Did you mean to pass something from the API response?
<AddButton count={resIndex.count} className="voting"/>
import React from 'react';
import { add_counter, setVoteCount } from '../actions/reducer';
import { connect } from 'react-redux';
const mapDispatchToProps = {
setVoteCount
};
const AddButton = props => (
<div className="voting">
<button onClick={() => {
props.setVoteCount(props.count);
}}>
Vote
</button>
</div>
);
export default connect(null, mapDispatchToProps)(AddButton);
When I try to access this.props.username in:
loginClick = (event) => {
event.preventDefault();
console.log('Login submit click, props.username: ' + this.props.username);
this.props.loginDispatch(this.props.username);
}
I get undefined.
Can you tell me what I'm missing?
Reducer:
import { fromJS } from 'immutable';
import { DEFAULT_ACTION, SET_USERNAME } from './constants';
const initialStateMutable = {
username: ''
};
const initialState = fromJS(initialStateMutable);
function loginReducer(state = initialState, action) {
switch (action.type) {
case DEFAULT_ACTION:
return state;
case SET_USERNAME:
console.log('reducer state.username value: ' + state.username);
return {
...state,
username: action.username
};
default:
return state;
}
}
Action:
import { LOGIN_SUBMIT, SET_USERNAME } from './constants';
export const loginDispatch = (name) => ({
type: LOGIN_SUBMIT,
name,
});
export const setUsername = (username) => {
return {
type: SET_USERNAME,
username,
};
};
Selector:
import { createSelector } from 'reselect';
const selectLoginPageDomain = () => (state) => state.get('loginPage');
const makeSelectLoginPage = () => createSelector(
selectLoginPageDomain(),
(substate) => substate.toJS()
);
export default makeSelectLoginPage;
export {
selectLoginPageDomain,
};
index.tsx:
import makeSelectLoginPage from './selector';
import * as React from 'react';
import { loginDispatch, setUsername } from './actions';
import { connect } from 'react-redux';
interface ILoginProps {
loginDispatch: Function;
setUsername: Function;
username: string;
}
interface ILoginState {
}
class LoginPage extends React.Component<ILoginProps, ILoginState> {
constructor(props, context) {
super(props, context);
}
updateInputValue = (event) => {
event.preventDefault();
console.log('Current value of props.username: ' + this.props.username);
this.props.setUsername(event.target.value);
}
loginClick = (event) => {
event.preventDefault();
console.log('Login submit click, props.username: ' + this.props.username);
this.props.loginDispatch(this.props.username);
}
render() {
return (
<div>
<div className="row">
<div className="col-xs-12">
<div className="card">
<div className="card-inside">
<div className="alignc">
<form onSubmit={this.loginClick} className="row">
<div>
<div className="alignl">
Enter username for calculation history.
</div>
<div>
<input type="text" value={this.props.username} onChange={this.updateInputValue}/>
</div>
<button type="submit" value="Submit">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
...state,
username: state.username,
...makeSelectLoginPage()(state),
});
const mapDispatchToProps = (dispatch) => ({
dispatch,
setUsername: (value: string) => dispatch(setUsername(value)),
loginDispatch: (name: string) => dispatch(loginDispatch(name)),
});
export default connect(mapStateToProps, mapDispatchToProps)(LoginPage);
UPDATE:
I just realized I'm getting this error from the selector:
Uncaught TypeError: substate.toJS is not a function
at eval (eval at ./app/containers/Login/selector.ts
state is an immutable variable. Try this :
const mapStateToProps = (state) => ({
...state.toJS(),
username: state.get('username'),
...makeSelectLoginPage()(state),
});