How to pass data between react embeddable widgets using redux - reactjs

I have two widgets called "search widget" and "Name Widget", and I build those widget using webpack. I want to pass data from search widget to name widget. This is not like passing data from one component to another component. Below image shows that widgets.
This is the script tags I used.
action.js
export const addReminder = text => ({
type : "ADD_REMINDER",
payload : text
});
reducer.js
const initialState = {
reminders : []
};
const nameReducer = (state = initialState , action) => {
switch(action.type){
case 'ADD_REMINDER':
console.log("Name reducer action - ",action.payload);
return {
...state,
reminders: [...state.reminders, action.payload]
}
default:
return state;
}
}
export default nameReducer;
store.js
import nameReducer from '../reducers/nameReducer';
import { createStore} from 'redux';
const store = createStore(
nameReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store;
search component code
import { addReminder } from '../Redux/actions/nameAction';
import { connect } from 'react-redux';
class searchComponent extends Component {
constructor() {
super();
this.state = {
name: '',
};
}
onChange(e) {
this.setState({
name: e.target.value,
});
}
onSubmit(e) {
e.preventDefault();
this.props.addReminder(this.state.name);
console.log("this is the form text", this.props.reminders);
}
render () {
return (
<div>
<form>
<input
type="text"
value={this.state.name}
onChange={e => this.onChange(e)} />
<br/><br/>
<button type="submit" onClick={e => {this.onSubmit(e)}}>Submit</button>
</form>
</div>
);
}
}
const mapStateToProps = (state) => ({
reminders: state.reminders
});
export default connect(mapStateToProps, {addReminder})(searchComponent);
name component code
import React, { Component } from 'react';
import { connect } from 'react-redux';
class nameComponent extends Component {
render() {
return (
<div>
<p>{this.props.reminders}</p>
</div>
)
}
}
const mapStateToProps = (state) => ({
reminders: state.reminders
});
export default connect(mapStateToProps)(nameComponent);
What I want is, when I enter something in search component and press submit button, the search value must display in the name component. But in the name component this.props.reminders didn't get any result. Do I need to pass variable in the script tag or How can I pass data from one widget to another widget?

Related

Pass text value to another component

How to pass text value to another component using Redux in React?
I am learning Redux in React. I am trying to pass text value to another component using Redux in React.
My code is like below
Mycomponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
class Mycomponent extends Component {
state = {
textInput: '',
}
handleChange = event => {
this.props.dispatch({ type: "add" });
}
render = () => {
return (
<div>
<input
type="text"
onChange={this.handleChange} />
</div>
);
}
}
const mapStateToProps = state => ({ nameState: state.nameState});
export default connect(mapStateToProps)(Mycomponent);
nameAction.js
export const nameAction = () => ({
type: 'add'
});
export default { nameAction };
nameReducer.js
const nameReducer = (state = {}, action) => {
switch (action.type) {
case 'add': {
return {
...state,
nameState: action.payload
};
}
default:
return state;
}
};
export default nameReducer;
Outputcomponent.js
import React, { Component } from 'react';
class Outputcomponent extends Component {
render = (props) => {
return (
<div>
<div>{this.props.nameState }</div>
</div>
);
}
}
export default Outputcomponent;
The use of redux hooks explained by Josiah is for me the best approach but you can also use mapDispatchToProps.
Even if the main problem is that you don't pass any data in your 'add' action.
nameAction.js
You call the action.payload in nameReducer.js but it does not appear in your action
export const nameAction = (text) => ({
type: 'add',
payload: text
});
Mycomponent.js
Then as for your state we can mapDispatchToProps.
(I think it's better to trigger the action with a submit button and save the input change in your textInput state, but I guess it's intentional that there is none)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {nameAction} from './nameAction'
class Mycomponent extends Component {
state = {
textInput: '',
}
handleChange = event => {
this.props.nameAction(event.target.value);
}
render = () => {
return (
<div>
<input
type="text"
onChange={this.handleChange} />
</div>
);
}
}
const mapStateToProps = state => ({ nameState: state.nameState});
const mapDispatchToProps = dispatch => ({ nameAction: (text) => dispatch(nameAction(text))});
export default connect(mapStateToProps,mapDispatchToProps)(Mycomponent);
OutputComponent.js
to get the data two possibilities either with a class using connect and mapStateToProps , or using the useSelector hook with a functional component.
with a Class
import React, { Component } from "react";
import { connect } from "react-redux";
class OutputComponent extends Component {
render = () => {
return (
<div>
<div>{this.props.nameState}</div>
</div>
);
};
}
const mapStateToProps = state => state;
export default connect(mapStateToProps)(OutputComponent);
with a functional component
import React from "react";
import { useSelector } from "react-redux";
const OutputComponent = () => {
const nameState = useSelector((state) => state.nameState);
return (
<div>
<div>{nameState}</div>
</div>
);
};
export default OutputComponent;
Of course you must not forget to create a strore and to provide it to the highest component
store.js
import { createStore } from "redux";
import nameReducer from "./nameReducer";
const store = createStore(nameReducer);
export default store;
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
Component
const AddTodo = () => {
const [todo, setTodo] = useState("");
const dispatch = useDispatch();
const handleChange = (e) => setTodo(e.target.value);
const handleSubmit = (e) => {
e.preventDefault();
dispatch(addTodoAction(todo));
}
return {
<form onSubmit={handleSubmit}>
<input type="text" onChange={handleChange} />
</form>
}
)
Actions
const addTodoAction = (text) => {
dispatch({
type: "ADD_TODO",
payload: text
})
}
Reducers
const addTodoReducer = (state, action) => {
switch(action.type) {
case "ADD_TODO":
return {
todo: action.payload,
}
default:
return state;
}
}
store
// some code for store.js
Accessing this todo from another component
const ComponentA = () => {
const {todo} = useSelector(state => state.todo);
return (
<p> {todo} </p>
)
}
Side Note:
Redux comes with too much boilerplate if you want to pass text from one component to another, just use props

Redux state changes back to Intital state

I am creating a web app where a user chooses a restaurant on one screen and the name of the restaurant is stored and then the menu screen checks the state for the restaurant name and gets the menu items from the server for that restaurant. When I press the button in userscreen.js the first time, the state doesn't change but it does change the next time. However, when I check the state from menu.js it is still the initialized state, which is empty. How do I get the state to not change back to its original value?
Here are the files im working on:
userscreen.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { setRestaurant } from '../actions/restaurant';
class Userscreen extends Component {
constructor(props){
super(props);
this.state={
r2:'',
};
this.handleClick1 = this.handleClick1.bind(this);
}
componentDidMount(){
fetch('api/rest-ratings', {
method: 'GET'
})
.then(res => res.json())
.then(body =>{
this.setState({r2: body.C})
})
}
handleClick1(event){
event.preventDefault()
this.props.setRestaurant("ChopChop");
console.log(this.props.rest)
}
render() {
return (
<div>
<img src={user_background} alt="" style= {{width: "100%", height: "auto", margin:"0auto"}}/>
<div id="btn2" onClick={this.handleClick1}>
Chop Chop
<div>
<StarRatingComponent name="ChopChop" editing={false} starCount={5} value={parseInt(this.state.r2)}/>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
rest: state.rest,
})
export default connect(mapStateToProps, { setRestaurant })(Userscreen)
menu.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { setRestaurant } from '../actions/restaurant';
class Menu extends Component {
constructor(props){
super(props);
this.state={
rest1: 'abc',
};
}
componentDidMount(){
console.log("mine",this.state.rest1)
console.log("store",this.props.rest)
}
render() {
return (
<div>
{this.state.rest}
</div>
);
}
}
const mapStateToProps = (state) => ({
rest: state.rest
})
export default connect(mapStateToProps, {setRestaurant})(Menu);
restaurant.js
export const setRestaurant = (restaurant) => dispatch => {
dispatch({
type: 'SET_RESTAURANT',
payload: restaurant
})
}
restReducer.js
const initialState = {
restaurant : ''
}
export default function(state = initialState, action ) {
switch(action.type) {
case 'SET_RESTAURANT':
return {
...state,
restaurant: action.payload,
}
default:
return state;
}
}
index.js
import { combineReducers } from 'redux';
import errorReducer from './errorReducer';
import authReducer from './authReducer';
import restReducer from './restReducer';
export default combineReducers({
errors: errorReducer,
auth: authReducer,
rest: restReducer
});
Your dispatch binder function should be defined as a simple action creator if it is going to be used like it is in export default connect(mapStateToProps, {setRestaurant})(Menu);:
export const setRestaurant = restaurant => ({
type: 'SET_RESTAURANT',
payload: restaurant
})
See defining mapDispatchToProps as an object
Also note that the mapStateToProps function passes the returned object via the props (as the name suggests) so using those passed in props should be done through this.props (instead of this.state).
return (
<div>{this.props.rest.restaurant}</div>
)

Type error when calling mapped action - mapping actions to props react/redux

I am trying to map an action to props however however I'm getting an error:
TypeError: _this2.props.updateUsername is not a function
How does one successfully map redux actions to props and call the function successfully? I havnt seen this error pop up in any other stackoverflow question/answers is it a simple mistake? Could it be a wrong setup of redux in .index or .app?
I have tried:
- importing without using default export
- having different formats of mapDispatchToProps (eg without using bindactioncreators)
- fixing typos
Component:
import { updateUsername } from "../../actions/user-actions";
import React, { Component } from "react";
import { InputText } from "primereact/inputtext";
import { Button } from "primereact/button";
import { Password } from "primereact/password";
import "./UserLogin.css";
import { connect } from "react-redux";
import { bindActionCreators } from 'redux'
export class UserLoginPage extends Component {
constructor(props) {
super(props);
this.state = { //used to be using states so ill leave these here for now
username: "",
password: "",
renderTryAgain: false
};
this.checkLoginDetails.bind(this.checkLoginDetails);
}
async checkLoginDetails() {
...
}
render() {
const usernameBox = (
<InputText
...
value={this.props.username}
onChange={e => this.props.updateUsername(e.target.value)}
/>
);
const passwordBox = (
<Password
...
/>
);
const loginButton = (
<Button
...
/>
);
return (
<header className="User-login">
<p>Dashboard User Login</p>
<div className="p-grid">
<div className="p-col">{usernameBox}</div>
<div className="p-col">{passwordBox}</div>
<div className="p-col">{loginButton}</div>
</div>
</header>
);
}
}
const mapStateToProps = state => ({
username: state.username
});
const mapDispatchToProps = dispatch => bindActionCreators(
{
updateUsername,
},
dispatch,
)
export default connect(
mapStateToProps,
mapDispatchToProps
)(UserLoginPage);
Reducers:
import { UPDATE_USERNAME} from '../actions/user-actions'
export function passReducer(state = "", {type, payload}) {
switch (type) {
case true:
return payload
default:
return state
}
}
export function usernameReducer(state = '', {type, payload}) {
switch (type) {
case UPDATE_USERNAME:
return payload.username
default:
return state
}
}
export default { passReducer, usernameReducer };
Action:
export const UPDATE_USERNAME = 'username:updateUsername'
export function updateUsername(newUsername){
return {
type: UPDATE_USERNAME,
payload: {
username: newUsername
}
}
}
export default {UPDATE_USERNAME, updateUsername}
Many Thanks
Can you check once after updating your constructor as below?
constructor(props) {
super(props);
//...
}
Don't use mapDispatchToProps. Instead just wrap all the actions you want to map inside an object and pass them as the second argument to the connect helper method.
Like this connect(mapStateToProps, { updateUsername })(UserLoginPage)
Hope this helps!

Actions may not have an undefined "type" property. Have you misspelled a constant in reactjs,redux

hello guys i'm new to react and redux .when i click a submit button Form.jsx an will dispatch but it shows type property undefined.any idea.
This is the image link of my error
https://imgur.com/a/aby1bci
this my store code below
import { createStore, applyMiddleware, compose } from "redux";
import rootReducer from "../reducers/index";
import { forbiddenWordsMiddleware } from "../middleware";
const storeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ||
compose;
const store = createStore(
rootReducer,
storeEnhancers(applyMiddleware(forbiddenWordsMiddleware))
);
export default store;
my action code below
import { ADD_ARTICLE } from "../constants/action-types";
export function addArticle(payload) {
return { type: ADD_ARTICLE, payload };
}
here is my Form component looks like below code
import React, { Component } from "react";
import { connect } from "react-redux";
import uuidv1 from "uuid";
import { addArticle } from "../actions/index";
function mapDispatchToProps(dispatch) {
return {
addArticle: article => dispatch(addArticle(article))
};
}
class ConnectedForm extends Component {
constructor() {
super();
this.state = {
title: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const { title } = this.state;
const id = uuidv1();
this.props.addArticle({ title, id });
this.setState({ title: "" });
}
render() {
const { title } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="title">Title</label>
<input
type="text"
className="form-control"
id="title"
value={title}
onChange={this.handleChange}
/>
</div>
<button type="submit" className="btn btn-success btn-lg">
SAVE
</button>
</form>
);
}
}
const Form = connect(
null,
mapDispatchToProps
)(ConnectedForm);
export default Form;
ADD_ARTICLE type should be in quotes like so:
// Action creator
export const addArticle = (article) => {
// returns an action
return {
type: 'ADD_ARTICLE',
payload: article
};
};
Notice how I implement the payload as well, you may want to take a look at that too.
Additionally, study and review ES6 syntax so you can avail yourself of the power of arrow functions and avoid having to use so many bind(this) and subsequently have cleaner code.
I think your mapDispatchToProps method is wrong. It must be something like below:
const mapDispatchToProps = {
addArticle
}

Child component not connecting to store

I have a component that connects to a store and displays a child component like below:
render() {
return <div>
<div className="userBox">
<ProfilePhoto userid={this.props.id} />
</div>
<div className="nameTitleBox">
<div className="firstLastTitle">
<h1>{this.props.firstName} {this.props.lastName}</h1>
</div>
<IDBox userid={this.props.id} />
</div>
<div className="childcomponent">
<childComponent />
</div>
<div className="profileBox">
<EditInterests interestsList={this.props.interest} />
</div>
</div>
}
}
export default connect(
(state) => state.user,
UserState.actionCreators
)(User);
I want the child component to be a smart component that loads it's own data and controls everything itself. The code for it is pretty simple.
import * as React from 'react';
import { Link, RouteComponentProps } from 'react-router-dom';
import { ApplicationState } from '../../store';
import { connect } from 'react-redux';
import * as ChildState from '../../store/childStore';
export class ChildComponent extends React.Component {
componentWillMount() {
this.props;
}
render() {
return (<div>
<div className="textCenter"><h2 id="sss">{this.props.text}</h2></div>
<div className="textRight">
<input type="button" className="button" value="Yes" /> <b className="textColor">No</b>
</div>
</div>
</div>
</div>)
}
}
const mapDispatchToProps = (dispatch) => {
return {
action: dispatch(ChildState.actionCreators.requestChildren())
}
}
export default connect(
mapDispatchToProps,
ChildState.actionCreators
)(ChildComponent);
this.props in the child component is always an empty object. Nothing from the child state is in there, the initial state, the actions, dispatch...anything. I've tried a few different things. ChildState loads fine if I actually load it in the parent. Don't know why it's not loading in the child and connecting the props.
Adding the store below:
import { Action, Reducer } from 'redux';
import { fetch, addTask } from 'domain-task';
import { AppThunkAction } from './';
export const actionCreators = {
requestChildren: () => (dispatch, getState) => {
let url = 'random';
var myheaders = new Headers();
myheaders.append("X-Requested-With", "XMLHttpRequest");
let fetchTask = fetch(url, {
headers: myheaders,
credentials: "same-origin"
})
.then(response => response.json())
.then(data => {
dispatch({ type: 'POST_ACTION', children: data });
});
addTask(fetchTask);
}
}
export const initialState = { ... };
export const reducer = (state = initialState, incomingAction) => {
const action = incomingAction;
switch (action.type) {
case 'REQUEST_ACTION':
return {
...
};
case 'POST_ACTION':
return {
...
};
default:
}
return state || initialState;
};
I believe the problem is in mapDispatchtoProps have you tried using bindActionCreators
bindActionCreators make sure action (ChildState.actionCreators.requestChildren) flows through the middleware if there is any and then to the reducers
import { bindActionCreators} from 'redux';
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
ChildState.actionCreators.requestChildren}, dispatch); }
export default connect(
ChildState.actionCreators,
mapDispatchToProps
)(ChildComponent);
This was happening because I was exporting both the child component and the connect function. I removed the export on the child component and its working now as expected.

Resources