How and where call function in component conditionally based on redux state - javascript

i have a component and in my component i have some child component.
in my parent component i have some function and i want to trigged it from child component. So i make it with redux.
It's my parent component:
import React, { Component } from "react";
import { withRouter } from "react-router-dom";
import { bindActionCreators } from "redux";
import { splashStop } from "store/actions/Home/splashStop";
import { connect } from "react-redux";
class Home extends Component {
constructor(props) {
super(props);
this.state = {
};
this.goPage = this.goPage.bind(this);
}
componentDidMount() {
}
goPage = () => {
this.props.history.push("/agencies");
};
render() {
if (this.props.homeSplash.splashStart == true) {
myTime.play();
}
return (
<div>
<ChildComponent />
</div>
);
}
}
const mapStateToProps = state => ({
homeSplash: state.homeSplash
});
function mapDispatchToProps(dispatch) {
return {
splashStop: bindActionCreators(splashStop, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(withRouter(Home));
it's my child component:
here is in my child component at onClick function i dispatch redux action:
triggerSplash = () => {
this.props.splashStart();
};
my action:
export const START_SPLASH =
"START_SPLASH";
export const splashStart = () => {
return dispatch => {
dispatch({
type: START_SPLASH,
payload: true
});
};
};
and my reducer:
import { START_SPLASH } from "store/actions/Home/splashStart";
let initialState = {
splashStart: false
};
export default (state = initialState, action) => {
switch (action.type) {
case START_SPLASH:
return { ...state, splashStart: action.payload };
default:
return state;
}
};
my reducer, action is working correctly.
here is i wonder why myTime.play(); working always when component mount it's just don't care this control:
if (this.props.homeSplash.splashStart == true) {
myTime.play();
}
i place it to wrong place or what ?

In your redux structure, it seems everything OK. But you should provide your childComponent also to make it more clear.
If you have connected redux action correctly in your child component then try this:
<button ... onClick={() => this.triggerSplash()}>Click</button>
Put arrow function inside onClick. Because, in the component initialization, all component functions are called automatically in the render time.

Related

Uncaught TypeError: this.props.fetchResults is not a function

Hello i begin in react redux i try to play with an api my problem is at begining in my idea i hope make a select and in the select all the results for a day:
My Component ResultListItems:
import { connect } from 'react-redux';
import { fetchResults } from "../actions/index";
class ResultListItems extends Component {
componentWillMount(){
this.props.fetchResults();
}
render() {
return (
<div>
<h2>Coucou la liste resultats</h2>
<select></select>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
results: state.resultsReducer.results
};
};
export default connect(mapStateToProps, null)(ResultListItems)
My Action in index.js in folder actionsat this moment i have a date in url
import axios from "axios";
export const GET_RESULTS = "GET_RESULTS";
const END_POINT = "http://data.nba.net/10s/20200203";
export function fetchResults() {
return function(dispatch) {
axios.get(`${END_POINT}`)
.then(axiosResponse => {
dispatch({ type: GET_RESULTS, payload: axiosResponse.data});
});
}
}
My reducer => reducer_results :
const initialResults ={
results: []
}
export default function (state = initialResults, action) {
switch (action.type) {
case GET_RESULTS:
return {
results: action.payload
};
}
return state
}
I import in index.js in reducer Folder:
import ReducerResults from "../reducers/reducer_results";
const rootReducer = combineReducers({
resultsReducer: ReducerResults
});
export default rootReducer;
And my container is results.js :
import { connect } from 'react-redux';
import ResultListItems from '../components/results_list_item'
class Results extends Component {
render() {
return (
<div>
<h1>App NBA</h1>
<ResultListItems />
</div>
);
}
}
export default connect()(Results);
You are not mapping your api call of fetchResults to props.Try the following. After mapping state to props, map dispatch as well to props in component ResultListItems.
const mapDispatchToProps = (dispatch, ownProps) => {
return {
fetchResults : () => dispatch(fetchResults()),
dispatch
}
}
then coonect it like this.
export default connect(mapStateToProps, mapDispatchToProps)(ResultListItems)
So, you haven't fetchResults in the list of props, this.props.fetchResults is undefined, because you haven't binded the action to the component's props. To deal with it you need to bind the actionCreator. Use a guide: https://blog.benestudio.co/5-ways-to-connect-redux-actions-3f56af4009c8
Or
just do like that:
componentWillMount(){
const {dispatch} = this.props;
dispatch(fetchResults());
}

Dispatch an action from container

I'm new to react-redux and i want to dispatch an action from container to component. Here is my code :
Container :
import { connect } from 'react-redux';
import addCountryComponent from '../../views/Country/AddCountry'
import { addCountry } from '../../actions/countryActions'
const mapDispatchToProps = (dispatch) => {
return {
addCountry:(country) => dispatch(addCountry(country))
}
}
const CountryContainer = connect(null, mapDispatchToProps)(addCountryComponent)
export default CountryContainer;
AddCountry Component :
import React, {Component} from 'react';
class AddCountry extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log(this.props);
}
render() {
return (
<div className="animated fadeIn">
asdas
</div>
);
}
}
export default AddCountry;
and Action file
import { ADD_COUNTRY } from './names'
export function addCountry(payload) {
console.log(payload, "actions")
return {
type: ADD_COUNTRY,
payload,
}
}
I can't see addCountry as a props, am i missing something ?
as you mentioned in the comment you should link your container to your route file.
that means your container gets called when a browser open this /add/country
const mapDispatchToProps = dispatch => {
return {
addCountry: (country) => dispatch({ type: ADD_COUNTRY ,country})
}}
TO used it on click event
you should make add reducer for this app
example
const balance =(state={country:""},action)=>{
switch(action.type){
case ADD_COUNTRY: return{ country: action.country;}
this.props.addCountry(country)
This because of mapDispatchToProps auto-add property addCountry to your addCountryComponent.
const mapDispatchToProps = (dispatch) => {
return {
// component that using this function will auto have addCountry in props of component
addCountry:(country) => dispatch(addCountry(country))
}
}
// this addCountryComponent using mapDispatchToProps so it have addCountry in props
const CountryContainer = connect(null, mapDispatchToProps)(addCountryComponent)
export default CountryContainer;
Did you try using bindActionCreators function of Redux?
import { bindActionCreators } from 'redux';
const mapDispatchToProps = (dispatch) => bindActionCreators({
addCountry: addCountry,
}, dispatch);

How can I expose a value to the global actions to share it among components?

I am trying to expose a value in order to share it among components:
I have this reducer:
import createReducer from '../../../redux/createReducer';
import ActionTypes from '../constants/ActionTypes';
const initialState = {
currentService: 'otherservices',
};
export const handlers = {
[ActionTypes.SELECTED_SERVICE_ACTION](state, action) {
return {
...state,
currentService: action.payload,
};
},
};
export default createReducer(initialState, handlers);
And this action:
import ActionTypes from '../constants/ActionTypes';
export const selectedServiceAction = service => ({
type: ActionTypes.SELECTED_SERVICE_ACTION,
payload: service,
});
export default selectedServiceAction;
And I have this component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { translate } from 'react-i18next';
import { DropdownV2 } from 'carbon-components-react';
import PropTypes from 'prop-types';
import TableMultiSelectItems from './TableMultiSelectItems';
import { selectedServiceAction } from '../actions/cancellations';
class TableMultiselect extends Component {
constructor(props) {
super(props);
this.state = {
itemState: 'otherservices',
};
}
onChange = e => this.setState({ itemState: e.selectedItem.id });
render() {
const { t } = this.props;
// Array of dropdown's items
const menuItems = TableMultiSelectItems(t);
return (
<div>
<DropdownV2
items={menuItems}
onChange={this.onChange}
/>
</div>
);
}
}
const wrappedComponent = connect(
() => ({
serviceSelected: this.state.itemState,
}),
dispatch => ({
serviceSelectedHandler: serviceSelected => {
dispatch(selectedServiceAction(serviceSelected));
},
}),
)(TableMultiselect);
TableMultiselect.propTypes = {
t: PropTypes.func.isRequired,
serviceSelectedHandler: PropTypes.func.isRequired,
};
export default translate()(wrappedComponent);
What I need from the component above is to take the value returned by the onChange function (itemState: e.selectedItem.id });) and expose it in order to grab it in another component and do something like this:
//other imports
import the-Action-To-Get-The-OnChange-Value from "..."
const Cancellations = () => (
<React.Fragment>
{the-Action-To-Get-The-OnChange-Value.id === 'thisID' ?
<SLRequests/> : <SLDevices/>
}
</React.Fragment>
);
This is the first component I am trying to do with Redux, so I need some help trying to achieve what I need.
If you want something to be accessible globally, you will have to store it inside application state (redux store). In your particular case, you want to store e.selectedItem.id. So besides setting the state (however this is redundant because the variable will be accessible globally).
What you need to do? Inside onChange function you have to dispatch the action and pass the argument.
onChange = (e) => this.props.dispatch(selectedServiceAction(e.selectedItem.id));
Note: To access the dispatch function your component has to be connected.
Then it will be catched by reducer and will be saved in store.

React-redux action is not defined

I'm trying to call an API with redux action
but everytime I call it in my componentDidMount function, it gives me an error stating that my function is not defined.. i'm so confused, I've been using my past redux project as reference and it's using the same method but it works.
Have a look at my codes
Reducer
import * as types from '../actions/actionconst';
const initialState = {
isfetching: false,
categories: [],
error: null
}
const categoryReducer = (state = initialState, action) => {
switch(action.type){
case types.FETCH_CATEGORIES:
console.log('in fetch categories');
state = {
...state,
isfetching: true,
categories: action.payload
}
break;
case types.FETCH_CATEGORIES_SUCCESS:
state ={...state, categories: action.payload, isfetching: false}
break;
case types.FETCH_CATEGORIES_ERROR:
state = {...state, isfetching: false, error: action.payload}
}
return state;
}
export default categoryReducer
Action
import * as types from './actionconst';
import categoryAPI from '../api/categoryAPI';
export function getCategory(){
return {dispatch => {
fetch("http://localhost:8000/api/v1/categories")
.then((response) => response.json())
.then((responseData) => {
dispatch({
type: types.FETCH_CATEGORIES
payload: responseData
})
})
.catch((err) => {
dispatch({type: types.FETCH_CATEGORIES_ERROR, payload: err});
})
}}
}
Container
import React, {Component} from 'react';
import {connect} from 'react-redux';
import Category from '../components/category';
class CategoryContainer extends Component{
constructor(props){
super(props);
console.log('category props', this.props);
}
componentDidMount(){
console.log('masuk CDM');
this.props.fetchCategory()
}
render(){
var viewtypequery = window.innerWidth >= 1025 ? "computers" : "mobile"
return(
<Category alphabets={this.state.alph}
categorylist={this.state.categoriestemp}
view={viewtypequery}
active={this.state.isActive}
/>
)
}
}
const mapStateToProps = (state) => {
console.log('state is', state);
return{
categories: state.category
}
}
const mapDispatchToProps = (dispatch) => {
return{
fetchCategory: () => {
console.log('cuk ta');
dispatch(getCategory())
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CategoryContainer)
I dont know if I miss something, It's been a while since I touch this project, been rewatching redux tutorial but I still couldn't find any solutions..
I don't see you importing your getCategory action in your component. I would generally write it like that:
import { getCategory } from '../path-to-action';
.......
export default connect(mapStateToProps, {getCategory})(CategoryContainer)
and then use it directly in the componentDidMount lifecycle method:
componentDidMount(){
this.props.getCategory()
}
Hi Arga try to use bindActionCreators from redux. Make changes in your code to
import React, {Component} from 'react';
import {connect} from 'react-redux';
import Category from '../components/category';
import CategoryActions from '../actions/category'; // notice this will be your category actions file
class CategoryContainer extends Component{
constructor(props){
super(props);
console.log('category props', this.props);
}
componentDidMount(){
console.log('masuk CDM');
this.props.getCategory(); // change here we call function from props binded to category component, this function is defined in your actions file
}
render(){
var viewtypequery = window.innerWidth >= 1025 ? "computers" : "mobile"
return(
<Category alphabets={this.state.alph}
categorylist={this.state.categoriestemp}
view={viewtypequery}
active={this.state.isActive}
/>
)
}
}
const mapStateToProps = (state) => {
console.log('state is', state);
return{
categories: state.category
}
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators(CategoryActions, dispatch) // notice change here we use bindActionCreators from redux to bind our actions to the component
}
export default connect(mapStateToProps, mapDispatchToProps)(CategoryContainer)
Hopefully it helps.

React Redux- My action creator is not passing actions to reducer (sync)

When I click the DIV in Home container, I have confirmed the set function is called (I see the console log)
teamReducer function is never called. Maybe bindActionCreators should be used differently? How can i have my action creator send action to reducer to update the league store?
// teamReducer.js
export function teamReducer(state = initialState, action){
switch (action.type) {
case 'SET_TEAM':
return {
...state,
called: true
};
default:
return state;
}
};
// reducers/index.js
import { combineReducers } from 'redux';
import { routeReducer } from 'redux-simple-router';
import { teamReducer } from './teamReducer';
const rootReducer = combineReducers({
routing: routeReducer,
league: teamReducer,
});
export default rootReducer;
// actions/setTeam.js
export function setTeam(team, position) {
console.log(team, position);
return {
type: 'SET_TEAM',
team,
position
};
}
}
// Home.js
import React, { PropTypes, Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import {setTeam } from '../../actions/teams';
const mapStateToProps = ({league}) => {
return {
called: league.called
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
setTeam,
}, dispatch);
};
#connect(mapStateToProps, mapDispatchToProps)
export class Home extends Component {
constructor(props) {
super(props);
}
render() {
const {set} = this.props.setTeam
return <div onClick={set} />
}
}
The issue in the render function. You use destructuring assignment wrong.
render() {
const {set} = this.props.setTeam;
return <div onClick={set} />
}
This assignment is the same as in the following code:
const set = this.props.setTeam.set;
But setTeam is a function and doesn't have set property. The correct code is:
render() {
const {setTeam} = this.props;
return <div onClick={setTeam} />
}

Categories