I'm building a Todo app using react+redux. When I add new todo in my list, state of store and state of TodoList component are updated successfully but My todoList code not working properly. React component is not rendering list.
Structure of state is below.
State = [
{
id,
text,
completed
},...
]
My code is below.
Todo.js
import React, { Component } from 'react';
import Form from './Form';
import TodoList from './TodoList';
import Filter from './Filter';
class ToDo extends Component {
render() {
return (
<div>
<h2>Todo App</h2>
<Form />
<TodoList />
<Filter />
</div>
);
}
}
export default ToDo;
TodoList.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { toggleToDo } from '../actions';
class TodoList extends Component {
constructor (props){
super(props);
this.state = {
list: []
};
}
render() {
console.log(this);
const todolist = this.state.list;
return (
<ul>
{
todolist.map(function(listValue) {
return <li>{listValue.text}</li>;
})
}
</ul>
);
}
}
const mapStateToProps = (state) => {
console.log('TodoList state',state);
return {
todos: state
}
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({toggleToDo},dispatch);
}
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
You are mapping your state to props with mapStateToProps so you should get this state value from your props.
const { todos } = this.props; and iterate on todos instead of todolist.
Related
Login.js in functional component
import React, { useState } from 'react';
import { connect } from 'react-redux';
import { login } from '../actions/auth';
const Login = ({ login, isAuthenticated }) => {
return (
<div>
// some code here
</div>
);
};
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
});
export default connect(mapStateToProps, { login })(Login);
How can I use above mapStateToProps function in class component as I used above in functional component?
Login.js in class component
import React, {Component} from "react";
class Login extends Component{
constructor(props) {
super(props);
this.state = {
search:'',
}
}
render() {
return(
<div>
//some code here
</div>
)
}
}
export default Login;
In class components mapStateToProps works the same as functional components, I feel there are only differences in some syntax or calling approaches.
It does not matter if a mapStateToProps function is written using the function keyword (function mapState(state) { } ) or as an arrow function
(const mapState = (state) => { } ) - it will work the same either way.
Class component with mapStateToProps
import React, {Component} from "react";
import { connect } from 'react-redux';
import { login } from '../actions/auth';
class Login extends Component{
constructor(props) {
super(props);
this.state = {
search:'',
}
}
render() {
const { isAuthenticated } = this.props;
return(
<div>
//some code here
</div>
)
}
}
function mapStateToProps(state) {
const { isAuthenticated } = state.auth.isAuthenticated
return { isAuthenticated }
}
export default connect(mapStateToProps)(Login)
As you can see there is only 1 major difference is: In Class component we are reading the value isAuthenticated from this.props whereas in the Functional component we are getting the value as arguments.
For information read more about mapStateToProps. https://react-redux.js.org/using-react-redux/connect-mapstate
The state is empty when I try to map the state from the store to the properties of a component. I try to get a value of a string displayed in JSX but it is missing. I cant manage to get anything to display from the redux store.
Reducer:
const initialState = {
visibles: "false",
error: null,
text: ""
};
const rootReducer = (
state = initialState,
action
) => {
switch (action.type) {
case "OPEN_MODAL":
return {
...state,
visibles: "true",
error: null
};
default:
return state;
}
}
export default rootReducer;
and index.js
import {createStore } from "redux";
import {Provider } from "react-redux";
import rootReducer from "./components/Redux/Reducer";
const store = createStore(rootReducer);
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
consumer of the redux store
import React, { Component } from 'react'
import {connect} from "react-redux";
import styles from "./modal.module.css";
export class Modal extends Component {
render() {
console.log(this.props)
return (
<div className={styles.root}>
<p className={styles.title}>{this.props.visible}</p>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
visible: state.visibles
}
}
export default connect(mapStateToProps)(Modal)
Found the reason why. I had to refactor the Modal class to not use "export class" and then I could get the state from the store with connect.
class Modal extends React.Component {
render() {
console.log(this.props)
return (
<div className={styles.root}>
<p className={styles.title}>{this.props.visible}</p>
</div>
)
}}
I would like to use some data I received from firestore to build a quiz. Unfortunately I can console.log the array, but if I use .length it is undefined.
Is this problem caused by some lifecycle or asnynchronous issue?
Thanks in advance!
import React, { Component } from 'react';
import { connect } from 'react-redux';
class LernenContainer extends Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
<div className="lernenContainer">
LernenContainer
{
console.log(this.props.firestoreData),
// prints array correctly
console.log(this.props.firestoreData.length)
// is undefined
}
</div>
);
}
}
const mapStateToProps = state => {
return {
firestoreData: state.firestoreData
};
};
const mapDispatchToProps = dispatch => {
return {
// todo Achievements
};
};
export default connect(mapStateToProps, mapDispatchToProps) (LernenContainer);
console.log(this.props.firestoreData):
Try below code
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types'
class LernenContainer extends Component {
constructor(props) {
super(props);
}
static propTypes = {
firestoreData: PropTypes.object.isRequired
}
render() {
const { firestoreData } = this.props
console.log(firestoreData);
console.log(firestoreData.length);
return (
<div className="lernenContainer">
</div>
);
}
}
const mapStateToProps = (state) => ({
firestoreData: state.firestoreData
})
const mapDispatchToProps = (dispatch) => ({
})
export default connect(mapStateToProps,mapDispatchToProps)(LernenContainer);
I am using react native and react navigation for routing.
How to update state from another component/page?
HomeScreen
export class HomeScreen extends Component {
constructor(){
this.state = {
test: ''
}
}
updateState = ()=>{
this.setState({test:'new value'});
}
}
SideMenuScreen
import { HomeScreen } from "./home";
export class SideMenuScreen extends Component {
updateHomeState = ()=>{
let oHome = new HomeScreen();
oHome.updateState();
}
}
My App.js and routing and sidemenu config as below :
import { createAppContainer, createDrawerNavigator } from "react-navigation";
import { SideMenuScreen } from "./screens/Sidemenu";
import { HomeScreen } from "./screens/Home";
export default class App extends Component {
render() {
return(
<AppContainer></AppContainer>
);
}
}
const AppNavigator = createDrawerNavigator(
{Home: HomeScreen,
other: otherpage},
{
contentComponent: SideMenuScreen
}
);
const AppContainer = createAppContainer(AppNavigator);
updateState executing but not updating state.
If you have to update from the child component
You will have to pass down the Handlers from the component which holds the state to update the values, child component can make use of these handlers to update the state
If you have to update from some other location
You will have to do a level up the State and follow the same has above.
LevelUpComponent
export class App extends Component {
constructor(){
this.state = {
test: ''
}
}
updateState = (values)=>{
this.setState(values);
}
render(){
return <div>
<HomeScreen></HomeScreen>
<SideMenuScreen updateState={this.updateState}></SideMenuScreen>
</div>
}
}
Since you're not haveing Parent-Child relationship between your components ... thi s could be accomplished through Redux Action
HomeScreen;
export class HomeScreen extends Component {
constructor() {
this.state = {
test: ""
};
}
componentWillReceiveProps(nextProps) {
const { test: nextTest } = nextProps;
const { test } = this.props;
if (nextTest !== test) {
this.setState({ test: nextTest });
}
}
}
const mapStateToProps = ({ yourReducerName: test }) => ({ test });
export connect(mapStateToProps)(HomeScreen);
import { HomeScreen } from "./home";
import { connect } from "tls";
class SideMenuScreen extends Component {
updateHomeState = () => {
const { updateHomeStateAction } = this.props;
updateHomeStateAction({ test: 'New Value' });
};
}
export default connect(null, { updateHomeStateAction })(SideMenuScreen);
when you navigate to next screen pass this function in params,
this.props.navigate("SideMenuScreen",{update:this.updateState});
And in your side menu screen,
call it using props,
this.props.navigation.state.params.update();//you can pass params also if needed
You can do this by using ref.
HomeScreen
export class HomeScreen extends Component {
constructor(){
this.state = {
test: ''
}
}
updateState = ()=>{
this.setState({test:'new value'});
}
}
SideMenuScreen
import { HomeScreen } from "./home";
export class SideMenuScreen extends Component {
updateHomeState = ()=>{
this.homeScreen.updateState();
}
render(){
return(
<HomeScreen ref={(ele) => this.homeScreen = ele}/>
);
}
}
How can I get access to props of a root component?
import React from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import cartReducer from './store/cartReducer'
import AddToCart from './cart/addToCart.jsx'
const store = createStore(cartReducer);
render(<Provider store={store}><AddToCart clicked={this.props.onIncrementCounter} />
</Provider>, document.getElementById('addToCart'));
Is it possible? Because I have an error: " Cannot read property 'props' of undefined".
I am new in React.
Here is AddToCart component
import React, { Component } from 'react';
import { connect } from 'react-redux';
class AddToCart extends Component {
constructor(props) {
super(props);
}
}
const mapStateToProps = state => {
return {
items: state.cartItems,
count: state.cartItemCount
};
};
const mapDispatchToProps = dispatch => {
return {
onIncrementCounter: () => dispatch({ type: 'INCREMENT' })
};
}
export default connect(mapStateToProps, mapDispatchToProps)(AddToCart);
you got this error " Cannot read property 'props' of undefined" because in that part of your code : <AddToCart clicked={this.props.onIncrementCounter} />
this is referencing anything
you can try this approach:
import React from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import cartReducer from './store/cartReducer'
import AddToCart from './cart/addToCart.jsx'
const store = createStore(cartReducer);
render(<Provider store={store}><AddToCart/>
</Provider>, document.getElementById('addToCart'));
AddToCart.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
class AddToCart extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div onClick={this.props.onIncrementCounter}>
Increment
</div>
)
}
}
const mapStateToProps = state => {
return {
items: state.cartItems,
count: state.cartItemCount
};
};
const mapDispatchToProps = dispatch => {
return {
onIncrementCounter: () => dispatch({ type: 'INCREMENT' })
};
}
export default connect(mapStateToProps, mapDispatchToProps)(AddToCart);