Got an error while setting the 'state' (REACT) - javascript

I was doing a small project just to learn more about React when I got this error:
" Line 19.5: 'state' is not defined no-undef ".
I don't know what is wrong...
I used the same structure in another project and I didn't get an error.
import React, { Component } from 'react'
import axios from 'axios'
import Main from '../template/Main'
const headerProps = {
icon: 'users',
title: 'Usuários',
subtitle: 'Cadastro de usuários: Incluir, Listar, Alterar e Excluir'
}
const baseUrl = 'http://localhost:3001/users'
const initalState = {
user: { name: '', email: '' },
list: []
}
export default class UserCrud extends Component {
state = { ...initalState }
clear() {
this.setState({ user: initalState.user })
}
save() {
const user = this.state.user
const method = user.id ? 'put' : 'post'
const url = user.id ? `${baseUrl}/${user.id}` : baseUrl
axios[method](url, user)
.then(resp => {
const list = this.getUpdatedList(resp.data)
this.setState({ user: initalState.user, list })
})
}
getUpdatedList(user) {
const list = this.state.list.filter(u => u.id !== user.id)
list.unshift(user)
return list
}
render() {
return (
<Main {...headerProps}>
Cadastro de Usuários
</Main>
)
}
}
Error message

Declare state inside constructor method using this.
export default class UserCrud extends Component {
constructor(props) {
super(props);
this.state = { ...initalState };
}
clear() {
this.setState({ user: initalState.user })
}
save() {
const user = this.state.user
const method = user.id ? 'put' : 'post'
const url = user.id ? `${baseUrl}/${user.id}` : baseUrl
axios[method](url, user)
.then(resp => {
const list = this.getUpdatedList(resp.data)
this.setState({ user: initalState.user, list })
})
}
getUpdatedList(user) {
const list = this.state.list.filter(u => u.id !== user.id)
list.unshift(user)
return list
}
render() {
return (
<Main {...headerProps}>
Cadastro de Usuários
</Main>
)
}
}

Related

Saving state to localStorage [duplicate]

