如何使用功能组件从 Redux 存储中检索数据并避免 useSelector 和 useDispatch
How to retrieve data from Redux store using functional components and avoiding useSelector & useDispatch
我正在尝试在 React-Redux 中开发 Todo App;获得了存储、操作、reducer 和 Addodo 组件 运行;但在显示待办事项时卡住了:
如果我的 initialState=[] 我如何从存储中检索数据?
商店:
import { createStore } from 'redux';
import rootReducer from '../reducer';
export const store = createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store
我的减速器:
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/components/Nav/Nav'
import Home from '../src/components/Home/Home'
import AddTodo from '../src/components/AddTodo/AddTodo'
import TodoDetail from '../src/components/TodoDetail/TodoDetail'
import './App.css';
export function App() {
return (
<React.Fragment>
<Provider store={store}>
<Nav />
<Route exact path="/" component={Home} />
<Route path="/add" component={AddTodo} />
<Route path="/edit/:id" component={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;
这是 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)
现在,我想在Todos组件上展示,每个Todos的“title”,还不知道怎么实现:
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)
您正在寻找 useSelector 钩子。
不要在功能组件中使用store.getState()
。另外,你不需要connect
函数组件,使用useDispatch钩子。
从存储中获取值将是这样的:
const todos = useSelector(store => store.items);
他们(代码训练营)要求您使用功能组件,然后不允许您使用使功能组件如此吸引人的 React 挂钩,这很奇怪。不用担心,您仍然可以使用旧的 connect
高阶组件将您的 redux 状态和可调度操作注入传递给该组件的 props。
您在 AddToDo
组件中遇到问题。您正在将 mapDispatchToProps
传递给 connect
HOC,其中将传递 mapStateToProps
回调。您也没有使用刚刚映射的注入 addTodo
操作。您几乎不需要直接访问 store
对象来调度操作,使用 React components/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
在 Todos
组件中,您的待办事项状态是一个数组,因此您可能希望将其映射到 JSX。记得解构传递的道具。因为你没有分享你的减速器或者你如何组合你的减速器,我假设只有一个减速器用于 todos
位于状态根。
[更新]
因为看起来你的 rootReducer
只是你的 todos
reducer 函数而且我没有看到 combineReducers
在哪里用于构建更复杂的状态树,state
IS 您正试图传递给 Todos
组件的 todos
数组状态。
[/更新]
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);
我正在尝试在 React-Redux 中开发 Todo App;获得了存储、操作、reducer 和 Addodo 组件 运行;但在显示待办事项时卡住了:
如果我的 initialState=[] 我如何从存储中检索数据?
商店:
import { createStore } from 'redux';
import rootReducer from '../reducer';
export const store = createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store
我的减速器:
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/components/Nav/Nav'
import Home from '../src/components/Home/Home'
import AddTodo from '../src/components/AddTodo/AddTodo'
import TodoDetail from '../src/components/TodoDetail/TodoDetail'
import './App.css';
export function App() {
return (
<React.Fragment>
<Provider store={store}>
<Nav />
<Route exact path="/" component={Home} />
<Route path="/add" component={AddTodo} />
<Route path="/edit/:id" component={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;
这是 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)
现在,我想在Todos组件上展示,每个Todos的“title”,还不知道怎么实现:
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)
您正在寻找 useSelector 钩子。
不要在功能组件中使用store.getState()
。另外,你不需要connect
函数组件,使用useDispatch钩子。
从存储中获取值将是这样的:
const todos = useSelector(store => store.items);
他们(代码训练营)要求您使用功能组件,然后不允许您使用使功能组件如此吸引人的 React 挂钩,这很奇怪。不用担心,您仍然可以使用旧的 connect
高阶组件将您的 redux 状态和可调度操作注入传递给该组件的 props。
您在 AddToDo
组件中遇到问题。您正在将 mapDispatchToProps
传递给 connect
HOC,其中将传递 mapStateToProps
回调。您也没有使用刚刚映射的注入 addTodo
操作。您几乎不需要直接访问 store
对象来调度操作,使用 React components/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
在 Todos
组件中,您的待办事项状态是一个数组,因此您可能希望将其映射到 JSX。记得解构传递的道具。因为你没有分享你的减速器或者你如何组合你的减速器,我假设只有一个减速器用于 todos
位于状态根。
[更新]
因为看起来你的 rootReducer
只是你的 todos
reducer 函数而且我没有看到 combineReducers
在哪里用于构建更复杂的状态树,state
IS 您正试图传递给 Todos
组件的 todos
数组状态。
[/更新]
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);