My mapStateToProps is not passing props to component - reactjs

I am really newbie in Redux development. Just started two days ago
Before, I used props - state pattern but I am going to change some parts of state - props pattern to Redux.
First, I will show my codes. index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import ItemList from './itemList';
import SearchList from './searchList';
import {Provider,connect} from 'react-redux';
import {store} from './storeReducer';
import {backToMain} from './reduxAction';
class App extends React.Component{
// not important some codes
render(){
return(
<div>
<section id="Search">
<form action="//localhost:80/ReactStudy/travelReduxApp/public/server/itemList.php" id="Search" className="search" method="GET" onSubmit={this.submitForm}>
<input ref={'search'} placeholder="search country, attraction names" type="text" name="search"/>
<button type="submit">SEARCH</button>
</form>
<p className={this.state.validateError.display}>
{this.state.validateError.type=='invalid value'?
'Only english letters are available in this input'
: (this.state.validateError.type=='not found')?
'Nothing was found with this keyword. Try again'
:'Empty text field'
}
</p>
</section>
<ItemContainer initializeSearch={this.initializeSearch} searchList={this.state.searchItem}/>
</div>
)
}
}
class ItemContainer extends React.Component{
state={
viewMain:true
}
//some codes
showMain=()=>{
this.setState({
viewMain:true
})
this.props.initializeSearch();
store.dispatch(backToMain());
}
render(){
console.log('Item container');
console.log(this.props);
return(
<section id="ItemContainer">
{
this.props.searchList!=''?
<SearchList searchList={this.props.searchList} mainVisible={this.state.viewMain}/>
:
<ItemList toggleView={this.toggleView} mainVisible={this.state.viewMain}/>
}
<button onClick={this.showMain}>Back to main</button>
</section>
)
}
}
const mapStateToProps =(state)=>{
console.log('working'); //it doesn't show it.
return{
visible:state.visible
}
};
const wrappedSearchList = connect(mapStateToProps,null)(ItemContainer);
const Root = () => (
<Provider store={store}>
<App/>
</Provider>
);
ReactDOM.render(
<Root/>,
document.getElementById('App')
)
reduxAction.js
export function backToMain(){
return{
type:'BACK_TO_MAIN'
}
}
storeReducer.js
import {createStore} from 'redux';
import {backToMain} from './reduxAction';
export const initialState = {
visible:true
}
export const store = createStore(viewMainReducer,initialState);
export function viewMainReducer(state=initialState,action){
switch(action.type){
case 'BACK_TO_MAIN':
console.log('Back..');
return{
...state,
visible:true
}
break;
default: return state;
}
}
I am really newbie in Redux so maybe I did not understand official document perfectly but I know mapStateToProps must pass state to the component as props. In my case, the component should be ItemContainer component.
Problem is when ItemContainer component is rendered.
If I check with
console.log(this.props)
in ItemContainer's render method , in console I see only initializeSearch and searchList are passed to the component. I cannot figure out why my visible property of initialState object is not passed to the component. What could be the reason? What should I do to pass visible property to ItemContainer component?
React / Redux: mapStateToProps not actually mapping state to props
read this thread but I just did not understand ...

Try using wrappedSearchList instead of ItemContainer
<wrappedSearchList initializeSearch={this.initializeSearch} searchList={this.state.searchItem}/>**strong text**

Related

React Adding two parents for a child component

State is the smart component which store all the states of child components
import React from 'react';
import TextArea from './Components/TextArea';
class State extends React.Component {
constructor(props) {
super(props);
this.state = {
name: ''
}
this.myChangeHandler = this.myChangeHandler.bind(this)
}
myChangeHandler = (event) => {
event.preventDefault();
this.setState({
[event.target.name]:event.target.value
});
}
render() {
return (
<div>
{/* Change code below this line */}
<TextArea name = {this.state.name}
myChangeHandler = {this.myChangeHandler}/>
{/* Change code above this line */}
</div>
);
}
};
export default State;
Now TextArea is the child component which share the input value to state.
import React from 'react';
import '../style.css';
class TextArea extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<input type="text" onChange= {this.props.myChangeHandler} name="name" value={this.props.name}></input>
<h1>Hello, my name is:{this.props.name} </h1>
</div>
);
}
};
export default TextArea;
There are several child components that send the data to state component.
so the app component is used to order the child component.
I need two parents for a child component. please see the image enter image description here
import React from 'react';
import { BrowserRouter, Route } from 'react-router-dom'
import './App.css';
import TextArea from './Components/TextArea'
function App() {
return (
<div className="App">
<BrowserRouter>
<Route path = "/new" component= {TextArea} />
</BrowserRouter>
</div>
);
}
export default App;
You can't have two "direct" parent for a single component but you can have multiple indirect parents.
Example:
App is the parent of State
State is the parent of TextArea
App is also a parent of TextArea but not a direct one.
This means that you can pass props (data and functions) from the top parent to all of his children.
If you need to pass a function from App to TextArea you need to pass it by State.
Here a tutorial on how to do it.
You can also use the Context and here's a tutorial on how to do it.

