React Redux Input handle - redux

I'm trying to handle simple input value using react-redux and then trying to display it. I know how to display it but i have no idea how to submit input value from component to redux store. I searched web and found nothing. Can someone explain how to do this? I'm totally new to react-redux
import React from "react";
import "./App.css";
import { connect } from "react-redux";
import { useState } from "react";
import { updateValue, addValue } from "./actions/inputActions";
function App(props) {
const [value, setValue] = useState("");
const handleChange = (e) => {
setValue(e.target.value);
};
return (
<div className="App">
<form onSubmit={(value) => props.submitValue(value)}>
<input onChange={handleChange} value={value} type="text" />
<button type="submit">Add</button>
</form>
<h1>{props.value}</h1>
</div>
);
}
const mapStateToProps = (state) => {
return {
value: state.value,
};
};
const mapDispatchToProps = (dispatch) => {
return {
submitValue: (e, value) => {
e.preventDefault();
dispatch(addValue(value));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);

Update your onSubmit function with the value stored in your local state, like this:
<form onSubmit={(e) => {
e.preventDefault();
props.submitValue(value)
}}>
<input onChange={handleChange} value={value} type="text" />
<button type="submit">Add</button>
</form>
And your mapDispatchToProps function like this:
const mapDispatchToProps = (dispatch) => {
return {
submitValue: (value) => {
dispatch(addValue(value));
},
};
};

Related

What do I need to do that appendChild and addEventListener is going to work?

I can see the issue here. Stuff is going to fetch before it's still there in the order of code execution, but I don't know how to fix that at all.
I want to grab some infos from my firebase firestore database and put it in the dom in a way I can show it of nicely.
The other thing is, css file isn't working cause of the same issue. When I setAttribute to it it's already initialized and of course, it wouldn't show up at all (for example: border: 50% to make the pic round).
What do I miss to learn?
import React from "react";
import firebase from "./firebase";
import "./artists-styles.css";
const db = firebase.firestore();
const form = document.querySelector("#add-artist-avatar");
function renderArtists(doc) {
const artistsAvatar = document.querySelector(".content");
let image = document.createElement("img");
image.setAttribute("src", doc.data().avatar);
artistsAvatar.appendChild(image);
}
// getting data
db.collection("artists")
.get()
.then(snapshot => {
console.log(snapshot.docs);
snapshot.docs.forEach(doc => {
console.log(doc.data());
renderArtists(doc);
});
});
// saving data
form.addEventListener("submit", e => {
e.preventDefault();
db.collection("artists").add({
avatar: form.avatar.value,
});
form.name.value = "";
});
const Artists = () => {
return (
<div>
<h1>Cloud Cafe</h1>
<form id="add-artist-avatar">
<input type="text" name="avatar" placeholder="Artists Avatar Link" />
<button>Add Avatar</button>
</form>
<div className="content"></div>
</div>
);
};
export default Artists;
Perhaps you need something like this
import React, { useEffect, useState } from "react";
import firebase from "./firebase";
import "./artists-styles.css";
const db = firebase.firestore();
const Artists = () => {
const [docs, setDocs] = useState([]);
const [inputValue, setInputValue] = useState('');
useEffect(() => {
db.collection("artists")
.get()
.then(snapshot => {
console.log(snapshot.docs);
setDocs(snapshot.docs);
});
}, []);
const handleSubmit = e => {
e.preventDefault();
db.collection("artists").add({
avatar: inputValue
});
};
return (
<div>
<h1>Cloud Cafe</h1>
<form id="add-artist-avatar" onSubmit={(e) => handleSubmit(e)}>
<input
type="text"
name="avatar"
placeholder="Artists Avatar Link"
value={inputValue}
onChange={e => setInputValue(e.target.value)}
/>
<button>Add Avatar</button>
</form>
<div className="content">
{docs.map(doc => (
<img src={doc.data().avatar}/>
))}
</div>
</div>
);
};
export default Artists;

Running code shows 'this.props.dispatch is not a function' after adding mapDispatchToProps

Let me tell you, this code were working fine and showing all products in shop page but after adding mapDispatchToProps.
it giving error:- TypeError: this.props.getProducts is not a function
mapStateToProps is giving products.
Trying to post data using mapDispatchToProps.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getProducts } from '../actions/productsAction';
import { addToCart } from '../actions/cartAction';
class Shop extends Component {
constructor(props) {
super(props);
this.state = {
pid: '',
pname: '',
pprice: '',
pimg: '',
qty: '',
total_price: '',
getValue:[]
};
}
componentDidMount() {
this.props.dispatch(getProducts());
let getValue = localStorage.getItem("userData");
this.setState({
getValue: JSON.parse(getValue),
});
}
handleSubmit = (event) => {
event.preventDefault();
const pid = this.state.pid;
const pname = this.state.pname;
const pprice = this.state.pprice;
const pimg = this.state.pimg;
const qty = this.state.qty;
const total_price = this.state.total_price;
const email = this.state.getValue.email;
const CartData = {pid: pid, pname: pname, pprice: pprice, pimg: pimg, qty:qty, total_price:total_price}
this.props.addToCart(CartData);
};
render() {
return (
...html code
<form onSubmit={ this.handleSubmit }>
<input type="hidden" onChange={this.handleChange} name="pid" value={product._id} />
<input type="hidden" onChange={this.handleChange} name="pname" value={product.pname} />
<input type="hidden" onChange={this.handleChange} name="pprice" value={product.pprice} />
<input type="hidden" onChange={this.handleChange} name="qty" value="1" />
<input type="hidden" onChange={this.handleChange} name="pimage" value={product.pimg} />
<input type="hidden" onChange={this.handleChange} name="total_price" value={product.pprice} />
<button type="submit" class="pro-btn"><i class="icon-basket"></i></button>
</form>
...html code
const mapStateToProps = (state) => ({ products: state.products });
const mapDispatchToProps = { addToCart };
export default connect(mapStateToProps, mapDispatchToProps)(Shop);
You have not defined the mapDispatchToProps properly.
It should look like below,
const mapDispatchToProps = (dispatch) => {
return {
addToCart: () => dispatch(addToCart()),
getProducts: () => dispatch(getProducts())
}
};
And you should call the function directly using props
componentDidMount() {
this.props.getProducts();
let getValue = localStorage.getItem("userData");
this.setState({
getValue: JSON.parse(getValue),
});
}
You have two actions that you want to use in your component, so you'll want to include them both in your mapDispatchToProps object. The function notation described by #AmilaSenadheera will work, but the object shorthand is easier.
const mapDispatchToProps = {
addToCart,
getProducts
};
Then you should be able to call this.props.getProducts().

Why is my method not working? react-redux

I am studying react-redux. First of all, the action of addTodo looks like this.
let nextTodoId = 0;
export const addTodo = (content) => ({
type: ADD_TODO,
payload: {
id: ++nextTodoId,
content
}
});
And the component is here
import React, { useState } from "react";
import { connect } from "react-redux";
import { addTodo } from "../redux/actions";
function AddTodoComponent(props) {
const [inputValue, setInput] = useState("");
console.log({ addTodo })
const handleAddTodo = () => {
console.log(inputValue)
props.addTodo(inputValue);
setInput("");
};
return (
<div>
<input onChange={(e) => setInput(e.target.value)} />
<button className="add-todo" onClick={handleAddTodo}>
Add Todo
</button>
</div>
);
}
export default connect(null, { addTodo })(AddTodoComponent);
I want to use mapStateToProps and mapDispatchToProps but It's not working.
I thought It will be work if I use destructing object.
But it's not appear in console too.
Am I wrong?
import React, { useState } from "react";
import { connect } from "react-redux";
import { addTodo } from "../redux/actions";
function AddTodo({
allId,
byId,
newTodo,
}) {
const [inputValue, setInput] = useState("");
const handleAddTodo = () => {
newTodo(inputValue);
setInput("");
};
return (
<div>
<input onChange={(e) => setInput(e.target.value)} />
<button className="add-todo" onClick={handleAddTodo}>
Add Todo
</button>
</div>
);
}
const mapStateToProps = state => {
return {
allId: state.allId,
byId: state.byId,
}
}
const mapDispatchToProps = dispatch => {
return {
newTodo: () => dispatch(addTodo()),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(AddTodo);
and this is reducer function.
import { ADD_TODO, TOGGLE_TODO } from "../actionTypes";
const initialState = {
allIds: [],
byIds: {}
};
export default function(state = initialState, action) {
switch (action.type) {
case ADD_TODO: {
const { id, content } = action.payload;
return {
...state,
allIds: [...state.allIds, id],
byIds: {
...state.byIds,
[id]: {
content,
completed: false
}
}
};
}
case TOGGLE_TODO: {
const { id } = action.payload;
return {
...state,
byIds: {
...state.byIds,
[id]: {
...state.byIds[id],
completed: !state.byIds[id].completed
}
}
};
}
default:
return state;
}
}
It took me a bit of playing but I found your problem! (3 problems, actually).
Your addTodo function is a function which takes the content of the Todo (a string) and creates the action.
const mapDispatchToProps = (dispatch) => {
return {
newTodo: () => dispatch(addTodo())
};
};
But in your mapDispatchToProps function, you are accepting no arguments and calling addTodo with no arguments. So your Todo gets added, but the content will always be undefined.
Change this to
newTodo: (content) => dispatch(addTodo(content))
In mapStateToProps you've got a misnamed property. You need to change state.byId to state.byIds.
In order to clear the content of the input, you need the value of the input to be controlled by your useState. Add value={inputValue} to the input element.
<input value={inputValue} onChange={(e) => setInput(e.target.value)} />
This is a sidenote, but you might want to think about learning typescript and adding annotations to your projects. There is a bit of a learning curve but the tradeoff is you would be able to catch things like missing arguments and misnamed properties easily. They can be a real head-scratcher otherwise.

Redux is not getting any data

I'm new to Redux. It's really confusing to understand basic syntax. None of the bugs are found so It's hard to figure out what's wrong with my code.
It worked well last week, I don't remember what I have changed.
//child component
import React, { Component } from 'react';
import { SingleDatePicker } from 'react-dates';
import moment from 'moment';
class InputForms extends Component {
state = {
inputs: ['input-0'],
title: '',
tag: '',
createdAt: moment(),
imageLinks: [''],
calendarFocused: false,
error: '',
}
appendInput(e) {
const newInput = `input-${this.state.inputs.length}`;
this.setState({ inputs: this.state.inputs.concat([newInput]) });
}
onTitleChange = (e) => {
const title = e.target.value;
this.setState(() => ({ title }));
};
onTagChange = (e) => {
const tag = e.target.value;
this.setState(() => ({ tag }));
};
onImageLinkChange = (e) => {
const imageLinks = e.target.value;
this.setState(() => ({ imageLinks: this.state.imageLinks.concat([imageLinks]) }));
};
onDateChange = (createdAt) => {
if (createdAt) {
this.setState(() => ({ createdAt }));
}
};
onFocusChange = ({ focused }) => {
this.setState(() => ({ calendarFocused: focused }));
};
onSubmit = (e) => {
e.preventDefault();
if (!this.state.title || !this.state.imageLinks) {
this.setState(() => ({ error: '제목과 이미지링크를 입력해주세요' }));
} else {
this.setState(() => ({ error: '' }));
this.props.onSubmit({
title: this.state.title,
tag: this.state.tag,
createdAt: this.state.createdAt.valueOf(),
imageLinks: this.state.imageLinks,
});
}
}
render() {
return (
<div>
<form onSubmit={this.onSubmit}>
<input
type="text"
placeholder="제목을 입력하세요"
required
value={this.state.title}
onChange={this.onTitleChange}
/>
<input
type="text"
placeholder="태그를 입력하세요"
value={this.state.tag}
onChange={this.onTagChange}
/>
<SingleDatePicker
date={this.state.createdAt}
onDateChange={this.onDateChange}
focused={this.state.calendarFocused}
onFocusChange={this.onFocusChange}
numberOfMonths={1}
isOutsideRange={() => false}
/>
{this.state.inputs.map((input, key) => {
return <input
key={input}
type="text"
required
value={this.state.imageLinks}
onChange={this.onImageLinkChange}
placeholder={`이미지링크 ${key + 1}`}
/>
})}
<button>저장</button>
</form>
</div>
)
}
}
export default InputForms;
//parent component
import React, { Component } from 'react';
import { connect } from 'react-redux';
import configureStore from '../store/configureStore';
import InputForms from './InputForms';
import { addPost } from '../actions/posts';
const store = configureStore();
class CreatePost extends Component {
onSubmit = (post) => {
this.props.addPost(post);
this.props.history.push('/');
};
render(){
return(
<div>
<InputForms onSubmit={this.onSubmit}/>
</div>
)
}
}
const mapDispatchToProps = (dispatch, props) => ({
addPost: (post) => dispatch(addPost(post))
});
export default connect(undefined, mapDispatchToProps)(CreatePost);
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import configureStore from './store/configureStore';
import registerServiceWorker from './registerServiceWorker';
import AppRouter from './routers/AppRouter';
import 'normalize.css/normalize.css';
import './style/style.css';
import 'react-dates/lib/css/_datepicker.css';
import 'react-dates/initialize';
const store = configureStore();
const jsx = (
<Provider store={store}>
<AppRouter />
</Provider>
);
ReactDOM.render(jsx, document.getElementById('root'));
registerServiceWorker();
//action
import database from '../firebase/firebase';
//Add Posts
export const addPost = (post) => ({
type: 'ADD_POST',
post
});
//reducer
const postReducerDefaultState = [];
export default (state = postReducerDefaultState, action) => {
switch (action.type) {
case 'ADD_POST':
return [
...state,
action.post
];
default:
return state;
}
};
In your reducer, you return as below
return [ ...state, action.post];
Reducer doesnt return array, but instead returning objects. Secondly, action.post is a value, you need to assign this to key, something like below:
return { ...state, post: action.post };

InitialValues aren't populating redux form

At the moment, I'm having difficulty populating the input fields for a redux form with initial values. Could someone please tell me what's wrong with the following code, or if this is a known issue? Thanks for the help and support.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm, reset, initialize } from 'redux-form'
const renderField = props => (
<div>
<label>{props.placeholder}</label>
<div>
<input {...props}/>
{props.touched && props.error && <span>{props.error}</span>}
</div>
</div>
)
class EditArtist extends Component {
render() {
const { initialValues} = this.props;
console.log(initialValues)
return (
<form>
<Field name="name" component={renderField} type="text" placeholder="Name"/>
</form>
)
}
}
const validate = values => {
const errors = {};
return errors;
}
const mapStateToProps = (state) => ({
initialValues: {
name: "COOL"
}
});
export default connect(mapStateToProps)(reduxForm({
form: 'edit_artist_form',
validate,
enableReinitialize: true
})(EditArtist));

Resources