Sorry but i'm newbie redux and react
I have some code follow example on stackoverflow, and generate error, but i don't know fixing, somebody help me
actions/login.js
export const LOGIN = 'LOGIN';
export const LOGOUT = 'LOGOUT';
export function login(login, password) {
return {
type: LOGIN,
login,
password
}
}
components/LoginForm.js
import { Component, PropTypes } from 'react'
class LoginForm extends Component {
render () {
console.log("LoginForm")
return (
<div>
<form action="#" onSubmit={(e) => this.handleSubmit(e)}>
<input type="text" ref={node => { this.login = node }} />
<input type="password" ref={node => { this.password = node }} />
<input type="submit" value="Login" />
</form>
</div>
)
}
handleSubmit(e) {
e.preventDefault();
this.props.onSubmit(this.login.value, this.password.value);
}
}
LoginForm.propTypes = {
onSubmit: PropTypes.func.isRequired
};
export default LoginForm;
containers/App.js
import { Component } from 'react'
import { connect } from 'react-redux'
import { login } from '../actions/login'
import LoginForm from '../components/LoginForm'
class App extends Component {
render () {
const { dispatch } = this.props;
return (
<div>
<LoginForm onSubmit={(id, pass) => dispatch(login(id, pass))} />
</div>
)
}
}
const mapStateToProps = (state) => {
return {}
};
const mapDispatchToProps = (dispatch) => {
return {}
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
Reducers/rootReducer.js
import { combineReducers } from 'redux'
import { LOGIN, LOGOUT } from '../actions/login'
const initialState = {
cid: null,
username: '',
logo: ''
};
const userLogin = (state = initialState, action) => {
switch (action.type) {
case LOGIN:
console.log("login");
return state;
case LOGOUT:
//...
return state;
default:
console.log("default");
return state;
}
};
const rootReducer = combineReducers({
userLogin
});
export default rootReducer;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App from './containers/App'
import rootReducer from './reducers/rootReducer'
let storelogin = createStore(rootReducer);
let rootElement2 = document.getElementById('root');
console.log("index");
ReactDOM.render(
<Provider store={storelogin}>
<App />
</Provider>,
rootElement2
);
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Soundcloud Client</title>
</head>
<body>
<div id="app"></div>
<div id="counter"></div>
<div id="root"></div>
<div id="hellouni"></div>
</body>
</html>
When build OK, but run localhost:8080 then i get error:
Uncaught ReferenceError: render is not defined
Anybody help me ?
You should be importing React itself too.
import React, { Component } from 'react'
Related
Page not rendering after adding if statement and useSelector hook.
Here is my App component:
import React from 'react';
import Sidebar from "./Sidebar"
import Feed from "./Feed"
import { useSelector } from "react-redux";
import { selectUser } from "./features/userSlice";
import Login from "./Login";
import './App.css';
import Header from './Header';
function App() {
const user = useSelector(selectUser);
return (
<div className="app">
<Header />
{!user
? ( <Login /> )
: (
<div className="app_body">
<Sidebar />
<Feed />
</div>
)
}
{/* Gidgets */}
</div>
);
}
export default App;
The app component quits rendering after I place the app_body inside this if statement and adding both of these :
const user = useSelector(selectUser);
{!user
? ( <Login />)
: (
<div className="app_body">
<Sidebar />
<Feed />
</div>
)
}
Here is my userSlice component if this is relevant:
import { createSlice } from '#reduxjs/toolkit';
const initialState = {
user: null,
status: 'idle',
};
export const userSlice = createSlice({
name: "user",
initialState,
user:null,
reducers: {
login: (state, action) => {
state.value = action.payload;
},
logout: (state) => {
state.user = null;
},
},
});
export const {login, logout} = userSlice.actions;
export const selectUser = (state) => state.user.user;
export default userSlice.reducer;
I tried eliminating different pieces of code and it appears the two pieces of code mentioned caused it to stop rendering.
I just looked in my store component:
import { configureStore } from '#reduxjs/toolkit';
import userReducer from '../features/userSlice';
export const store = configureStore({ reducer: { user: userReducer, }, });
And I had
count:userReducer instead of user: userReducer
That was the issue.
Thank you guys so much for the help!
I have a login page (login.js), when the form is submited data gets sent using redux , dispatch but when i console.log user selector it shows undefined and i don't really know why. The ajax call work and resp.data.json show the data in saga.js.
Init state is defined so even before the ajax call i should be able to access to isLoading and errorMessage which i cannot even have access.
login.js
import React, { Component, useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { useParallax } from "react-scroll-parallax";
import { useTranslation } from "react-i18next";
import axios from "axios";
import "./Login.css";
import logoWhite from './img/logo-white.png';
import svgLogo from './img/log.png';
import { Helmet } from 'react-helmet';
import { useDispatch, useSelector } from 'react-redux';
import userActions from './redux/auth/actions';
const {
postToApi,
} = userActions;
function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const user = useSelector(
state => state.user
);
const dispatch = useDispatch();
const handleLogin = e => {
e.preventDefault();
var data = {};
data.email = email;
data.password = password;
dispatch(postToApi(data));
console.log(user); // Undefined
};
const { t, i18n } = useTranslation();
return (
<div className="login-page">
<Helmet>
<title>Espace Client - Développement de site internet à Antibes, Cannes, Nice</title>
</Helmet>
<div className="container">
<div className="forms-container">
<div className="signin-signup">
<form onSubmit={handleLogin} autoComplete="off" className="sign-in-form">
<h2 className="title">Identifiez-vous</h2>
<div className="input-field">
<i className="fas fa-user"></i>
<input type="text" value={email} onInput={e => setEmail(e.target.value)} placeholder="Adresse e-mail" autoComplete="off" />
</div>
<div className="input-field">
<i className="fas fa-lock"></i>
<input type="password" value={password} onInput={e => setPassword(e.target.value)} placeholder="Mot de passe" autoComplete="new-password" />
</div>
<button type="submit" className="btn solid">CONTINUER</button>
</form>
</div>
</div>
<div className="panels-container">
<div className="panel left-panel">
<div className="content">
<Link to="/"><img src={logoWhite} className="logo" alt="Création de sites Web vitrine" /></Link>
<h3 className="text-white">ESPACE CLIENT</h3>
<p>
Vous pourrez suivre vos factures, modifier vos informations personelles, trouver de l'aide...
</p>
</div>
<img src={svgLogo} className="image" alt="Création de sites Web vitrine" />
</div>
</div>
</div>
</div>
)
}
export default Login;
actions.js
const actions = {
POST_TO_API: 'POST_TO_API',
POST_TO_API_SUCCESS: 'POST_TO_API_SUCCESS',
POST_TO_API_ERROR: 'POST_TO_API_ERROR',
postToApi: data => {
return {
type: actions.POST_TO_API,
payload: { data },
};
},
postToApiSuccess: data => ({
type: actions.POST_TO_API_SUCCESS,
payload: { data },
}),
postToApiError: error => ({
type: actions.POST_TO_API_ERROR,
payload: { error },
}),
};
export default actions;
reducer.js
import actions from './actions';
const initState = {
isLoading: false,
errorMessage: false,
data: []
};
export default function reducer(
state = initState,
{ type, payload }
) {
switch (type) {
case actions.POST_TO_API:
return {
...state,
isLoading: true,
errorMessage: false
};
case actions.POST_TO_API_SUCCESS:
return {
...state,
isLoading: false,
data: payload.data,
errorMessage: false
};
case actions.POST_TO_API_ERROR:
return {
...state,
isLoading: false,
errorMessage: 'There is a problem'
};
default:
return state;
}
}
saga.js
import { all, takeEvery, put, call } from 'redux-saga/effects';
import actions from './actions';
import axios from "axios";
function run(data){
var actionUrl = '/pages/login';
return axios ({
method: 'POST',
url: 'http://xzy/api' + actionUrl,
data: {
data
},
headers: { 'Content-Type': 'application/json;charset=UTF-8', "Access-Control-Allow-Origin": "*", "Accept": "application/json" }
});
}
function* postToApi(payload) {
try {
const resp = yield call(run, payload.payload.data)
console.log(resp.data.json); // Data shown in the log
yield put(actions.postToApiSuccess(resp.data.json));
} catch (error) {
yield put(actions.postToApiError(error));
}
}
export default function* rootSaga() {
yield all([
takeEvery(actions.POST_TO_API, postToApi),
]);
}
App.js
import React from 'react';
import { Provider } from 'react-redux';
import { store } from './redux/store';
import Routes from './router';
import AppProvider from './AppProvider';
const App = () => (
<Provider store={store}>
<AppProvider>
<>
<Routes />
</>
</AppProvider>
</Provider>
);
export default App;
AppProvider.js
import React from 'react';
import { ConfigProvider } from 'antd';
export default function AppProvider({ children }) {
return (
<ConfigProvider locale="fr">
{children}
</ConfigProvider>
);
}
./redux/store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './root-reducer';
import rootSaga from './root-saga';
const sagaMiddleware = createSagaMiddleware();
const middlewares = [thunk, sagaMiddleware];
const bindMiddleware = middleware => {
if (process.env.NODE_ENV !== 'production') {
const { composeWithDevTools } = require('redux-devtools-extension');
return composeWithDevTools(applyMiddleware(...middleware));
}
return applyMiddleware(...middleware);
};
const store = createStore(rootReducer, bindMiddleware(middlewares));
sagaMiddleware.run(rootSaga);
export { store };
root-saga.js
import { all } from 'redux-saga/effects';
import authSagas from './auth/saga';
export default function* rootSaga(getState) {
yield all([
authSagas()
]);
}
root-reducer.js
import { combineReducers } from 'redux';
import App from './app/reducer';
import Auth from './auth/reducer';
export default combineReducers({
Auth,
App
});
as mentioned in the title I'm trying to set up some test for <Search /> component, in particular I want to test the useState hooks.
After mocking the Redux store and creating a shallow wrapper I tried to simulate an input from the child component DisplaySearchBar but apparently I cannot even mamage to select it.
That's the error I get:
Method “props” is meant to be run on 1 node. 0 found instead.
Here's Search.js
import React, { useState } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { handleScriptLoad } from '../../../helpers/Autocomplete';
import { getRestaurants, setAlert } from '../../../actions/restaurantAction';
import DisplaySearchBar from '../../layout/DisplaySearchBar/DisplaySearchBar';
import styles from './Search.module.scss';
const Search = ({ getRestaurants, setAlert }) => {
const [where, setWhere] = useState('');
const [what, setWhat] = useState('');
const [sortBy, setSortBy] = useState('rating');
const sortByOptions = {
'Highest Rated': 'rating',
'Best Match': 'best_match',
'Most Reviewed': 'review_count',
};
// give active class to option selected
const getSortByClass = (sortByOption) => {
if (sortBy === sortByOption) {
return styles.active;
} else {
return '';
}
};
// set the state of a sorting option
const handleSortByChange = (sortByOption) => {
setSortBy(sortByOption);
};
//handle input changes
const handleChange = (e) => {
if (e.target.name === 'what') {
setWhat(e.target.value);
} else if (e.target.name === 'where') {
setWhere(e.target.value);
}
};
const onSubmit = (e) => {
e.preventDefault();
if (where && what) {
getRestaurants({ where, what, sortBy });
setWhere('');
setWhat('');
setSortBy('best_match');
} else {
setAlert('Please fill all the inputs');
}
};
// displays sort options
const renderSortByOptions = () => {
return Object.keys(sortByOptions).map((sortByOption) => {
let sortByOptionValue = sortByOptions[sortByOption];
return (
<li
className={getSortByClass(sortByOptionValue)}
key={sortByOptionValue}
onClick={() => handleSortByChange(sortByOptionValue)}
>
{sortByOption}
</li>
);
});
};
return (
<DisplaySearchBar
onSubmit={onSubmit}
handleChange={handleChange}
renderSortByOptions={renderSortByOptions}
where={where}
what={what}
handleScriptLoad={handleScriptLoad}
/>
);
};
Search.propTypes = {
getRestaurants: PropTypes.func.isRequired,
setAlert: PropTypes.func.isRequired,
};
export default connect(null, { getRestaurants, setAlert })(Search);
DisplaySearchBar.js
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { clearSearch } from '../../../actions/restaurantAction';
//Import React Script Libraray to load Google object
import Script from 'react-load-script';
import Fade from 'react-reveal/Fade';
import Alert from '../Alert/Alert';
import styles from './DisplaySearchBar.module.scss';
const DisplaySearchBar = ({
renderSortByOptions,
onSubmit,
where,
handleChange,
what,
handleScriptLoad,
restaurants,
clearSearch,
}) => {
const googleUrl = `https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_API_KEY}&libraries=places`;
// {googleUrl && <Script url={googleUrl} onLoad={handleScriptLoad} />}
return (
<section className={styles.searchBar}>
<form onSubmit={onSubmit} className={styles.searchBarForm}>
<legend className="title">
<Fade left>
<h1>Where are you going to eat tonight?</h1>
</Fade>
</legend>
<Fade>
<fieldset className={styles.searchBarInput}>
<input
type="text"
name="where"
placeholder="Where do you want to eat?"
value={where}
onChange={handleChange}
id="autocomplete"
/>
<input
type="text"
name="what"
placeholder="What do you want to eat?"
onChange={handleChange}
value={what}
/>
<div className={styles.alertHolder}>
<Alert />
</div>
</fieldset>
<fieldset className={styles.searchBarSubmit}>
<input
id="mainSubmit"
className={`${styles.myButton} button`}
type="submit"
name="submit"
value="Search"
></input>
{restaurants.length > 0 && (
<button
className={`${styles.clearButton} button`}
onClick={clearSearch}
>
Clear
</button>
)}
</fieldset>
</Fade>
</form>
<article className={styles.searchBarSortOptions}>
<Fade>
<ul>{renderSortByOptions()}</ul>
</Fade>
</article>
</section>
);
};
DisplaySearchBar.propTypes = {
renderSortByOptions: PropTypes.func.isRequired,
where: PropTypes.string.isRequired,
handleChange: PropTypes.func.isRequired,
what: PropTypes.string.isRequired,
handleScriptLoad: PropTypes.func.isRequired,
restaurants: PropTypes.array.isRequired,
clearSearch: PropTypes.func.isRequired,
};
const mapStatetoProps = (state) => ({
restaurants: state.restaurants.restaurants,
});
export default connect(mapStatetoProps, { clearSearch })(DisplaySearchBar);
And Search.test.js
import React from 'react';
import { mount } from 'enzyme';
import configureStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import Search from '../Search';
import DisplaySearchBar from '../../../layout/DisplaySearchBar/DisplaySearchBar';
const mockStore = configureStore();
const initialState = {
restaurants: { restaurants: ['foo'], alert: null },
};
describe('Search', () => {
test('renders withut errors', () => {
const store = mockStore(initialState);
const wrapper = mount(
<Provider store={store}>
<Search setAlert={jest.fn()} getRestaurants={jest.fn()} />
</Provider>
);
wrapper.find(DisplaySearchBar).props();
});
});
Thanks for your help!
shallow doesn't work for react-redux new versions (>= 6).
Use mount instead:
const wrapper = mount( // <-- changed shallow to mount.
<Provider store={store}>
<Search {...props} />
</Provider>
);
Run It On Sandbox (Use tests tab to run tests.)
Try to mount it like this:
const wrapper = shallow(
<Provider store={store} />
<Search setAlert=jest.fn() getRestaurants=jest.fn() />
</Provider>
);
I have a ecommerce store with registration and login. After registration, the token is stored in cookie and authentication state is updated. It is working. But the problem is, when I refresh the page, authentication state is set to null. Please check my store and reducers.
store.js
import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import {composeWithDevTools} from 'redux-devtools-extension'
import rootReducer from './reducers';
const initialState = {};
const middleware = [thunk];
const store = createStore(rootReducer, initialState,
composeWithDevTools(applyMiddleware(...middleware)));
export default store;
authReducer.js
import * as types from '../types'
export const authReducer = (state = { token: null }, action) => {
switch (action.type) {
case types.AUTHENTICATE:
return {
...state,
token: action.payload
};
case types.DEAUTHENTICATE:
return {
token: null
};
default:
return state;
}
};
authAction.js
import * as types from '../types'
import axios from 'axios'
import cookie from 'js-cookie';
import * as api from '../../pages/api'
import Router from 'next/router';
export const authenticate = user => async dispatch => {
const res = await axios.post(api.URL_REGISTER, {user})
.then(res => {
if (res.data.response === 200) {
setCookie('token', res.data.data.token);
Router.push('/');
dispatch({
type: types.AUTHENTICATE,
payload: res.data.data.token
})
}
else
dispatch({
type: types.AUTHENTICATE,
payload: res.data
})
}).catch(error => {
console.log(error);
});
}
// gets the token from the cookie and saves it in the store
export const reauthenticate = token => {
return dispatch => {
dispatch({ type: types.AUTHENTICATE, payload: token });
};
};
// removing the token
export const deauthenticate = () => {
return dispatch => {
removeCookie('token');
Router.push('/');
dispatch({ type: types.DEAUTHENTICATE });
};
};
/**
* cookie helper methods
*/
export const setCookie = (key, value) => {
if (process.browser) {
cookie.set(key, value, {
expires: 1,
path: '/'
});
}
};
export const removeCookie = key => {
if (process.browser) {
cookie.remove(key, {
expires: 1
});
}
};
export const getCookie = key => {
return cookie.get(key);
};
Header.js
import React from 'react'
import Link from 'next/link'
import {FontAwesomeIcon} from '#fortawesome/react-fontawesome'
import { faSearch, faShoppingCart, faUserCircle, faBoxOpen, faHeart } from '#fortawesome/fontawesome-free-solid'
import { deauthenticate } from '../../store/actions/authAction';
import { connect } from 'react-redux';
const Header = ({ deauthenticate, isAuthenticated }) => (
<div>
<div className="col-12 col-md-4 col-lg-3">
<div className="text-center text-md-right">
<div className="d-inline loginDrop">
<Link href="/">
<a className="signinBtn mr-5">{!isAuthenticated ? "Sign In" : "My Account"}</a>
</Link>
<div className={!isAuthenticated ? "login-content" : "login-content logout-content"}>
<p> </p>
<div className="login-inner">
<Link href={!isAuthenticated ? "/login" : "/profile"}><a><FontAwesomeIcon icon={faUserCircle} className="mr-2"/> Your Profile</a></Link>
<Link href={!isAuthenticated ? "/login" : "/orders"}><a><FontAwesomeIcon icon={faBoxOpen} className="mr-2 orderIcon"/> Orders</a></Link>
<Link href={!isAuthenticated ? "/login" : "/wishlist"}><a><FontAwesomeIcon icon={faHeart} className="mr-2"/> Whishlist</a></Link>
<div className="otherDrop">
{!isAuthenticated ?
<>
<p className="first">Don't have an account?</p>
<p className="register"><Link href="/register" as="/register"><a>Register</a></Link></p>
<p className="login"><Link href="/login"><a>Login</a></Link></p>
</>
:
<p className="login"><a href="#" onClick={deauthenticate}>Logout</a></p>
}
</div>
</div>
</div>
</div>
<Link href="/">
<a className="cartBtn"><FontAwesomeIcon icon={faShoppingCart} className="mr-xl-1"/> Cart</a>
</Link>
</div>
</div>
</div>
)
const mapStateToProps = state => ({ isAuthenticated: !!state.authentication.token });
export default connect(
mapStateToProps,
{ deauthenticate }
)(Header);
_app.js
import App from 'next/app'
import React from 'react'
import {Provider} from 'react-redux'
import {createWrapper} from 'next-redux-wrapper'
import store from '../store/store'
class MyApp extends App {
render() {
const {Component, pageProps} = this.props
return (
<Provider store={store}>
<Component {...pageProps}></Component>
</Provider>
)
}
}
const makestore = () => store;
const wrapper = createWrapper(makestore);
export default wrapper.withRedux(MyApp);
How to fix initial state not to be null even after refresh the page. I am really stuck here. Is there any option to fix.
All you need is to persist your redux state across a browser refresh by using redux middleware like redux-persist, ie:
if (isClient) {
store = createStore(
persistReducer(persistConfig, rootReducer),
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
}
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;