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)}
Related
So I'm flying by the seat of my pants here, and I need help reordering a data set. Here's the base of my react component. This is a personal project that I'm doing to then reuse at work for an actual project. The base of this came from a YouTube series about React + Firebase: https://www.youtube.com/playlist?list=PL4cUxeGkcC9iWstfXntcj8f-dFZ4UtlN3
Ideally, I'd like a set of buttons that will sort the data from asc or desc. And maybe dependent on some other things.
import React, { Component } from 'react';
import ShopList from '../shops/ShopList.js';
import { Helmet } from 'react-helmet';
import { connect } from 'react-redux';
import { firestoreConnect } from 'react-redux-firebase';
import { compose } from 'redux';
class Dashboard extends Component {
reOrder = (e) => {
e.preventDefault();
console.log("button works!");
}
render() {
const { shops } = this.props;
return(
<div className="dashboard container">
<Helmet>
<title>Dashboard | Indianapolis Coffee Guide</title>
</Helmet>
<div className="row">
<div className="col-sm-6">
<button className="btn btn-primary" onClick={this.reOrder}>Reorder</button>
</div>
</div>
<div className="row">
<ShopList shops={shops} />
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
shops: state.firestore.ordered.coffeeShops,
auth: state.firebase.auth
}
}
export default compose(
connect(mapStateToProps),
firestoreConnect([
{ collection: 'coffeeShops', orderBy: ['shopName', 'asc']}
])
)(Dashboard)
The data is being ordered right now at the end with the orderBy, but I need to be able to update that...
Thanks for your help!
I am not sure it would work, because I have never used react-redux-firebase, but it seems to me you could create a redux action that sets the ordering direction in redux store. Like this:
import React, { Component } from 'react';
import ShopList from '../shops/ShopList.js';
import { Helmet } from 'react-helmet';
import { connect } from 'react-redux';
import { firestoreConnect } from 'react-redux-firebase';
import { compose } from 'redux';
class Dashboard extends Component {
reOrder = (e) => {
e.preventDefault();
console.log("button works!");
const orderDirection = this.props.orderDirection === 'asc' ? 'desc' : 'asc';
this.props.dispatch(ReOderAction(orderDirection));
}
render() {
const { shops } = this.props;
return(
<div className="dashboard container">
<Helmet>
<title>Dashboard | Indianapolis Coffee Guide</title>
</Helmet>
<div className="row">
<div className="col-sm-6">
<button className="btn btn-primary" onClick={this.reOrder}>Reorder</button>
</div>
</div>
<div className="row">
<ShopList shops={shops} />
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
shops: state.firestore.ordered.coffeeShops,
auth: state.firebase.auth,
orderDirection: state.anything.orderDirection,
}
}
export default compose(
connect(mapStateToProps),
firestoreConnect([
{ collection: 'coffeeShops', orderBy: ['shopName', orderDirection]}
])
)(Dashboard)
Please, let me know if it worked...
First Compoent
import React from "react";
import ReactDOM from "react-dom";
import PropTypes from 'prop-types'
import { withRouter } from "react-router-dom";
import { gateway as MoltinGateway } from "#moltin/sdk";
import {getList,updateList} from "./../Action/Action";
import { connect } from "react-redux";
import Icon from '#material-ui/core/Icon';
import Payment from "./../Payment/Payment";
import Tick from './done.png'
export class Item extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.pickItem = this.pickItem.bind(this);
}
UpdateList ={}
pickItem(pickedItem, id) {
//console.log(pickedItem,id)
document.getElementById(id).classList.toggle("active")
this.UpdateList = pickedItem.map(function(data,i){
if(data.id == id && i<=5 && data.pickedItem!=='Yes'){
data.pickedItem = 'Yes'
return data
}else{
data.pickedItem = 'No'
return data
}
});
}
componentWillMount() {
this.props.getList();
}
updateList(){
//console.log(this.UpdateList)
this.props.updateList(this.UpdateList)
this.props.history.push({
pathname: '/Payment',
});
}
render() {
//const { pickedItem } = this.state;
const {list} = this.props
let filtereDate;
if(list!==undefined && list.length>0){
filtereDate = list.map(function(data,i){
if(i<=5){
return(
<div key={data.id} ref={data.id} id={data.id} onClick={this.pickItem.bind(this, list, data.id )} className='item-list'>
<span className="tickMark"><img src={Tick} /></span>
<div className="logoWarapper">
<img
src="https://rukminim1.flixcart.com/image/660/792/jmdrr0w0/shirt/q/q/r/xxl-tblwtshirtful-sh4-tripr-original-imaf9ajwb3mfbhmh.jpeg?q=50"
width="100"
height="100"
alt=""
/>
</div>
<div className="itemWarapper">
<h3>{data.name}</h3>
<p>
<span>₹</span>
<span>{data.id}</span>
</p>
</div>
</div>
)
}
}.bind(this));
}
return (
<div className="ItemPage">
<header>
<h1>Online shopping</h1>
<h2>Visit | Pick | Pay</h2>
</header>
{filtereDate}
<div className="btnWrp">
<button onClick={this.updateList.bind(this)} className="button">Make Payment</button>
</div>
</div>
);
}
}
Item.propTypes = {
list: PropTypes.object,
getList: PropTypes.func,
updateList:PropTypes.func
}
function mapStateToProps(state){
const Items= state
return {
list : Items.list
}
}
const mapDispatchToProps = dispatch => ({
getList: () => dispatch(getList()),
updateList: (list) =>
dispatch(updateList(list))
})
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(Item));
Sages file
import { put, takeLatest, all, call,select } from "redux-saga/effects";
function* fetchNews() {
const json = yield fetch(
"http://petstore.swagger.io/v2/pet/findByStatus?status=available"
).then(response => response.json());
yield put({ type: "GET_LIST_SUCCESS", json: json });
}
function * updateNewList(data){
///console.log(data.payload)
yield put({ type: "GET_LIST_SUCCESS", list: data.payload });
}
function * fetchupateList(){
const signals = yield select(store => store)
console.log(signals)
}
function* actionWatcher() {
yield takeLatest("GET_LIST_REQUEST", fetchNews);
yield takeLatest("GET_UPDATED_LIST_REQUEST", fetchupateList);
yield takeLatest("UPDATE_LIST_REQUEST", updateNewList);
}
export default function* rootSaga() {
yield all([actionWatcher()]);
}
**Second Component **
import React from "react";
import ReactDOM from "react-dom";
import PropTypes from 'prop-types'
import { withRouter } from "react-router-dom";
import { connect } from "react-redux";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
import {getList,updateList,getUpdatedList} from "./../Action/Action";
export class Payment extends React.Component {
constructor(props) {
super(props);
this.state = {
pickedItem: [1, 2]
};
}
componentWillMount() {
this.props.getUpdatedList();
}
render() {
console.log(this.props)
const { pickedItem } = this.state;
//console.log(pickedItem);
return (
<div className="PaymentPage">
<div className="pageWrapper">
<form noValidate autoComplete="off">
<h1>Payment Details</h1>
<TextField
id="outlined-name"
label="Card Type"
margin="normal"
variant="outlined"
/>
<TextField
id="outlined-name"
label="Card Name"
margin="normal"
variant="outlined"
/>
<TextField
id="outlined-name"
label="Card Number"
margin="normal"
variant="outlined"
/>
<div className="clm-2-inp">
<TextField
id="outlined-name"
label="Expiry Date (MM/YYYY)"
margin="normal"
variant="outlined"
/>
<TextField
id="outlined-name"
label="CVV"
margin="normal"
variant="outlined"
/>
</div>
</form>
<div className="itemsection">
<h2>Summery</h2>
<div className="item-list">
<div className="logoWarapper">
<img
src="https://rukminim1.flixcart.com/image/660/792/jmdrr0w0/shirt/q/q/r/xxl-tblwtshirtful-sh4-tripr-original-imaf9ajwb3mfbhmh.jpeg?q=50"
width="100"
height="100"
alt=""
/>
</div>
<div className="itemWarapper">
<h3>Item Name</h3>
<p>
<span>₹</span>
<span>3000</span>
</p>
</div>
</div>
<Button variant="contained" color="primary">
Submit Purchase
</Button>
</div>
</div>
</div>
);
}
}
Payment.propTypes = {
list: PropTypes.object,
getList: PropTypes.func,
updateList:PropTypes.func,
getUpdatedList:PropTypes.func
}
function mapStateToProps(state,ownProps){
console.log(state,ownProps)
const Items= state
return {
list : Items.list
}
}
const mapDispatchToProps = {
getList,
updateList,
getUpdatedList
};
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(Payment));
Reducer
const initialState = {
list: {}
}
const Reducer = (state = initialState, action) => {
switch (action.type) {
case "GET_LIST_SUCCESS":
return {
...state,
list: action.json,
}
case "GET_LIST_SUCCESS":
return {
...state,
list: action.list,
}
default:
return state;
}
};
export default Reducer;
Once i click the "Make payment" button in the first component, i will updated the list with some modification those modified changes i want to get in the second component.
I unable to get first redux store value in the second component.
Help me to ix this issue please.
Ive created a Rexux store. In my entry point I can add an item to my store and see that it works:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import allReducers from './reducers';
import { ADD_TODO_ITEM } from './actionCreators';
import App from './components/containers/App';
let store = createStore(allReducers);
store.subscribe(() => console.log(store.getState()));
store.dispatch(ADD_TODO_ITEM('test 1'));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
Im trying to use this action dispatcher in my component. When I submit the form below I get the error:
TypeError: dispatch is not a function
I think Im not passing dispatch to AddTodo, but how do you pass dispatch to component?
import React from 'react';
import { ADD_TODO_ITEM } from '../../actionCreators';
const AddTodo = ({ dispatch }) => {
let input;
return (
<form
onSubmit={e => {
e.preventDefault();
const text = input.value;
console.log(text);
dispatch(ADD_TODO_ITEM(text));
}}
>
<input
type="text"
ref={node => {
input = node;
}}
/>
<button type="submit">Add Item</button>
</form>
);
};
export default AddTodo;
In your case, this.props is empty because you haven't passed any props or connected your component to your redux state. In order to have dispatch in your component, you'll need to use connect from react-redux which takes 2 arguments, one being mapStateToProps and other is mapDispatchToProps. The code goes something like this:
import React from 'react';
import {connect} from 'react-redux';
import { ADD_TODO_ITEM } from '../../actionCreators';
const AddTodo = ({ addItem }) => {
let input;
return (
<form
onSubmit={e => {
e.preventDefault();
const text = input.value;
console.log(text);
dispatch(addItem(text));
}}
>
<input
type="text"
ref={node => {
input = node;
}}
/>
<button type="submit">Add Item</button>
</form>
);
};
const mapDispatchToProps = (dispatch) => {
return {
addItem: (item) => {
dispatch(ADD_TODO_ITEM(item));
}
}
};
export default connect(undefined, mapDispatchToProps)(AddTodo);
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;
I am trying to dispatch a redux action when an element is clicked. Here is how I currently have things set up
the action
export function removeItem(idx) {
// remove the item at idx
return {
type: "DESTROY_ITEM",
payload: {idx: idx}
}
}
container component
import ItemUi from '../ui/Item';
import { connect } from 'react-redux'
import { removeItem } from '../../actions'
const mapDispatchToProps = dispatch => {
return({
destroyItem: (index) => {
dispatch(
removeItem(index)
)
}
})
}
export default connect(null, mapDispatchToProps)(ItemUi)
ui component
import React, { Component, PropTypes } from 'react';
class Item extends Component {
// ... methods removed for length
render() {
return (
<div>
<span
className="btn btn-primary btn-xs glyphicon glyphicon-trash"
onClick={() => {this.props.destroyItem(this.props.index)}}></span>
</div>
)
}
}
DestroyItem.propTypes = {
onRemoveItem: PropTypes.func
}
export default Item
the top level component
import React, { Component } from 'react';
import Item from './Item'
class App extends Component {
render() {
return(
<div className="container">
<NewItem/>
<ClearAll/>
<div className="panel-group" id="accordion">
{this.props.item.map(this.eachItem)} // <-- renders each item
</div>
</div>
)
}
}
export default App;
When the user clicks the span element shown in the Item ui component I want to fire the destroyItem action passing in the component's index prop. Instead I get the error
TypeError: _this2.props.destroyItem is not a function
Can you please provide some guidance on how I should do this? Let me know if there is any other useful context I can provide.
Try:
const mapDispatchToProps = {
destroyItem: removeItem
}