How tell an other component of changement state of redux? - reactjs

I have two components reactjs , I create an state redux to handle this state from two components .
`appcomponent.js
import React, { Component } from 'react';
import { createStore } from 'redux';
import { connect } from 'react-redux';
//reducer
export function get_user(state=[], action) {
switch (action.type) {
case 'ADD_USER':
return [
{user:action.user}
];
default:
return state;
}
}
class appcomponent extends Component {
constructor(props) {
super(props);
this.state = {Users:[]};
//this.addUser=this.addUser.bind(this);
this.onFormSubmit=this.onFormSubmit.bind(this);
this.get=this.get.bind(this);
}
get(){
console.log(this.props.r);
}
onFormSubmit() {
this.props.send('user');
}
render() {
return (
<div>
<br /><br /><br />
<button onClick={this.onFormSubmit}>redux</button><br /><br /><br /><br />
<button onClick={this.get}>REDUX</button>
</div>
)}
}
// action
export function addUser(user) {
return {
type: 'ADD_USER',
user,
};
}
function mapDispatchToProps (dispatch) {
return {
send: user => dispatch(addUser(user))
};
};
const mapStateToProps = (state, ownProps) => {
return { r:state};
};
export default connect(mapStateToProps,mapDispatchToProps)(appcomponent);
In this component when I click "redux" button then onclick "REDUX" button I get the state changed.
In the other component I have this code :
class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div><h1>{this.props.user}</h1></div>
)
}}
const mapStateToProps = (state, ownProps) => {
return { user: state[0].user};//.user
};
function mapDispatchToProps (dispatch) {
return {
get: user => dispatch(addUser('username'))
};
};
export default connect(mapStateToProps,mapDispatchToProps)(App);
In the last component always I get the initial state created in index.js
var store = createStore(get_user,[{user:'hhhh'}]);
ReactDOM.render( <Provider store={store}>
Please who can help me ?

You only need to call createStore() once, preferably near the top of your component tree not in each component.
Assuming you wrap your app in a Provider (from redux) you'll have access to redux's central State via the mapStateToProps function (where you can assign state elements to a particular components props):
import { Provider } from 'react-redux';
import {createStore, combineReducers } from 'redux';
const store = createStore(
combineReducers({
user: usersReducer,
otherThings: otherThingsReducer
})
)
const app = (
<Provider store={store}>
<MainAppComponentOrRouter/>
</Provider>
);
ReactDOM.render(app, document.getElementById("app"));
And then in a component:
const mapStateToProps = (state, props) => {
return {
user: state.user,
otherThings: state.otherThings
};
};
export default connect(mapStateToProps)(MyComponent);

in the first component try use the following code
import React, { Component } from 'react';
import { createStore } from 'redux';
import { connect } from 'react-redux';
//reducer
export function get_user(state={user:[]}, action) {
switch (action.type) {
case 'ADD_USER':
return {
...state,
user:action.user
}
default:
return state;
}
}
class appcomponent extends Component {
constructor(props) {
super(props);
this.state = {Users:[]};
//this.addUser=this.addUser.bind(this);
this.onFormSubmit=this.onFormSubmit.bind(this);
this.get=this.get.bind(this);
}
get(){
console.log(this.props.r);
}
onFormSubmit() {
this.props.send('user');
}
render() {
return (
<div>
<br /><br /><br />
<button onClick={this.onFormSubmit}>redux</button><br /><br /><br /><br />
<button onClick={this.get}>REDUX</button>
</div>
)}
}
// action
export function addUser(user) {
return {
type: 'ADD_USER',
user,
};
}
function mapDispatchToProps (dispatch) {
return {
send: user => dispatch(addUser(user))
};
};
const mapStateToProps = (state, ownProps) => {
return { r:state};
};
export default connect(mapStateToProps,mapDispatchToProps)(appcomponent);
and on the second component use the following code
class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div><h1>{this.props.user}</h1></div>
)
}}
const mapStateToProps = (state, ownProps) => {
return { user: state.user};//.user
};
function mapDispatchToProps (dispatch) {
return {
get: user => dispatch(addUser('username'))
};
};
export default connect(mapStateToProps,mapDispatchToProps)(App);

Related

react/ redux app : actions not dispatching to store

I am creating a react app with redux for state management, I am facing issues when trying to dispatch and action, action is showing in redux devtools but it's not storing data to redux store not sure why it's happening, very unusual
If anyone knows why this happens please do let me know
My component is below
import axios from "axios";
import React, { Component } from "react";
import { connect } from "react-redux";
import { SETDATA } from "./store";
class Hello extends Component {
constructor() {
super();
this.state = {
data: [],
};
}
componentDidMount() {
this.firstdispatch();
}
firstdispatch = () => {
axios.get("https://jsonplaceholder.typicode.com/users").then((r) => {
console.log("data fetched", r.data);
this.props.setdata(r.data);
});
};
render() {
return (
<div>
{" "}
fff
{/* <button onClick={this.props.setdata}>getdata</button>
<button onClick={this.props.removedata}>decriment</button> */}
{/* <button onClick={props.push}>push</button>
<button onClick={props.pop}>pop</button> */}
{console.log(this.props)}
{this.props.users &&
this.props.users.map((m, i) => (
<div key={i}>
{m.title} {` - - - -`} {m.email}
</div>
))}
</div>
);
}
}
const mapstatetoprops = (state) => {
return {
users: state.users.users || [],
};
};
const mapDispatchTopProps = (dispatch) => {
return {
setdata: (users) => {
dispatch({ type: SETDATA, users });
},
};
};
export default connect(mapstatetoprops, mapDispatchTopProps)(Hello);
Actions reducers and store is below
updated
import * as redux from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
export const SETDATA = "users";
export const DELETEDATA = "data/deletedata";
const initSst = {
users: [],
};
const users = (state = initSst, action) => {
switch (action.type) {
case SETDATA:
return { ...state, ...action.data };
case DELETEDATA:
return { data: null };
default:
return state;
}
};
const rootReducer = redux.combineReducers({
users,
});
const store = redux.createStore(
rootReducer,
composeWithDevTools(
redux.applyMiddleware(thunk)
// other store enhancers if any
)
);
export default store;
Just update "SETDATA" to SETDATA in the switch/case
case SETDATA:
return { ...state, ...action.data };
once I updated the initial state to empty array its working
redux, actions, store
import * as redux from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
export const SETDATA = "users";
export const DELETEDATA = "data/deletedata";
const users = (state = [], action) => {
switch (action.type) {
case SETDATA:
return [...action.payload];
default:
return state;
}
};
const rootReducer = redux.combineReducers({
users: users,
});
const store = redux.createStore(
rootReducer,
composeWithDevTools(
redux.applyMiddleware(thunk)
// other store enhancers if any
)
);
export default store;
component
import axios from "axios";
import React, { Component } from "react";
import { connect } from "react-redux";
import { SETDATA } from "./store";
class Hello extends Component {
constructor() {
super();
this.state = {
data: [],
};
}
componentDidMount() {
this.firstdispatch();
}
firstdispatch = async () => {
await axios.get("https://jsonplaceholder.typicode.com/users").then((r) => {
// console.log("data fetched", r.data);
this.props.setdata(r.data);
});
};
render() {
return (
<div>
fff {console.log(this.props.users, "fff")}
{(this.props.users || []).map((m, i) => (
<div key={i}>
{m.title} {m.email}
</div>
))}
</div>
);
}
}
const mapstatetoprops = (state) => {
return {
users: state.users,
};
};
const mapDispatchTopProps = (dispatch) => {
return {
setdata: (users) => {
dispatch({ type: SETDATA, payload: users });
},
};
};
export default connect(mapstatetoprops, mapDispatchTopProps)(Hello);

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!

action does not modify state

I am trying to add user metadata to my store when mounting a screen. However, when I send the action to the reducer, the store is not modified.
I would expect props after sending the action to be as follows:
{addUserMetaData: ƒ addUserMetaData(user_object),
user: {firestore_doc: {name: "Joe"}}
}
What am i missing here?
To reproduce, react-native-init mwe then add the following code. I've added an image of the app logs below.
App.js
import React, { Component} from 'react';
import { View } from 'react-native';
import Screen from './src/screen';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
const userReducer = function userReducer(state = {}, action) {
console.log('action', action);
switch (action.type) {
case "ADD_USER_METADATA":
return { ...state, firestore_doc: action.payload };
default:
return { ...state };
}
};
const store = createStore(userReducer);
export default class App extends Component {
render() {
return (
<Provider store={store}>
<View>
<Screen />
</View>
</Provider>
);
}
};
src/screen.js
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { connect } from 'react-redux';
const addUserMetaData = (user) => ({
type: "ADD_USER_METADATA",
payload: user
})
class Screen extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const user = { name: "Joe" };
console.log('props', this.props);
this.props.dispatch(addUserMetaData(user));
console.log('props after action', this.props);
}
render() {
return (
<View>
<Text>Welcome to react native</Text>
</View>
)
}
}
const mapStateToProps = state => {
return { user: state };
};
export default connect(mapStateToProps)(Screen);
Fixed https://snack.expo.io/#janithar/c3RhY2
Lines I changed
return { ...state, firestore_doc: action.payload };
Please added state.firestore_doc instead of state because in reducer action.payload assign the data in firestore_doc state so you are not getting data from state.user
const mapStateToProps = state => {
return { user: state.firestore_doc };
};

Redux update additional props in component

I have a component which is using redux connect. In this component I have mapStateToProps which getting project from redux state and projectTransform is a value which has filter values from project redux state:
import React, { Component } from 'react';
import PropTypes from "prop-types";
import { connect } from 'react-redux';
class ProjectForm extends Component {
constructor(props){
super(props);
}
componentDidMount() {
const {
fetchProject,
} = this.props;
fetchProject();
}
onClick() {
this.setState({
project1: {
"a": 1,
"b": 2
}
})
}
render() {
const { project1 } = this.props;
return (
<div>
<button onClick={onClick()} />
</div>
)
}
}
ProjectForm.propTypes = {
fetchProject: PropTypes.func.isRequired
};
function mapDispatchToProps (dispatch) {
return
fetchProject: () => dispatch(projectActions.getProjectRequest()),
}
}
function mapStateToProps ( state ) {
const { project} = state
return {
project: project,
project1: ((project) => {
return project[0]
})(project)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ProjectForm)
I trying to now trigger re-rendering on the button but I have not clue how to do it as I tried.
this.setState((previousState) => {
project1: [JSON value from Form]
});
Also why previousState is null I would assume it would have mapStateToProps data.
Any idea how to do it without dispatching whole redux? Or how to do it in a proper way?
The problem was with reading data not from the state but props.
render() {
const { project1 } = this.state;
return (
<div>
<button onClick={onClick()} />
</div>
)
}

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