React REDUX not updating the state to the new one

Just trying to build a simple react-redux code here. Whenever I click one of the button with some data value attached to it, I just want it to use it to update state of my react app.
The directory composition is :
src/index.js
src/App.js
src/reduxButtonGroup.js
src/reduxActions.js
src/reducers/index.js
src/reduxStore.js
src/reduxHelloWorld.js
Now, coming to the codes here is how App.js looks like:
import React from 'react';
import HelloWorld from './reduxHelloWorld.js';
import {store} from './reduxStore.js'
import ButtonGroup from './reduxButtonGroup.js';
import 'bootstrap/dist/css/bootstrap.min.css';
class App extends React.Component {
render(){
return(
<React.Fragment>
<HelloWorld name = {store.getState().name} />
<ButtonGroup names = {["NameA","NameB","NameC"]}/>
</React.Fragment>
)
}
}
export default App;
Here is how reduxButtonGroup.js looks like:
import React from 'react';
import Button from 'react-bootstrap/Button';
import {store} from './reduxStore.js';
import {setName} from './reduxActions.js';
const ButtonGroup = ( {names} ) => (
<div>
{names.map((name,i) => (
<Button data-name={name} key={`btn-${i}`} style={{marginRight: "15px"}} className={"btn btn-danger"} onClick={dispatchBtnAction}>
{name}
</Button>
))}
</div>
);
function dispatchBtnAction(e){
const name = e.target.dataset.name;
console.log(name);
store.dispatch(setName(name));
}
export default ButtonGroup;
And reduxActions.js:
export function setName (name) {
return {
type: "SET_NAME",
name: name
}
}
Also, reducers/index.js:
export default (state,action) => {
console.log(action.name)
switch(action.type){
case "SET_NAME":
console.log("here")
return{
...state,
name: action.name
};
default:
return state;
}
};
Here is how reduxStore.js looks like:
import {createStore} from 'redux';
import reducer from "./reducers";
const initialState = { name: "initialName " };
export const store = createStore(reducer, initialState);
And at last reduxHelloWorld.js:
import React from 'react';
class HelloWorld extends React.Component{
render(){
return(
<React.Fragment>
<h1>Hello {this.props.name}</h1>
</React.Fragment>
)
}
}
export default HelloWorld;
Now, in the terminal I can see the right values in action.type and action.name . However I think that somehow the part shown below is not working. i.e., I'm unable to update my state variable called name to action.name .
return{
...state,
name: action.name
};
Though I'm getting the right values, my component is not getting rendered with the right values. Any idea what I'm doing wrong over here. Any help would be highly appreciated.

nested component can't get props through connect

