Saving state to localStorage [duplicate] - javascript

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();

Related

Getting information about outcome of the class React

I am making project, where you get books cards using Google Books API. I need to count amount of books I get in the end and print in in Header.js(after search). I think I need to add new parameter like 'count' in constructor that will get books.length but still don't know how to pass it in the end.
Books.js
import React, { Component } from 'react';
import SearchArea from './SearchArea';
import request from 'superagent';
import BookList from './BookList';
class Books extends Component {
constructor(props){
super(props);
this.state = {
books: [],
searchField: '',
sort: ''
}
}
searchBook = (e) => {
e.preventDefault();
request
.get("https://www.googleapis.com/books/v1/volumes")
.query({ q: this.state.searchField })
.then((data) => {
console.log(data);
const cleanData = this.cleanData(data)
this.setState({ books: cleanData })
})
}
handleSearch = (e) => {
this.setState ({ searchField: e.target.value })
}
handleSort = (e) => {
console.log(e.target.value)
this.setState({sort: e.target.value})
}
cleanData = (data) => {
const cleanedData = data.body.items.map((book) => {
if(book.volumeInfo.hasOwnProperty('publishedDate') === false){
book.volumeInfo['publishedDate'] = '0000';
}
else if(book.volumeInfo.hasOwnProperty('imageLinks') === false) {
book.volumeInfo['imageLinks'] = {thumbnail: 'https://vignette.wikia.nocookie.net/pandorahearts/images/a/ad/Not_available.jpg/revision/latest?cb=20141028171337'}
}
console.log(this.state.books.length)
return book;
})
return cleanedData;
}
render(){
const sortedBooks = this.state.books.sort((a,b) => {
if(this.state.sort === 'Newest') {
return parseInt(b.volumeInfo.publishedDate.substring(0,4)) - parseInt(a.volumeInfo.publishedDate)
}
else if(this.state.sort === 'Oldest') {
return parseInt(a.volumeInfo.publishedDate.substring(0,4)) - parseInt(b.volumeInfo.publishedDate)
}
})
return (
<div>
<SearchArea searchBook = {this.searchBook} handleSearch={this.handleSearch} handleSort={this.handleSort}/>
<BookList books={this.state.books} />
</div>
);
}
}
export default Books;
SearchArea.js
import React from 'react'
const SearchArea = (props) => {
return(
<div className="search-area">
<form onSubmit={props.searchBook} action="">
<input onChange={props.handleSearch} type="text"/>
<button id="search" type="submit">Search</button>
<select defaultValue="Sort" onChange={props.handleSort}>
bled v<option disaalue="Sort">Sort</option>
<option value="Newest">Newest</option>
<option value="Oldest">Oldest</option>
</select>
</form>
</div>
)
}
export default SearchArea;
BookList.js
import React from 'react';
import BookCard from './BookCard';
const BookList = (props) => {
return(
<div className="list">
{
props.books.map((book,i) => {
return <BookCard
key={i}
image={book.volumeInfo.imageLinks.thumbnail}
title={book.volumeInfo.title}
author={book.volumeInfo.authors}
published={book.volumeInfo.publishedDate}
/>
})
}
</div>
)
}
export default BookList;
Header.js
import React from 'react';
const Header = () => {
return(
<header>
<h1>Book Cards</h1>
</header>
)
}
export default Header;

todo list app - onChange on ReactJS doesn't work?

