I'm doing an attemp of Todo App in React- Redux; got store, actions, reducer & Addodo ponent running; but got stucked at showing todos:
if my initialState=[] how can i retrieve data from store?
Store:
import { createStore } from 'redux';
import rootReducer from '../reducer';
export const store = createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store
My reducer:
const initialState = [];
const todos = (state = initialState, action) => {
switch(action.type) {
// Aca va tu codigo;
case 'AddTodo':
return [...state, action.payload];
case 'RemoveTodo':
return state.filter(todo => todo.id !== action.payload)
case 'ToInProgress':
return state.map((todo) =>
todo.id === action.payload ? { ...todo, status: "InProgress" } : todo
);
case 'ToDone':
return state.map((todo) =>
todo.id === action.payload ? { ...todo, status: "Done" } : todo
);
default:
return state
}
}
export default todos;
App.js:
import React from 'react'
import { Route } from "react-router-dom"
import {Provider} from 'react-redux'
import store from './store/index'
import Nav from '../src/ponents/Nav/Nav'
import Home from '../src/ponents/Home/Home'
import AddTodo from '../src/ponents/AddTodo/AddTodo'
import TodoDetail from '../src/ponents/TodoDetail/TodoDetail'
import './App.css';
export function App() {
return (
<React.Fragment>
<Provider store={store}>
<Nav />
<Route exact path="/" ponent={Home} />
<Route path="/add" ponent={AddTodo} />
<Route path="/edit/:id" ponent={TodoDetail} />
</Provider>
</React.Fragment>
);
}
export default App;
Home.js:
import React from 'react';
import Todos from '../Todos/Todos'
import './home.css'
export function Home() {
return (
<div className="todosContainer">
<div>
<Todos status="Todo"/>
<label>TODO</label>
</div>
<div>
<Todos status='InProgress' />
<label>InProgress</label>
</div>
<div>
<Todos status='Done'/>
<label>Done</label>
</div>
</div>
)
};
export default Home;
Here's AddTodo:
export function AddTodo() {
const [state,setState]=React.useState({
title:"",
description:"",
place:"",
date:"",
})
function handleChange(e){
const value=e.target.value;
setState({
...state,
[e.target.name]:value
})
}
function handleSubmit(e){
e.preventDefault();
store.dispatch(addTodo({
place:state.place,
title:state.title,
date:state.date,
description:state.description
})) // parameters "id" & "status" loaded in Actions.
setState({title:"",
description:"",
place:"",
date:"",})
}
return (
<div className="todoContainer">
<form id="formulario"onSubmit={handleSubmit} >
<label>
Title
<input type="text" name="title" value={state.title} onChange={handleChange} />
</label>
<label>
Description
<textarea type="text" name="description" value={state.description} onChange= {handleChange}/>
</label>
<label>
Place
<input type="text" name="place" value={state.place} onChange={handleChange}/>
</label>
<label>
Date
<input type="text" name="date" value={state.date} onChange={handleChange}/>
</label>
<button className="boton" type="submit" onClick={addTodo}>Agregar</button>
</form>
</div>
)
};
function mapDispatchToProps(dispatch){
return{
addTodo: todo => dispatch(addTodo(todo))
}
}
export default connect(mapDispatchToProps)(AddTodo)
Now, i want to show at Todos ponent, every Todos "title", still didn't know how to perform it:
export function Todos(data) {
return (
<div className="todoDetail">
<h4>{data.title}</h4>
</div>
)
};
function mapStateToProps(state) {
return {
data: state.title,
};
}
export default connect(mapStateToProps)(Todos)
I'm doing an attemp of Todo App in React- Redux; got store, actions, reducer & Addodo ponent running; but got stucked at showing todos:
if my initialState=[] how can i retrieve data from store?
Store:
import { createStore } from 'redux';
import rootReducer from '../reducer';
export const store = createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store
My reducer:
const initialState = [];
const todos = (state = initialState, action) => {
switch(action.type) {
// Aca va tu codigo;
case 'AddTodo':
return [...state, action.payload];
case 'RemoveTodo':
return state.filter(todo => todo.id !== action.payload)
case 'ToInProgress':
return state.map((todo) =>
todo.id === action.payload ? { ...todo, status: "InProgress" } : todo
);
case 'ToDone':
return state.map((todo) =>
todo.id === action.payload ? { ...todo, status: "Done" } : todo
);
default:
return state
}
}
export default todos;
App.js:
import React from 'react'
import { Route } from "react-router-dom"
import {Provider} from 'react-redux'
import store from './store/index'
import Nav from '../src/ponents/Nav/Nav'
import Home from '../src/ponents/Home/Home'
import AddTodo from '../src/ponents/AddTodo/AddTodo'
import TodoDetail from '../src/ponents/TodoDetail/TodoDetail'
import './App.css';
export function App() {
return (
<React.Fragment>
<Provider store={store}>
<Nav />
<Route exact path="/" ponent={Home} />
<Route path="/add" ponent={AddTodo} />
<Route path="/edit/:id" ponent={TodoDetail} />
</Provider>
</React.Fragment>
);
}
export default App;
Home.js:
import React from 'react';
import Todos from '../Todos/Todos'
import './home.css'
export function Home() {
return (
<div className="todosContainer">
<div>
<Todos status="Todo"/>
<label>TODO</label>
</div>
<div>
<Todos status='InProgress' />
<label>InProgress</label>
</div>
<div>
<Todos status='Done'/>
<label>Done</label>
</div>
</div>
)
};
export default Home;
Here's AddTodo:
export function AddTodo() {
const [state,setState]=React.useState({
title:"",
description:"",
place:"",
date:"",
})
function handleChange(e){
const value=e.target.value;
setState({
...state,
[e.target.name]:value
})
}
function handleSubmit(e){
e.preventDefault();
store.dispatch(addTodo({
place:state.place,
title:state.title,
date:state.date,
description:state.description
})) // parameters "id" & "status" loaded in Actions.
setState({title:"",
description:"",
place:"",
date:"",})
}
return (
<div className="todoContainer">
<form id="formulario"onSubmit={handleSubmit} >
<label>
Title
<input type="text" name="title" value={state.title} onChange={handleChange} />
</label>
<label>
Description
<textarea type="text" name="description" value={state.description} onChange= {handleChange}/>
</label>
<label>
Place
<input type="text" name="place" value={state.place} onChange={handleChange}/>
</label>
<label>
Date
<input type="text" name="date" value={state.date} onChange={handleChange}/>
</label>
<button className="boton" type="submit" onClick={addTodo}>Agregar</button>
</form>
</div>
)
};
function mapDispatchToProps(dispatch){
return{
addTodo: todo => dispatch(addTodo(todo))
}
}
export default connect(mapDispatchToProps)(AddTodo)
Now, i want to show at Todos ponent, every Todos "title", still didn't know how to perform it:
export function Todos(data) {
return (
<div className="todoDetail">
<h4>{data.title}</h4>
</div>
)
};
function mapStateToProps(state) {
return {
data: state.title,
};
}
export default connect(mapStateToProps)(Todos)
Share
Improve this question
edited Jul 16, 2021 at 1:08
Martin Gonzalez
asked Jul 15, 2021 at 22:41
Martin GonzalezMartin Gonzalez
771 gold badge1 silver badge13 bronze badges
2 Answers
Reset to default 4You looking for useSelector hook.
Do not use store.getState()
in functional ponent. Also, you do not need to connect
functions ponents, use useDispatch hook.
Getting values from store will be like this:
const todos = useSelector(store => store.items);
It's very odd they (code bootcamp) would require you to use a function ponent and then not allow you to use the React hooks that make the function ponents so appealing. No worries, you can still use the older connect
Higher Order Component to inject your redux state and dispatchable actions into the props passed to the ponent.
You've an issue in AddToDo
ponent. You are passing the mapDispatchToProps
to the connect
HOC where the mapStateToProps
callback would be passed. You also aren't using the injected addTodo
action you just mapped. You almost won't ever need to access the store
object directly to dispatch actions, use the React ponents/hooks.
export function AddTodo() {
const [state, setState] = React.useState({
title:"",
description:"",
place:"",
date:"",
});
function handleChange(e) {
const { value } = e.target;
setState(prevState => ({ // <-- use functional state update
...prevState,
[e.target.name]:value
}));
}
function handleSubmit(e) {
e.preventDefault();
this.props.addTodo({ // <-- addTodo action injected into props
place:state.place,
title:state.title,
date:state.date,
description:state.description
});
setState({
title:"",
description:"",
place:"",
date:"",
});
}
return (
<div className="todoContainer">
...
</div>
)
};
const mapDispatchToProps = {
addTodo,
}
export default connect(null, mapDispatchToProps)(AddTodo); // <-- mapStateToProps is null
In Todos
ponent, your todos state is an array, so you likely want to map it to JSX. Remember to destructure the passed props. Since you didn't share your reducers or how you bine your reducers I'm going to assume there is just one reducer for todos
located at the state root.
[update]
Since it seems your rootReducer
is just your todos
reducer function and I don't see where bineReducers
is used to build a more plex state tree, state
IS your todos
array state you are trying to pass to Todos
ponent.
[/update]
function Todos({ todos }) {
return (
<div className="todoDetail">
{todos.map((todo) => (
<h4 key={todo.id}>{todo.title}</h4>
))}
</div>
)
};
function mapStateToProps(state) {
return {
todos: state, // <-- state is todos array
};
}
export default connect(mapStateToProps)(Todos);