I am using a connected component as a props passed to a parent component, but I can't get any props from connect() or even from the function definition inside the component.
I have tried to defined the props function in render() but still not work
import React from 'react';
import PropTypes from 'prop-types';
import {Col,Row} from 'antd'
import injectSheet from 'react-jss';
class SubComponent extends React.Component{
constructor(props){
super(props);
}
picClicked=()=>{
console.log("cause state!");
console.log(this.props.picClicked);// output undefined
this.props.picClicked;
}
render(){
const {picClicked,classes} = this.props;// classes is from react-jss
console.log(this.props);// only classes is shown from the console log
return(
<div>
<div onClick={this.picClicked} className={classes.headBlank}>
</div>
</div>
)
}
SubComponent.propTypes={
picClicked:PropTypes.func.isRequired
};
export default injectSheet(logoStyle)(SubComponent)
then the container looks like following:
const mdtp = (dispatch)=>{
return{
picClicked:()=>{console.log("picClicked!");}
};
};
export default connect(null,mdtp)(SubComponent);
The SubComponent is then used as a props in another parent component like this:
ReactDOM.render(
<Provider store={storeMainContents}>
<ParentComponent contentsShow={<SubComponent />} />
</Provider>
,document.getElementById("parentComponent")
);
The parent component looks like this:
render(){
const {contentsShow,classes}=this.props;
return(
<div>
<div>
{this.props.contentsShow}
</div>
</div>
);
}
What I expected is that the SubComponent can access the props like picClicked as a action that can be dispatched or at least get accessed. Now it is simply undefined.

How can I reference a DOM element in a function that makes an action call?

I have a functional component that I would like to use an onClick in to dispatch an action for a simple like button. I the onClick function to take in the store properties of the DOM element it refers to in order to update the store slice it is designed to affect.
I've tried to pass in the data as props, to no avail. I've also tried using a react Ref, but this seems to be reserved for class components
The component that handles the click
The likes and content are passed down from the Redux store via props from a parent component
import React from 'react';
import styles from '../scss/styles.scss';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {onNewLike} from './../actions';
function Post(props){
function doALike() {
const { dispatch } = props
dispatch(onNewLike())
}
return(
<div className="post">
<h1>{props.content}</h1>
<div className="post-statistics">
<p onClick={doALike}>LIKE</p>
<p>likes: {props.likes}</p>
</div>
</div>
);
}
Post.propTypes = {
content: PropTypes.string,
likes: PropTypes.number,
dispatch: PropTypes.func
}
export default connect()(Post)
The Reducer I am trying to pass the post to, so that I can update each unique post's likes (haven't written the logic for handling a like yet - just want to make sure I'm getting each post's likes
import { initialState } from '../constants/initialState';
import c from './../constants';
export function likeReducer(state = initialState, action){
switch (action.type){
case c.NEW_LIKE:
console.log(action.id)
default:
return state;
}
}
The component that allows users to generate a new post, and passes 'likes' set to '0' to the redux store
import React from 'react';
import styles from '../scss/styles.scss';
import PropTypes from 'prop-types';
import { v4 } from 'uuid';
import {connect} from 'react-redux';
import {onNewPost} from './../actions';
function NewPost({dispatch}){
let _content = null;
function handleNewPost(e){
e.preventDefault();
let post = {content: _content.value, likes: 69, id: v4()}
dispatch(onNewPost(post))
}
return(
<div className='newPost'>
<h1>Create a Post</h1>
<form onSubmit={handleNewPost}>
<input type='text'
id='content'
className='newPostInput'
placeholder='Whats on your mind?'
ref={(input) => {_content = input;}}/>
<button type='submit'>Submit</button>
</form>
</div>
);
}
You can pass in what you need to the doALike function and then call it in the click handler as an anonymous function like below.
function Post(props){
function doALike(whateverProps) {
dispatch(onNewLike())
}
return(
<div className="post">
<h1>{props.content}</h1>
<div className="post-statistics">
<p onClick={() => {doALike(props)}}>LIKE</p>
<p>likes: {props.likes}</p>
</div>
</div>
);
}

Where in redux-react app would I include my stateful presentational component? In components or containers folder?

Search Component:
import React from "react";
import SearchResults from "../SearchResults";
import PropTypes from "prop-types";
class Search extends React.Component {
state = {
value: ""
};
handleChange = event => {
let value = event.target.value;
this.setState({ value });
this.props.performSearch(value);
};
handleSubmit = event => {
event.preventDefault();
};
render() {
return (
<div>
<h1>The Guardian Search App</h1>
<form onSubmit={this.handleSubmit}>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</form>
<div>
<SearchResults articles={this.props.articles} />
</div>
</div>
);
}
}
Search.propTypes = {
performSearch: PropTypes.func,
articles: PropTypes.array
};
export default Search;
Search Container:
import React from "react";
import Search from "../../components/Search";
import { API_KEY } from "../../../config";
import fetchArticles from "../../api";
class SearchContainer extends React.Component {
state = {
articles: []
};
performSearch = event => {
return fetchArticles(event).then(data =>
this.setState({ articles: data.response.results })
);
};
render() {
return (
<Search
performSearch={this.performSearch}
articles={this.state.articles}
/>
);
}
}
export default SearchContainer;
I am currently trying to get my head around redux so transitioning this into react-redux version. I've got a Search Container whereby I am doing mapStateToProps and will soon write mapDispatchToProps as well. But if my Search component also includes state, do I then do another Search Container to then map its state to props?
The state required in your Search component is directly linked and required by the input element that you have rendered as a child. Therefore, the value state in the Search component should stay within the component and not be associated with Redux.
There is no "correct" way of doing this, mainly preference and design pattern. Since you have state in the Search component that you don't want to be associated with Redux, I would hook the SearchContainer component into your Redux store for providing the array of article objects which can then be passed to the base Search component as a prop and leave that component entirely unaware that Redux even exists.

Resources