I am new to ReactJS and I'm doing a simple to-list with it. I am working on the part of check box. What I want to do is to uncheck the box whenever i click it or vice versa. But nothing has been changed, so I am wondering if anything wrong....
Below is the App.js and index.js file
import React from 'react';
import Todolist from './Todolist';
import todoData from './todoData';
class App extends React.Component {
constructor(){
super()
this.state = {
todos: todoData //grab the raw data
}
this.handleChange = this.handleChange.bind(this)
}
handleChange (id){
console.log(id)
this.setState (prevState => {
const updatedtodos = prevState.todos.map(todo => {
if(todo.id == id) {
todo.completed = !todo.completed
}
return todo
})
return {
todos: updatedtodos
}
})
}
render() {
const TodoItem = this.state.todos.map(item => <Todolist key={item.id} item={item} handleChange={this.handleChange}/>)
return(
<div>
{TodoItem}
</div>
);
}
}
export default App;
import React from 'react';
function Todolist (props){
return(
<div className="wholelist">
<input
type="checkbox"
checked={props.item.completed}
onChange={()=> props.handleChange(props.item.id)}
/>
<label className="items">{props.item.name}</label>
</div>
);
}
export default Todolist;
Change handleChange:
handleChange(id) {
console.log(id);
const updatedtodos = this.state.todos.map(todo => {
if (todo.id === id) {
todo.completed = !todo.completed;
}
return todo;
});
this.setState({
todos: updatedtodos
});
}
you need to change two things.
firstly:
handleChange = (id) => { // I've changed this to an arrow function so it can access parent scope and you can use "this" keyword
console.log(id)
this.setState (prevState => {
const todos = this.state.todos.map(todo => {
if(todo.id === id) {
todo.completed = !todo.completed
}
return todo
})
this.setState({ todos }) // you can use object shorthand here to change todos in state to use the todos set above
})
}
secondly:
change this: handleChange={this.handleChange}
to: handleChange={() => this.handleChange(item.id)}
you said that handleChange(id) need to take an id, so we need to pass one in when we call it
let me know if that works!

React exporting context returns Parsing error: Export 'SearchContextConsumer' is not defined

I am trying to create a context in order to pass data to another component without using props drilling, but when I export my consumer I get that Parsing error: Export 'SearchContextConsumer' is not defined
What seems to be the problem and how can I export it successfully?
Here is my code:
import React, { Component } from "react";
import axios from "axios";
class Search extends Component {
state = {
searchResults: [],
isSearched: false
}
SearchContext = React.createContext('context');
SearchContextConsumer = SearchContext.Consumer;
data = { searchResults: this.state.searchResults }
Search = ({ children }) => (
<SearchContext.Provider value={searchResults}>{children}</SearchContext.Provider>
)
getSearchQuery = (event) => {
const queryString = document.querySelector(
".search-input"
).value;
if (event.keyCode === 13) {
axios.post("http://localhost:3001/search", {
queryString: queryString,
}).then(response => {
this.setState({ ...this.state, searchResults: response.data });
});
this.setState({ ...this.state, isSearched: true });
window.location.href = '/blog/searchResults'
}
};
render() {
return (
<div>
<input
type="text"
className="search-input"
onKeyDown={(e) => this.getSearchQuery(e)}
/>
</div>
);
}
}
export { SearchContextConsumer }
export default Search;
You can't export a property of a class this way.
I think the simplest and cleanest way to do what you have in mind is to create your context outside of your class like this:
import React, { Component } from "react";
import axios from "axios";
const SearchContext = React.createContext();
class Search extends Component {
state = {
searchResults: [],
isSearched: false
}
data = { searchResults: this.state.searchResults }
getSearchQuery = (event) => {
const queryString = document.querySelector(
".search-input"
).value;
if (event.keyCode === 13) {
axios.post("http://localhost:3001/search", {
queryString: queryString,
}).then(response => {
this.setState({ ...this.state, searchResults: response.data });
});
this.setState({ ...this.state, isSearched: true });
window.location.href = '/blog/searchResults'
}
};
render() {
return (
<SearchContext.Provider value={searchResults}>
<input
type="text"
className="search-input"
onKeyDown={(e) => this.getSearchQuery(e)}
/>
</SearchContext.Provider>
);
}
}
export SearchContext.Consumer as SearchContextConsumer
export default Search;
and here is how you can do above functionality in Function Component which is more readable and less code:
import React, { Component } from "react";
import axios from "axios";
const SearchContext = React.createContext();
const Search = () => {
const [state, setState] = useState({
searchResults: [],
isSearched: false
});
const getSearchQuery = event => {
const queryString = document.querySelector(".search-input").value;
if (event.keyCode === 13) {
axios
.post("http://localhost:3001/search", {
queryString: queryString
})
.then(response => {
setState({ ...state, searchResults: response.data });
});
setState({ ...state, isSearched: true });
window.location.href = "/blog/searchResults";
}
};
return (
<SearchContext.Provider value={state.searchResults}>
<input
type="text"
className="search-input"
onKeyDown={e => getSearchQuery(e)}
/>
</SearchContext.Provider>
);
};
export default Search;
now if you need to use your context data just do this inside provider zone:
const searchResults = React.useContext(SearchContext);
This looks uneccessary complicated to me. Why don't you straight up export the created context and wrap the children
in the Provider directly:
import React, { Component } from "react";
import axios from "axios";
export const SearchContext = React.createContext();
class Search extends Component {
state = {
searchResults: [],
isSearched: false
}
data = { searchResults: this.state.searchResults }
getSearchQuery = (event) => {
const queryString = document.querySelector(
".search-input"
).value;
if (event.keyCode === 13) {
axios.post("http://localhost:3001/search", {
queryString: queryString,
}).then(response => {
this.setState({ ...this.state, searchResults: response.data });
});
this.setState({ ...this.state, isSearched: true });
window.location.href = '/blog/searchResults'
}
};
render() {
return (
<SearchContext.Provider value={searchResults}>
<input
type="text"
className="search-input"
onKeyDown={(e) => this.getSearchQuery(e)}
/>
</SearchContext.Provider>
);
}
}
export default Search;
Components which want to use the context will have to be wrapped inside the Consumer:
import {SearchContext} from "Search"
<SearchContext.Consumer>
{value => /* render something based on the context value */}
</SearchContext.Consumer>

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>
)
}