I have no idea How to store the react js state into localstorage.
import React, { Component } from 'react'
import './App.css';
import { auth,createUserProfileDocument } from './firebase/firebase.utils'
import { TodoForm } from './components/TodoForm/TodoForm.component'
import {TodoList} from './components/TodoList/TodoList.component'
import {Footer} from './components/footer/footer.component'
import Header from '../src/components/header/header.component'
import {Redirect} from 'react-router-dom'
import {connect} from 'react-redux'
import {setCurrentUser} from './redux/user/user.actions'
export class App extends Component {
constructor(props) {
super(props)
this.input=React.createRef()
this.state = {
todos:[
{id:0, content:'Welcome Sir!',isCompleted:null},
]
}
}
todoDelete = (id) =>{
const todos = this.state.todos.filter(todo => {
return todo.id !== id
})
this.setState({
todos
})
}
toDoComplete = (id,isCompleted) =>{
console.log(isCompleted)
var todos = [...this.state.todos];
var index = todos.findIndex(obj => obj.id === id);
todos[index].isCompleted = !isCompleted;
this.setState({todos});
console.log(isCompleted)
}
addTODO = (todo) =>{
todo.id = Math.random()
todo.isCompleted = true
let todos = [...this.state.todos, todo]
this.setState({
todos
})
}
unsubscribeFromAuth = null;
componentDidMount() {
const { setCurrentUser } = this.props;
this.unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
if (userAuth) {
const userRef = await createUserProfileDocument(userAuth);
userRef.onSnapshot(snapShot => {
setCurrentUser({
id: snapShot.id,
...snapShot.data()
});
});
}
setCurrentUser(userAuth);
});
}
componentWillUnmount() {
this.unsubscribeFromAuth();
}
render() {
return (
<div className='App'>
<Header />
<TodoForm addTODO={this.addTODO} />
<TodoList
todos={this.state.todos}
todoDelete={ this.todoDelete}
toDoComplete={ this.toDoComplete}
/>
<Footer/>
</div>
)
}
}
const mapStateToProps = ({ user }) => ({
currentUser: user.currentUser
});
const mapDispatchToProps = dispatch => ({
setCurrentUser: user => dispatch(setCurrentUser(user))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
in my input Form
import './TodoForm.style.css'
export class TodoForm extends Component {
constructor(props) {
super(props)
this.state = {
content : ''
}
}
handleChange = (e) =>{
this.setState({
content: e.target.value
})
}
handleSubmit =(e) =>{
e.preventDefault();
this.props.addTODO(this.state);
this.setState({
content: ''
})
}
render() {
return (
<div className='inputTask'>
<form onSubmit={ this.handleSubmit}>
<input
className="textBox"
type='text'
onChange={ this.handleChange}
value={this.state.content}
placeholder='what you want to do ...'
/>
</form>
</div>
)
}
}
export default TodoForm
I have no idea How to store the react js state into localstorage.
i searched on internet but unable to find the exact solution all the codes that i think is necessary post.
You can use reactLocalStorage to save any data in local storage
import {reactLocalStorage} from 'reactjs-localstorage';
reactLocalStorage.set('var', true);
reactLocalStorage.get('var', true);
reactLocalStorage.setObject('var', {'test': 'test'});
reactLocalStorage.getObject('var');
reactLocalStorage.remove('var');
reactLocalStorage.clear();
Read out the localStorage item in the componentDidMount callback. Simply read the item you want to get, check if it exists and parse it to a usable object, array or datatype that need. Then set the state with the results gotten from the storage.
And to store it, simply handle it in an event handler or helper method to update both the state and the localStorage item.
class ExampleComponent extends Component {
constructor() {
super();
this.state = {
something: {
foo: 'bar'
}
}
}
componentDidMount() {
const storedState = localStorage.getItem('state');
if (storedState !== null) {
const parsedState = JSON.parse(storedState);
this.setState({ something: parsedState });
}
}
clickHandler = (event) => {
const value = event.target.value;
const stringifiedValue = JSON.stringify(value);
localStorage.setItem('state', stringifiedValue);
this.setState({ something: value });
}
render() {
return (
<button onClick={clickHandler} value={this.state.something}>Click me</button>
);
}
}
Set data in localStorage
key-value pair :
localStorage.setItem('key_name',"value");
object
localStorage.setItem('key_name', JSON.stringify(object));
Remove data from localStorage
localStorage.removeItem('key_name');
Get data from localStorage
let data = localStorage.getItem('key_name');
object :
let data = JSON.parse(localStorage.getItem('key_name'));
clear localStorage (delete all data)
localStorage.clear();

Problem using multiple Reducers and Actions Redux

I have a little problem.
I have diferent reducers in different files using a combine reducer, but when i try to use the "different"
INITIAL STATES on these reducers it doesnt apear
For example
Product Reducer -> This is the state that i have to take
const INITIAL_STATE = {
productosInventario: [],
loading: false,
error: ''
Category Reducer -> this is the state for these reducer
const INITIAL_STATE = {
categorias: [],
categoriaActual: '',
loading: false,
error: ''
}
The idea is use both on these component:
Component:
import React, { Component } from 'react'
/* Components */
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import CardItemInventario from '../components/inventario/CardItemInventario'
import * as ProductoActions from '../actions/ProductoActions'
import * as CategoriasActions from '../actions/CategoriasActions'
/* Styles */
import Spinner from '../components/Spinner'
import Fatal from '../components/Fatal'
import '../assets/styles/Containers/Inventario.scss'
class Inventario extends Component {
async componentDidMount() {
await this.props.traerTodosLosProductos();
}
handleChangeCategoria = (e) => {
this.props.cambioCategoriaInventario(e.target.value)
this.props.traerProductosPorCategoriaInventario(e.target.value)
}
/* Mapea todas las categorias disponibles en base de datos */
traerCategoriasInventario = () => this.props.categoriasInventario.map(category => {
let categori = category.categoria
return (
<option
value={categori}
>
{categori}
</option>
)
})
ponerContenido = () => {
if (this.props.loading) {
return (
<Spinner />
)
}
if (this.props.error) {
return (
<Fatal
error={this.props.error} />
)
}
return (
<>
<div className="button-add__cont">
<h1 className="button-add__title">
Inventario
</h1>
<Link to='/agregarinventario' className="button-add__cont--link">
Agregar a Inventario
</Link>
</div>
<select
name="categoriaSelect"
id=""
onChange={this.handleChangeCategoria}
className="selector-categoria"
>
<option value='' defaultValue> - Categoria -</option>
{this.traerCategoriasInventario()}
</select>
<div className="inventario-cont">
{this.imprimirProductos()}
</div>
</>
)
}
imprimirProductos = () => this.props.productosInventario.map(Productos =>
<CardItemInventario
nombre={Productos.nombre}
marca={Productos.marca}
cantidad={Productos.cantidad}
distribuidor={Productos.distribuidor}
precio={Productos.precio}
/>
)
render() {
console.log(this.props)
return (
<>
{this.ponerContenido()}
</>
)
}
}
const mapStateToProps = (reducers) => {
return (
reducers.ProductoReducer,
reducers.CategoriasReducer
)
}
const mapDispatchToProps = {
...ProductoActions,
...CategoriasActions
}
export default connect(mapStateToProps, mapDispatchToProps)(Inventario);
actions ->
productoActions:
import axios from 'axios'
import {
TRAER_TODOS_LOS_PRODUCTOS
} from '../types/ProductoTypes'
import { host_name, port_redux } from '../../../config'
import { CARGANDO, ERROR } from '../types/GlobalTypes'
const axiosConf = {
baseURL: `http://${host_name}:${port_redux}`
}
export const traerTodosLosProductos = () => async (dispatch) => {
dispatch({
type: CARGANDO
})
try {
const res = await axios.get(`/api/productos/get/listar`, axiosConf)
dispatch({
type: TRAER_TODOS_LOS_PRODUCTOS,
payload: res.data
})
} catch (error) {
console.log("Error: " + error)
dispatch({
type: ERROR,
payload: error.message
})
}
}
export const traerProductosPorCategoriaInventario = (categoria) => async (dispatch) => {
try {
const res = await axios.get(`/api/cotizacion/get/productosporcategoria/${categoria}`, axiosConf)
dispatch({
type: TRAER_TODOS_LOS_PRODUCTOS,
payload: res.data
})
} catch (error) {
console.log("Error: " + error)
dispatch({
type: ERROR,
payload: error.message
})
}
}
categoryActions_ >
import axios from 'axios'
import { host_name, port_redux } from '../../../config'
import { CARGANDO, ERROR } from '../types/GlobalTypes'
import {
LISTAR_CATEGORIAS,
CATEGORIA_ACTUAL
} from '../types/CategoriasTypes'
const axiosConf = {
baseURL: `http://${host_name}:${port_redux}`
}
export const traerCategoriasInventario = () => (dispatch) => {
const res = axios.get(`/api/categorias/get/listar`, axiosConf)
console.log(res)
dispatch({
type: LISTAR_CATEGORIAS,
payload: res.data.data
})
}
export const cambioCategoriaInventario = (categoria) => async (dispatch) => {
try {
dispatch({
type: CATEGORIA_ACTUAL,
payload: categoria
})
} catch (error) {
console.log("Error: " + error)
dispatch({
type: ERROR,
payload: error.message
})
}
}
const mapStateToProps = (reducers) => {
return (
reducers.ProductoReducer,
reducers.CategoriasReducer
)
}
It seems like you are having some confusion between state and reducer. The state is the object which contains all of your data. It is just a plain javascript object. The reducer is a function which takes the state object and an action and returns a new state object.
Your setup should look something like this:
const productoReducer = (state = INITIAL_PRODUCTOS, action ) => {
switch ( action.type ) {
case 'TRAER_TODOS_LOS_PRODUCTOS':
/* ... code here ... */
default:
return state;
}
}
const categoriasReducer = (state = INITIAL_CATEGORIAS, action ) => {
switch ( action.type ) {
case 'LISTAR_CATEGORIAS':
/* ... code here ... */
default:
return state;
}
}
export const reducer = combineReducers({
producto: productoReducer,
categorias: categoriasReducer,
})
Here we have two separate reducers for categories and for products, and each gets a separate initial state. We use combineReducers to put them together so now the combined state has properties producto and categorias.
Your component Inventario needs to access a bunch of values from state: categoriasInventario, productosInventario, loading, and error. Rather than passing the state into the component, we use mapStateToProps to extract these values and pass them as props.
const mapStateToProps = (state) => {
return {
categoriasInventario: state.categorias.categorias,
productosInventario: state.productos.productosInventario,
loading: state.categorias.loading || state.productos.loading,
error: state.categorias.error || state.productos.error,
}
}

How to make live search on this name react js?

I am trying to make live search for name in table but i can't make live search i don't know how to do this i wrote my code like this as i mentioned please help me how to make live search on name field foe table and in Search Page i used onSubmit={this.props.loaddata like this thanks
import React, { Component } from "react";
import Search from "../../views/Cars/Search";
class Search1 extends Component {
constructor(props) {
super(props);
this.state = {
query: []
};
}
// Get Data from filter date
getData = async e => {
try {
const search = e.target.elements.search.value;
e.preventDefault();
const res = await fetch(`https://swapi.co/api/people/?search=${search}`);
const query = await res.json();
console.log(query);
this.setState({
query: query.results
});
} catch (e) {
console.log(e);
}
};
async componentDidMount() {
// let authToken = localStorage.getItem("Token");
try {
const res = await fetch(`https://swapi.co/api/people/`);
const query = await res.json();
// console.log(movie);
this.setState({
query: query.results
});
} catch (e) {
console.log(e);
}
}
render() {
const options = this.state.query.map(r => <li key={r.id}>{r.name}</li>);
return (
<div>
<Search loaddata={this.getData} />
{options}
</div>
);
}
}
export default Search1;
Genrally You can try React-Search
import Search from 'react-search'
import ReactDOM from 'react-dom'
import React, { Component, PropTypes } from 'react'
class TestComponent extends Component {
HiItems(items) {
console.log(items)
}
render () {
let items = [
{ id: 0, value: 'ruby' },
{ id: 1, value: 'javascript' },
{ id: 2, value: 'lua' },
{ id: 3, value: 'go' },
{ id: 4, value: 'julia' }
]
return (
<div>
<Search items={items} />
<Search items={items}
placeholder='Pick your language'
maxSelected={3}
multiple={true}
onItemsChanged={this.HiItems.bind(this)} />
</div>
)
}
}
Made few changes to your component. Send e.target.value from your child component
class Search1 extends Component {
constructor(props) {
super(props);
this.state = {
query: []
};
}
// Get Data from filter date
getData = search => {
const url = `https://swapi.co/api/people${search ? `/?search=${search}` : ``}`;
// e.preventDefault();
fetch(url)
.then(res => res.json())
.then(data =>
this.setState({
query: data.results || []
})).catch(e => console.log(e));
};
async componentDidMount() {
// let authToken = localStorage.getItem("Token");
this.getData();
}
render() {
const options = this.state.query.map(r => <li key={r.id}>{r.name}</li>);
return (
<div>
<Search loaddata={this.getData} />
{options}
</div>
);
}
}
export default Search1;
For Gettind Data from Api you can follow this code of react-search
import Search from 'react-search'
import ReactDOM from 'react-dom'
import React, { Component, PropTypes } from 'react'
class TestComponent extends Component {
constructor (props) {
super(props)
this.state = { repos: [] }
}
getItemsAsync(searchValue, cb) {
let url = `https://api.github.com/search/repositories?q=${searchValue}&language=javascript`
fetch(url).then( (response) => {
return response.json();
}).then((results) => {
if(results.items != undefined){
let items = results.items.map( (res, i) => { return { id: i, value: res.full_name } })
this.setState({ repos: items })
cb(searchValue)
}
});
}
render () {
return (
<div>
<Search items={this.state.repos}
multiple={true}
getItemsAsync={this.getItemsAsync.bind(this)}
onItemsChanged={this.HiItems.bind(this)} />
</div>
)
}

How to query in firebase database in react?

I have the following data structure in firebase as a realtime database:
{
"react" : {
"url_01" : "https://stackoverflow.com/",
"url_02" : "https://google.com/",
"url_03" : "https://www.youtube.com/"
}
}
I'm trying to query the database in React to display all URLs in the below component.
So far I got it to display the first URL in the database correctly but now trying to display them all in the div as <h1>.
class FirebaseDB extends React.Component {
constructor() {
super();
this.state = {
speed: [],
};
}
componentDidMount() {
const rootRef = firebase.database().ref().child('react');
const speedRef = rootRef.child('url_01');
speedRef.on('value', snap => {
this.setState({
speed: snap.val()
});
});
}
render() {
return (
<div>
<h1>URL: {this.state.speed}</h1>
</div>
);
}
}
componentDidMount() {
const rootRef = firebase.database().ref();
const speedRef = rootRef.child('react');
speedRef.once("value", snap => {
// Handle state
let speedsUrls = []
snap.forEach(child => {
speedsUrls.push(child.val())
});
this.setState({speed: speedsUrls})
});
}
render() {
const SpeedURLS = this.state.speed.map(url => <h1>URL: {url}</h1>);
return (
<div>
{SpeedURLS}
</div>
);
}
Another solution:
const object1 = {
"url_01" : "https://stackoverflow.com/",
"url_02" : "https://google.com/",
"url_03" : "https://www.youtube.com/"
};
let a = Object.values(object1);
a is now
["https://stackoverflow.com/","https://google.com/","https://www.youtube.com/"]

React Enzyme Jest error jest.fn() should be called

My component is as below
import React from 'react';
import { connect } from 'react-redux';
import { Button } from 'react-bootstrap';
import UserActions from '../../../actions/sampleUserAction';
import UserForm from '../../../views/sample/userForm';
import UsersList from '../../../views/sample/usersList';
#connect(store => ({
users: store.sampleUserReducer.users,
}))
export default class UserComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
displayForm: false,
user: { id: '', fName: '', lName: '' },
isCreationMode: true,
};
this.addNewUser = this.addNewUser.bind(this);
this.handleChange = this.handleChange.bind(this);
this.submitForm = this.submitForm.bind(this);
this.editUser = this.editUser.bind(this);
this.deleteUser = this.deleteUser.bind(this);
}
addNewUser() {
this.setState({
displayForm: !this.state.displayForm,
isCreationMode: true,
user: { id: '', fName: '', lName: '' },
});
}
createUser(users) {
users.push({
id: users.length + 1,
fName: this.state.user.fName,
lName: this.state.user.lName,
});
return users;
}
updateUser(users) {
users.forEach((user) => {
if (user.id === this.state.user.id) {
user.fName = this.state.user.fName;
user.lName = this.state.user.lName;
}
});
return users;
}
submitForm(e) {
e.preventDefault();
let { users } = this.props;
if (this.state.isCreationMode) {
users = this.createUser(users);
} else if (!this.state.isCreationMode) {
users = this.updateUser(users);
}
this.addNewUser();
this.props.dispatch(UserActions.listUsers(users));
}
handleChange(e) {
const { id } = this.state.user;
let { fName, lName } = this.state.user;
if (e.target.name === 'fName') {
fName = e.target.value;
}
if (e.target.name === 'lName') {
lName = e.target.value;
}
this.setState({ user: { id, fName, lName } });
}
editUser(e, id) {
const { users } = this.props;
let user = users.filter(obj => obj.id === id);
user = user.length > 0 ? user[0] : null;
if (user != null) {
this.setState({
displayForm: true,
isCreationMode: false,
user: { id: user.id, fName: user.fName, lName: user.lName },
});
}
}
deleteUser(e, id) {
let { users } = this.props;
users = users.filter(user => user.id !== id);
this.props.dispatch(UserActions.listUsers(users));
}
render() {
console.log(this.state.displayForm);
return (
<div className="container-fluid">
<div className="well">
Sample Users App With Redux
</div>
<UserForm
displayForm={this.state.displayForm}
isCreationMode={this.state.isCreationMode}
submitForm={this.submitForm}
handleChange={this.handleChange}
user={this.state.user}
addNewUser={this.addNewUser}
/>
<UsersList
users={this.props.users}
editUser={this.editUser}
deleteUser={this.deleteUser}
/>
<div className="clearfix">
<Button bsStyle="primary" onClick={this.addNewUser}>Add User</Button>
</div>
</div>
);
}
}
and test file is as below
import React from 'react';
import { createMockStore } from 'redux-test-utils';
import { shallowWithStore } from 'enzyme-redux';
import { Button } from 'react-bootstrap';
import UserComponent from '../../../../src/components/containers/sample/userComponent';
import UserForm from '../../../../src/views/sample/userForm';
import UsersList from '../../../../src/views/sample/usersList';
describe('UsersComponent', () => {
let store;
let container;
const props = {
submitForm: jest.fn(),
addNewUser: jest.fn(),
};
beforeEach(() => {
const defaultState = { sampleUserReducer: { users: [] } };
store = createMockStore(defaultState);
container = shallowWithStore(<UserComponent />, store);
});
it('should work', () => {
expect(true).toEqual(true);
});
it('container should have UserForm component', () => {
expect(container.dive().find(UserForm)).toHaveLength(1);
});
it('container should have UsersList component', () => {
expect(container.dive().find(UsersList)).toHaveLength(1);
});
it('should have add new user button', () => {
expect(container.dive().find(Button)).toHaveLength(1);
expect(container.dive().find(Button).dive().text()).toEqual('Add User');
});
it('On click add user button', () => {
container.dive().find(Button).simulate('click');
expect(props.addNewUser).toHaveBeenCalled();
});
});
I'm using jest, enzyme, enzyme-redux. I'm new to react unit testing. Last test case is giving error as below. React version is 16.x. In last test case I'm trying to call mocked jest function on button click. For button using react-bootstrap inbuilt Button component
expect(jest.fn()).toHaveBeenCalled()
Expected mock function to have been called.
You are likely to need to add container.update(); which forces a re-render after external inputs like clicking.
http://airbnb.io/enzyme/docs/api/ShallowWrapper/update.html
Sometimes container.update() does not work and in such cases, try container.instance().forceUpdate() in your tests after the click which updates the component after the state changes.
Another option would be to use jest's spy to assert that addNewUser was called.
const spy = jest.spyOn(container.instance(), 'addNewUser');
container.dive().find(Button).simulate('click');
expect(spy).toBeCalled();

Categories