I am new in React. As I read many documents, I realized that the state of the application should managed outside each components. And I choose Redux for my project.And I tried to pass username and password from my SigIn component. But when I click on the login button , the default statement inside the switch is always executed.The code are given below.
SignIn.jsis as below
import React from 'react';
import Header from './Head.js';
import { logIn } from '../actions/index.js';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
class SignIn extends React.Component{
constructor(){
super();
this.logInClick = this.logInClick.bind(this);
}
logInClick() {
let { dispatch } = this.props;
const data = {username:'sojimon#gmail.com', password:'12345'}
// this.props.logIn(data);
this.props.dispatch(logIn(data));
}
render(){
return(
<div>
<Header/>
<br/>
<div className="col-md-4 col-md-offset-4">
<div className="well">
<h4 className="signin_header">Sign In</h4>
<div>
<div>
<label>Email:</label>
<input type="text" className="form-control" />
</div>
<div>
<label>Password:</label>
<input type="text" className="form-control"/>
</div>
<br/>
<button className="btn btn-primary" onClick={ this.logInClick }>Login</button>
</div>
</div>
</div>
</div>
)
}
}
const matchDispatchToProps = (dispatch) => ({
// logIn: (data) => dispatch(logIn(data)),
})
SignIn.propTypes = {
logIn: React.PropTypes.func
}
export default connect (matchDispatchToProps)(SignIn);
And my action/index.js as follows,
import * as types from './types.js';
export const logIn = (state, data) => {
return {
type: types.LOG_IN,
state
}
}
And reducers/logIn.js is,
import React from 'react';
import { LOG_IN } from '../actions/types.js'
const logIn = (state = [], action) => {
switch (action.type) {
case 'LOG_IN':
console.log('switch Case ==> LOG_IN');
return [
...state,
{
username: 'asdf',
password: '123',
}
]
// return action.logIn
default:
console.log('switch Case ==> Default');
return state
}
}
export default logIn
And created store in index.js file as,
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app/App';
import './app/index.css';
import Routes from './app/route';
import { createStore } from 'redux' // import store
import { Provider } from 'react-redux' // import provider
import myApp from './app/reducers/index.js'
let store = createStore(myApp);
ReactDOM.render(
<Provider store={store}>
<Routes />
</Provider>,
document.getElementById('root')
);
export default store;
Related
I am learning react-redux, I couldn't understand what problem occuring when I wrap App component with Provider.
Error: Invalid Hook Call
https://i.stack.imgur.com/yFSnF.png
But If I don't wrap it's OK.
Now, My question is what's the mistake in my code?
Root Component:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import App from './components/App';
import reducers from './reducers';
const store = createStore(reducers);
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>
,
document.getElementById('root')
);
App Component:
import React from 'react';
import SongList from './songList';
const App = ()=>{
return (
<div>
<SongList />
</div>
);
};
export default App;
SongList Component:
import React from 'react';
class SongList extends React.Component{
render(){
return(
<div className='ui divided list'>
<div className='ui header'>
<div className='title'>
Song List
</div>
</div>
<div className='ui button primary'>
Select
</div>
</div>
);
}
};
export default SongList;
Reducers:
import {combineReducers} from 'redux';
const songReducer = ()=>{
return [
{title:'Zikrullah', duration: 4.05},
{title: 'Madina', duration: 5.50},
{title: 'Sunnat', duration: 3.96},
{title: 'Mandatory', duration:5.16}
]
};
const selectedSongReducer = (selectedSong = null, action) => {
if(action.type === 'SONG_SELECTED'){
return action.payload;
}
return selectedSong;
};
export default combineReducers({songs: songReducer,
selectedSong: selectedSongReducer});
Action:
export const selectSong = (song)=> {
return {
type: 'SONG_SELECTED',
payload:song
};
};
I am trying to identify the wrong part of code for two days. I couldn't identify. Please, help me to solve the issue.
I am setting up React-Redux to my web application, I have been getting a Could not find "store" in the context of "Connect(Register)".
I figured maybe I would have to pass the store that I created in [[2]] store.js and it worked but I haven't seen it done this way online and when I tried using redux DevTools it kept showing no store found.
I thought the purpose of connect() was to wrap around the component and access the global state in redux via mapStateToProps. If someone could point me in the right direction or possibly explain why I am getting this error would great!
Something things I have tried:
Since I was had a container component LoginContainer.js (which I could access via connect()(LoginContainer) I thought I would able to access the state here and pass down the props to register.js component and then propagate up state changes.
I have been thinking of changing register.js to a functional component because maybe this may be affecting it somehow?
I have been reading about context and how by using <Provider store={store}> at the index.js it should have allowed access to the Redux store via connect(mapState,MapDispach)(Component) however I still cannot distinguish how or when I am losing to context to Provider.
//index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Provider } from "react-redux"
import { BrowserRouter, Route } from "react-router-dom";
import store from "./store";
ReactDOM.render(
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>,
document.getElementById("root")
);
// App.js
import React, { Component } from "react";
import {
Route,
Switch
} from "react-router-dom";
import LoginContainer from "./containers/login";
class App extends Component{
render() {
return (
<div className="App">
<header className="App-header">
<Switch>
<Route path='/login' component={LoginContainer} />
</Switch>
</header>
</div>
);
}
}
export default App;
// LoginContainer.js
import React, { Component } from "react";
import ReactDOM from "react-dom";
import Register from "../componets/Registration/register";
import Login from "../componets/Login/login";
import { withRouter } from "react-router-dom";
import { Input, Button } from "semantic-ui-react";
import { connect } from "react-redux";
import store from "../store";
class LoginContainer extends Component {
constructor(props) {
super(props);
this.state = {
//some local UI states
};
}
render() {
return (
<div>
<div className="ToggleContainer">
<div className={"toggle"}>
<Button.Group>
<Button
onClick={this.registerHandler}
positive={this.state.registerOn}
>
SignUp
</Button>
<Button.Or />
<Button onClick={this.loginHandler} positive={this.state.loginOn}>
Login
</Button>
</Button.Group>
</div>
<Provider store = {store}> <Register {...this.props} /> </Provider> // [[6]], uncommented [[4]] works but is it different than method [[1]]?
// <Register{...this.props} /> // [[2]] cannot connect to store
// <Register store={store} {...this.props} />} [[1]] can connect store via directly sending store //
</div>
</div>
);
}
}
// ReactDOM.render(<LoginContainer />, document.getElementById("root")); [[answer]] removing this fixed the problem
const mapStateToProps = state => {
return {
loggedIn: state.registration.isLoggedIn
};
};
const mapDisptachToProps = dispatch => ({
registerUser: id => dispatch({ type: "SIGN_IN" })
});
export default withRouter(
connect(
mapStateToProps,
mapDisptachToProps
)(LoginContainer)
);
//components/register.js
import React, { Component } from "react";
import { Input, Button } from "semantic-ui-react";
import { connect } from "react-redux";
class Register extends Component {
constructor(props) {
super(props);
// Local State
}
const check() {
let userData: User;
if (validEmail(this.state.email)) {
userData = {
//data
};
let user = await this.handleSignUp(userData);
const res = JSON.parse(user);
if (res.message === "Success") {
alert('Account success')
}
if(typeof user === 'string'){
user =JSON.parse(user)
}
} else {
this.setState({ hiddenErrorMessage: false });
}
this.props.registerUser(userData);
// func: returns true if it is valid, o.w. false
function validEmail(email) {
}
};
//handlers()
render() {
return (
// eslint-disable-next-line react/jsx-filename-extension
<div>
<Input
className="customInput"
onChange={this.handleEmail}
placeholder="Email"
/>
<Input
className="customInput"
onChange={this.handlePassword}
placeholder="Password"
type="password"
/>
<br />
<Button
size="big"
className="customButton"
onClick={this.checkUserInput}
>
Sign up
</Button>
<p>
<span hidden={this.state.hiddenErrorMessage}>
Invalid Email/Passoword
</span>
</p>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
loggedIn:state.registration.isLoggedIn
}
};
const mapDisptachToProps = dispatch => ({
registerUser: id => dispatch({ type: "SIGN_IN" }) // return dispatch
});
export default Register // [[3]] Works as expected
// export default connect( [[4]] Could not find "store" in the context of "Connect(Register)". Either wrap the root component in a <Provider> Error
// mapStateToProps,
// mapDisptachToProps
// )(Register);
//store.js
import { createStore } from "redux";
import rootReducer from './reducers';
export default createStore(rootReducer);
//reducers/index.js
import { combineReducers } from "redux";
import registration from "./registration";
export default combineReducers({ registration });
//actionType.js
const SIGN_IN = 'SIGN_IN';
export { SIGN_IN };
//reducers/registration.js
const initialState = {
isAuthenticated: false,
isLoggedIn: false,
isLoggedOut: false,
userId : ''
};
export default (state = initialState, action) => {
if (action.type === "SIGN_IN") {
return { ...state, isLoggedIn: true };
}
if (action.type === "SIGN_OUT") {
return { ...state, isLoggedOut: true };
}
return state;
};
Solution to this problem was removing the next code from the LogainContainer:
ReactDOM.render(<LoginContainer />, document.getElementById("root"));
My state is changing as I can see in console but my Book component is not refreshed on state change. I have two containers/components in my app. BookList that renders the list of all available books. Book component just gets the activeBook and display its details. I am facing the rerender issue on Book Component.
import React, {Component} from 'react';
import {connect} from 'react-redux';
class Book extends Component{
render(){
return(
<div className="col-md-9 details">
<h3>Title: {this.props.activeBook.name}</h3>
<p><b>Author:</b> {this.props.activeBook.author}</p>
<p><b>Pages:</b>{this.props.activeBook.pages}</p>
<p><b>Available:</b>{this.props.activeBook.aval}</p>
{console.log(this.props)}
</div>
);
}
}
const mapStateToProps = (state) =>{
return {
activeBook: state.active
}
}
export default connect(mapStateToProps)(Book);
My BookList Component is as following
import React, {Component} from 'react';
import {connect} from 'react-redux';
class BookList extends Component{
renderList(){
return this.props.books.map((book)=>{
return(
<li
key={book.id}
onClick={() => this.props.dispatch({type:'CHANGED',activeBook:book})}
className="list-group-item">
{book.name}
</li>
);
});
}
render(){
return(
<div className="col-md-3">
<ul className='list-group'>
{this.renderList()}
</ul>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
books:state.books
}
}
export default connect(mapStateToProps)(BookList);
My App.js is as follows:-
import React, { Component } from 'react';
//Import All Components Here
import BookList from './containers/BookList';
import Book from './components/Book';
class App extends Component {
render() {
return (
<div className="container">
<div className="App">
<div className="row">
<BookList/>
<Book/>
</div>
</div>
</div>
);
}
}
export default App;
and lastly my bookReducer is as follows:-
const bookReducer = (state = [], action) => {
switch(action.type){
case 'CHANGED':
state.active=action.activeBook;
return state;
default:
return state;
}
}
export default bookReducer;
I can exactly see in my console that State is being changed, but problem is Book Container does not respond to that change. In index.js this is my code
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore} from 'redux';
import {Provider} from 'react-redux';
import 'bootstrap/dist/css/bootstrap.min.css';
import './index.css';
import App from './App';
import bookReducer from './reducers/bookReducer';
const initialState={
books:[
{id:1,name:'Learn Java', author:'Shakeel', pages:50,aval:'Yes'},
{id:2,name:'React Native', author:'Asim', pages:212,aval:'No'},
{id:3,name:'Angular JS', author:'Tahir', pages:150,aval:'Yes'},
{id:4,name:'NodeJS', author:'Saleem', pages:120,aval:'Yes'},
{id:5,name:'C++ for Games', author:'Shakeel', pages:140,aval:'Yes'}
],
active:{id:5,name:'C++ for Games', author:'Shakeel', pages:140,aval:'Yes'}
};
const store = createStore(bookReducer,initialState);
ReactDOM.render(<Provider store={store}>
<App /></Provider>,
document.getElementById('root'));
The way you are setting the state in reducer needs to change, try this change.
const bookReducer = (state = [], action) => {
switch(action.type){
case 'CHANGED':
return {
...state,
active : action.activeBook
}
default:
return state;
}
}
In my app, I have a state that save userData if the user is logged in, but and I want to redirect him to /dashboard/:id with it id. But when the action is completed, the url is good (e.g : /dashboard/12) but the view is style on /login component..
router version :
"react-router": "^3.2.0",
"react-router-dom": "^4.2.2"
Here is the code :
App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Login from './components/Login/Login';
import Register from './components/Register/Register';
import Dashboard from './components/Dashboard/Dashboard';
import './App.css';
class App extends Component {
render() {
return (
<Router>
<div>
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route path="/dashboard/:id" component={Dashboard} />
</div>
</Router>
);
}
}
export default App;
sessionReducer:
import * as types from '../actions/types';
import initialState from './initialState';
export default function sessionReducer(state = initialState, action) {
switch(action.type) {
case types.LOG_IN_SUCCESS:
console.log(action);
return {
...state,
userData: action.payload
}
case types.LOG_IN_FAILED:
console.log('login failed');
break;
default:
return state;
}
}
authAction.js :
import { browserHistory } from 'react-router';
import { Redirect } from 'react-router-dom'
import * as types from './types';
import sessionApi from '../api/SessionApi';
import history from '../history';
export function loginSuccess(userData) {
return {
type: types.LOG_IN_SUCCESS,
payload: userData
}
}
export function loginFailed() {
return {
type: types.LOG_IN_FAILED
}
}
export function logInUser(credentials) {
return function(dispatch) {
return sessionApi.login(credentials)
.then(response => {
console.log(response);
if(response.data) {
sessionStorage.setItem('jwt', response.data.authentication_token);
dispatch(loginSuccess(response.data));
history.push('/dashboard/' + response.data.id);
} else {
dispatch(loginFailed());
}
})
.catch(error => {
throw(error);
})
}
}
The dashboard.js :
import React, { Component } from 'react';
import { withRouter } from 'react-router';
import { connect } from 'react-redux';
class Dashboard extends Component {
constructor(props) {
super(props);
console.log(props);
}
componentWillReceiveProps() {
}
render() {
console.log(this.props.userData);
return(
<div>
<h1> Hello user </h1>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
userData: state.sessionReducer.userData
}
}
export default withRouter(connect(mapStateToProps)(Dashboard));
And the loginForm.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { bindActionCreators } from 'redux';
import { withRouter } from 'react-router';
import { connect } from 'react-redux';
import * as authActions from '../../actions/authActions';
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
errors: {},
isLoading: false,
};
}
onChange(e) {
this.setState({
[e.target.name]: e.target.value
})
}
onSubmit(e) {
e.preventDefault();
this.setState({ errors: {}, isLoading: true });
this.props.actions.logInUser( { data: { user: { email: this.state.email, password: this.state.password }}})
}
render() {
return(
<div>
<form onSubmit={this.onSubmit.bind(this)}>
<div className="field">
<label className="label"> Email </label>
<div className="control">
<input type="email"
name="email"
value={this.state.email}
onChange={this.onChange.bind(this)}
className="input" />
</div>
</div>
<div className="field">
<label className="label"> Mot de passe </label>
<div className="control">
<input type="password"
ref="password"
name="password"
value={this.state.password}
onChange={this.onChange.bind(this)}
className="input" />
</div>
</div>
<div className="form-group">
<input type="submit" value="Signup" className="button is-primary" />
</div>
<Link to={{ pathname: '/register' }}>Inscription</Link>
</form>
</div>
);
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(authActions, dispatch)
};
}
export default withRouter(connect(null, mapDispatchToProps)(LoginForm));
I just want to render the good component with the right view, does someone know why the Dashboard component doesn't render ?
EDIT
add index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { routerMiddleware } from 'react-router-redux'
import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from './reducer/rootReducer';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
/*
* CSS
*/
import './bulma.css';
import './index.css';
/*
* Render
*/
const store = createStore(
rootReducer,
compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'));
registerServiceWorker();
you must to use in router v4:
<BrowserRouter>
<Switch>
<Route exact path="/testcolors" component={TestColors} />
</Switch>
</BrowserRouter>
this.props.history.push('/customers');
i don't know what im doing wrong.
I thought i got the point how to implement with redux.
My Problem is that the state of the Component is not propagating to the Component after the state changed. I know we have to create new state object and i'm sure im doing it right. But there is no changes.
And the other question is, why the state is in the object "resetLink" see image. Why is it not stored in the state Object?
Please help me to get it work.
Action for the redux:
export const sendResetLink = (email) => {
return {
type: RESET_LINK,
email
}
}
class App extends React.Component {
render() {
return <VisibleResetLink/>
}
}
This is where the magic with props and dispatch function happens:
import {connect} from 'react-redux';
import SendResetLink from '../components/SendResetLink.jsx';
import {sendResetLink} from '../actions/index'
import _ from 'lodash';
const mapDispatchToProps = (dispatch) => {
return {
onClick: (email) => {
dispatch(sendResetLink(email))
}
}
}
const mapStateToProps = (state) => {
console.log("actual state", state);
return _.assign({} , {state: state.resetLink});
}
const VisibleResetLink = connect(
mapStateToProps,
mapDispatchToProps
)(SendResetLink)
export default VisibleResetLink
This is the Component which load props but never rerender them when they change.
import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
class SendResetLink extends React.Component {
constructor(props, email, result) {
super(props);
console.log('props',props);
this.onClick = props.onClick;
this.result = props.state.result;
this.input = props.state.email;
}
renderResult (result){
console.log("renderResult",result);
if(result)
return <div className="card-panel deep-orange lighten-4">Invalid username and password.</div>
}
render() {
return <div>
{this.renderResult(this.result)}
{this.result}
<form className="col s12" action="/login" method="post" onSubmit={e => {
e.preventDefault()
if (!this.input.value.trim()) {
return
}
this.onClick(this.input.value);
this.input.value = ''
} }>
<div className="row">
<div className="input-field col s12">
<i className="material-icons prefix">email</i>
<input id="email" type="email" name="email" className="validate" ref = {(node) => this.input = node } />
<label for="email">Email</label>
</div>
</div>
<div className="divider"></div>
<div className="row">
<div className="col m12">
<p className="right-align">
<button className="btn btn-large waves-effect waves-light" type="submit" name="action">Send reset key</button>
</p>
</div>
</div>
</form></div>
}
}
SendResetLink.propTypes = {
onClick: PropTypes.func.isRequired,
state: PropTypes.object.isRequired
}
export default SendResetLink
And this is the other relevant code snippet, where the reducer is implemented.
import _ from 'lodash';
const resetLink = (state = {email:"test#test.de", result:true}, action) => {
console.log('state', state)
switch (action.type) {
case 'RESET_LINK':
return _.assign({},state,{email: action.email, result: false});
default:
return state
}
}
export default resetLink;
import { combineReducers } from 'redux'
import resetLink from './ResetLinkReducer.jsx'
const resetApp = combineReducers({
resetLink
})
export default resetApp
import App from './components/app.jsx';
import {Provider} from 'react-redux';
import { createStore } from 'redux';
import { render } from 'react-dom';
import React from 'react';
import resetApp from './reducers/index.js';
let store = createStore(resetApp,{});
console.log(store)
render(<Provider store={store}>
<App />
</Provider>, document.getElementById('sendResetLinkComponent'));
console logs. After click the renderResult should change to false. But it stays on true
You set this.result in your SendResetLink component only once in the constructor, which is only executed when the component is instantiated. The constructor will not be executed every time the application's state changes:
this.result = props.state.result;
Instead of assigning this part of the state to an instance attribute of your react component, simply use the props attribute directly in your render() function:
{this.renderResult(this.props.state.result)}