updating set state in api call react

I'm having issues with setting this.setState from within my API call. If I console.log the stocks array inside the axios call the data is available in the array. It is not available outside if it.
Is the problem because this.setState is merging objects? I'm having a hard time conceptualizing what is happening here. How do I fix this problem so I can pass the contents to props?
import React, { Component } from 'react';
import axios from 'axios';
import SearchBar from './components/search_bar';
import StockList from './components/StockList';
import './App.css';
class App extends Component {
constructor() {
super();
this.state = {
stocks: [],
term: null,
value: ''
};
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({
value: e.target.value
});
}
handleClick(e) {
if(e) e.preventDefault();
this.setState({
value: '',
term: this.state.value
});
let term = this.state.value;
const key = 'F41ON15LGCFM4PR7';
const url = `https://www.alphavantage.co/query?function=BATCH_STOCK_QUOTES&symbols=${term}&apikey=${key}`;
axios.get(axios.get(url)
.then(res => {
let stocks = Array.from(res.data['Stock Quotes']).map((stock) => [{symbol: stock['1. symbol'], price: stock['2. price'], volume: stock['3. volume'], timestamp: stock['4. timestamp']}]);
this.setState((state, props) => {
return [...this.state.stocks]
})
})
.catch(error => console.log(error))
)
}
render () {
let stocks = this.state.stocks;
const value = this.state.value;
return (
<div className="App">
<h1>Stock Search</h1>
<SearchBar value={ value }
onChange={ this.handleChange }
onClick={ this.handleClick }/>
<StockList stockItems={ stocks }/>
</div>
);
}
}
export default App;
Your setState there is the issue, it's messing up the structure of your state.
this.setState((state, props) => {
return [...this.state.stocks]
});
Should be either:
this.setState({
// set stocks to that array you parsed from the axios response
stocks
});
or
this.setState((state, props) => {
return {
...state,
// set stocks to that array you parsed from the axios response
stocks
};
});
I suggest that because you're accessing the stocks via this.state.stocks in your render

Categories