I've following code,
I've created a dumb component,
const editViewTable = ({ headerData, bodyData }) =>
(
<div>.....</div>
)
editViewTable.propTypes = {
headerData: React.PropTypes.arrayOf(React.PropTypes.string),
bodyData: React.PropTypes.arrayOf(React.PropTypes.object),
};
export default editViewTable;
And an intelligent one,
import * as actions from './actions';
import React from 'react';
import { connect } from 'react-redux';
import { getOnehopProducts } from './reducers';
import editViewTable from '../common/editViewTable/component';
const mapStateToProps = (state, params) => {
return {
headerData: ['name', 'category', 'merchant'],
bodyData: getOnehopProducts(state)
};
}
class ProductList extends React.Component {
componentDidMount() {
this.fetchData();
}
fetchData() {
const { fetchProducts } = this.props;
fetchProducts({});
}
render(){
const { headerData, bodyData } = this.props;
return <editViewTable headerData={headerData} bodyData={bodyData} />;
}
}
ProductList = connect(
mapStateToProps,
actions
)(ProductList);
export default ProductList;
Whenever I'm rendering the component, I'm getting the error Warning: Unknown props 'headerData', 'bodyData' on <editViewTable> tag. Remove these props from the element.
I'm unable to find, what's causing the problem. I'm clearly not passing extra props, so what's causing the error. I'm pretty much newbie to react.
I'm using react-material.
After renaming editViewTable to EditViewTable, this warning has gone, and everything is working fine and dandy.
Related
Post component:
import React from 'react';
import './post.styles.scss';
import { connect } from 'react-redux';
import { requestContents } from '../../redux/post/post.actions';
class Post extends React.Component {
componentWillMount(){
}
render(){
return (
<div>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => {
return {
onRequestContents : dispatch(requestContents())
}
}
const mapStateToProps = (state) => {
return {
posts: state.post.posts,
isPending: state.post.isPending
}
}
User component:
export default connect(mapStateToProps, mapDispatchToProps)(Post)
import React from 'react';
import './user.styles.scss';
import { connect } from 'react-redux';
import { requestUsers } from '../../redux/user/user.actions';
class User extends React.Component {
componentWillMount(){
this.props.onRequestUsers();
}
render(){
return (
<div>
</div>
}
}
const mapDispatchToProps = (dispatch) => {
return {
onRequestUsers: () => dispatch(requestUsers())
}
}
const mapStateToProps = (state) => {
return {
users: state.user.users,
isPending: state.user.isPending
}
}
export default connect(mapStateToProps, mapDispatchToProps)(User)
Here I am using redux with React.
In user component i am calling onRequestUsers inside componentWillMount()
but in post component i am not calling onRequestContents inside componentWillMount()
But still how it is calling and display in my redux-logger
I am calling mapDispatchToProps only inside user component
Please have a look
You're calling requestContents in your mDTP call:
const mapDispatchToProps = (dispatch) => {
return {
onRequestContents: dispatch(requestContents())
}
}
That's what those two parens do:
requestContents()
Omit them:
onRequestContents: dispatch(requestContents)
That said: there's something odd with your function. Normally you'd mDTP with a function, e.g.,
onRequestContents: () => dispatch(requestContents())
(Used when you need to pass parameters, like an event.)
I have a simple component I'm trying to make work with redux. I map both props and dispatch actions, however only the props I initially get from the store work properly. I traced it all down to my actions: they are being dispatched, but respective reducers don't really do anything. Pretty simple stuff I came up with according to the tutorial and everything looks good to me, but I can't wrap my head around the problem here.
Here is a simplified version of the app:
// index.js
import React from 'react'
import ReactDOM from 'react-dom'
import Search from './Search'
import { Provider } from 'react-redux'
import store from './store'
const root = document.querySelector('#app')
ReactDOM.render(
<Provider store={store}>
<Search/>
</Provider>, root)
// Search.js
import React from 'react'
import { setText } from '../../actions/appActions'
import { connect } from 'react-redux';
const mapStateToProps = state => {
return {
text: state.app.searchText
}
}
const mapDispatchToProps = dispatch => {
return {
setText,
dispatch
}
}
class Search extends React.Component {
constructor() {
super()
}
render() {
return (
<input type="text" onChange={() => this.props.setText("text")} value={this.props.text}/>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Search)
// store.js
import { createStore, combineReducers } from 'redux'
import app from './reducers/appReducer'
export default createStore(combineReducers({/*other non-relevant reducers*/, app}))
// appActions.js
export function setText(text) {
return {
type: "APP_SET_TEXT",
payload: text,
}
}
// appReducer.js
const initialState = {
isSearchActive: true,
searchText: "Text",
}
export default function reducer(state = initialState, action) {
switch (action.type) {
case "APP_SET_TEXT":
console.log("fart")
return {
...state,
searchText: action.payload,
}
default:
return state
}
}
What I'm trying to to is to simply make the input value change according to the redux state. I do get the text from {this.props.text}, the change handler onChange={() => this.props.setText("text")} is being dispatched, but the reducer for some reason fails to catch the action that was dispatched.
I think you should change the mapDispatchToProps variable like the following:
const mapDispatchToProps = dispatch => {
return {
setText = (text) => dispatch(setText(text)),
}
}
There are two ways to achieve this
// MODIFYING DISPATHCER
const mapDispatchToProps = dispatch => {
return {
changeText: data => dispatch(setText(data)),
}
}
or
// CONNECT
export default connect(mapStateToProps, {
setText
})(Search)
const mapDispatchToProps = dispatch => {
return {
setText,
dispatch
}
}
change to
const mapDispatchToProps = dispatch => {
return {
changeText: text => dispatch(setText(text)),
}
}
And in your component use this.props.changeText function
as most of the answers suggests you can dispatch the actions or else you can simply have mapDispatchToProps an object.
mapDispatchToProps = {
setText,
dispatch
}
Your HOC connect should take care of dispatching not need to external definition
Use bindActionCreators from redux
import { bindActionCreators } from 'redux';
const mapDispatchToProps = dispatch => {
const setText = bindActionCreators(setText, dispatch);
return setText;
}
Since you're mapping your dispatch to props like this:
const mapDispatchToProps = dispatch => {
return {
setText,
dispatch
}
}
You'll need to explicitly call dispatch in your component:
class Search extends React.Component {
constructor() {
super()
}
render() {
const {dispatch, setText} = this.props;
return (
<input type="text" onChange={() => dispatch(setText("text"))} value={this.props.text}/>
)
}
}
It is easier just to map dispatch to props like this: setText = (text) => dispatch(setText(text))
I am new to redux, and I am creating a small app to render an API onClick. I call the action creator inside the componentDidMount which is able to generate the desired outcome the first click. However, because componentDidMount only renders once, nothing happens upon the second "click".
The following code is the component containing the onClick called "handleFavClick" inside this function two action creators are triggered one to identify the button that was clicked and add it to the state for use in the second action creator, which gets the API.
import React from 'react';
import { connect } from 'react-redux';
import '../stylesheet/FavoriteList.css';
import { uploadGif } from '../actions';
import Display from './Display';
class FavoriteList extends React.Component {
handleFavClick = (id) => {
this.props.uploadGif(id);
this.displayGif();
}
displayGif = () => {
this.setState({display: true});
};
renderList = (callback) => {
let fullList = this.props.favsList.map(function(cur, index) {
return (
<button onClick={function() {
callback(index);
}} className="list-item" key={index}>{cur}</button>
)
});
return fullList;
}
render() {
return (
<div>
<div className="favs">
<h2>Favorite List</h2>
<ul className="unordered-list">
{this.renderList(this.handleFavClick)}
</ul>
</div>
{this.state.display && <Display />}
</div>
)
}
}
const mapDispatchToProps = {
uploadGif,
}
const mapStateToProps = (state) => {
return {
favsList: state.myFirstReduxKey,
}
};
export default connect(mapStateToProps, mapDispatchToProps)(FavoriteList);
Display Component (after onClick is triggered, this component is rendered and the display is updated with the data received from the API request)
import React from 'react';
import { connect } from 'react-redux';
import { getGif } from '../actions';
class Display extends React.Component {
componentDidMount() {
const list = this.props.gifList;
const item = this.props.chosenGif;
this.props.getGif(list[item]);
}
.
.
.
.
const mapStateToProps = (state) => {
return {
gifList: state.myFirstReduxKey,
chosenGif: state.uploadGif,
gifs: state.getGif
}
}
export default connect(mapStateToProps, { getGif })(Display);
Called Action Creator
export const getGif = (action) => async dispatch => {
const key = 'GRghbyFwY5CEhc1h7ngS9KBEK9s2W3zBa'
const response = await gifApi.get(`search?q=${action}&api_key=${key}`)
.then(function(response) {
return response.data.data
});
dispatch({ type: GET_GIF, payload: response})
};
At the end of the day, I would like to know how redux programmers handle a client clicking one button, which renders something, then a client clicks a new button which removes the prior click's rendering and renders the new information.
Your code looks fine but there is one thing you need to change to make this work has expected, like how you said since your code is in componentDidMount, this is gonna work only in the Creational life cycle of the component,
now there are two things you can do.
1.**Move your this.props.getGif(list[item]) into **render() (Recomended):
import React from 'react';
import { connect } from 'react-redux';
import { getGif } from '../actions';
class Display extends React.Component {
render(){
const list = this.props.gifList; //this code gets executed every time
const item = this.props.chosenGif;
this.props.getGif(list[item]);
}
}
const mapStateToProps = (state) => {
return {
gifList: state.myFirstReduxKey,
chosenGif: state.uploadGif,
gifs: state.getGif
}
}
export default connect(mapStateToProps, { getGif })(Display);
2.Have a separate handler and have both componentDidMount and componentDidUpdate call it:
import React from 'react';
import { connect } from 'react-redux';
import { getGif } from '../actions';
class Display extends React.Component {
componentDidMount() {
this.loadGifHandler();
}
componentDidUpdate() {
this.loadGifHandler();
}
loadGifHandler = () => {
const list = this.props.gifList;
const item = this.props.chosenGif;
this.props.getGif(list[item]);
}
.
.
.
.
const mapStateToProps = (state) => {
return {
gifList: state.myFirstReduxKey,
chosenGif: state.uploadGif,
gifs: state.getGif
}
}
export default connect(mapStateToProps, { getGif })(Display);
I observed that this problem is common, but I didn't find a solution for my case.
I'm trying to redirect the user to another navigator in react native, using react and redux with redux-thunk. If I display just Home screen it works fine, but when I'm redirecting from SignIn screen to Home, it goes into an infinite loop, I found the problem is in the dispatch function.
import {
FETCHING_CATEGORIES_REQUEST,
FETCHING_CATEGORIES_SUCCESS,
FETCHING_CATEGORIES_FAILURE,
} from "../types"
import { Categories } from "../../services/firebase"
export const fetchingCategoriesRequest = () => ({
type: FETCHING_CATEGORIES_REQUEST,
})
export const fetchingCategoriesSuccess = data => ({
type: FETCHING_CATEGORIES_SUCCESS,
payload: data,
})
export const fetchingCategoriesFailure = error => ({
type: FETCHING_CATEGORIES_FAILURE,
payload: error,
})
export const fetchCategories = () => {
return async dispatch => {
dispatch(fetchingCategoriesRequest())
Categories.get()
.then(data => dispatch(fetchingCategoriesSuccess(data)))
.catch(error => dispatch(fetchingCategoriesFailure(error)))
}
}
Routing
import { createSwitchNavigator } from "react-navigation"
import PrivateNavigator from "./private"
import PublicNavigator from "./public"
const Navigator = (signedIn = false) => {
return createSwitchNavigator(
{
Private: {
screen: PrivateNavigator,
},
Public: {
screen: PublicNavigator,
},
},
{
initialRouteName: signedIn ? "Private" : "Public",
},
)
}
export default Navigator
Redirecting
import React from "react"
import { Spinner } from "native-base"
import { connect } from "react-redux"
import Navigator from "../navigation"
class AppContainer extends React.Component<any, any> {
render() {
const { isLogged, loading } = this.props.auth
const Layout = Navigator(isLogged)
return loading ? <Spinner /> : <Layout />
}
}
const mapStateToProps = state => {
return {
...state,
}
}
export default connect(
mapStateToProps,
{},
)(AppContainer)
Be careful with mapStateToProps, you should only select the part of the store you're interested in, otherwise performance problems could occur
const mapStateToProps = state => ({auth: state.auth});
A little explanation how react-redux connect works,
each time there is a modification in the store (from the reducers), the mapStateToProps functions of all the connected components are executed
if the one prop in the returned object is different from the previous one (the operator === is used) then the component is re-rendered otherwise it does nothing.
In your example, as you select all the props of the store, your component will be re-rendered for each modification in the store
I have this error and can't really understand what could go wrong when {connect} imported and const mapStateToProps declared:
./src/Movies.js Syntax error: C:/projects/library/src/Movies.js:
Unexpected token (6:8)
6 | const mapStateToProps = (state) => ({
import React, { Component } from "react";
import { connect } from "react-redux";
import MovieItem from "./MovieItem";
class Movies extends Component {
const mapStateToProps = (state) => ({
movies: state.movies;
});
render() {
let movieItems = this.props.movies.map(movie => {
return <MovieItem movie={movie} />;
});
return <div className="Movies">{movieItems}</div>;
}
}
export default connect(mapStateToProps, null)(Movies);
You need to define mapStateToProps function outside of your React component
import React, { Component } from "react";
import { connect } from "react-redux";
import MovieItem from "./MovieItem";
class Movies extends Component {
render() {
let movieItems = this.props.movies.map(movie => {
return <MovieItem movie={movie} />;
});
return <div className="Movies">{movieItems}</div>;
}
}
const mapStateToProps = (state) => ({
movies: state.movies;
});
export default connect(mapStateToProps, null)(Movies);
A class member cannot be declared as a const, var or let. Also since you need to use it outside of the React component only, you should define it separately