【问题标题】:How to retrieve data from Redux store using functional components and avoiding useSelector & useDispatch如何使用功能组件从 Redux 存储中检索数据并避免 useSelector 和 useDispatch
【发布时间】:2021-07-15 22:41:53
【问题描述】:

我正在 React-Redux 中尝试 Todo App;运行 store、actions、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 “标题”,仍然不知道如何执行:

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)     

【问题讨论】:

    标签: javascript reactjs redux state mapstatetoprops


    【解决方案1】:

    你正在寻找useSelector钩子。

    不要在函数组件中使用store.getState()。另外,你不需要connect函数组件,使用useDispatch钩子。

    从 store 中获取值是这样的:

    const todos = useSelector(store => store.items);
    

    【讨论】:

    • 非常感谢您的回答安东!我的错误,我编辑我的问题。不允许使用 UseSelector 或 UseDispatch。我希望我能做到!我发现的所有代码示例都建议我这样做
    • @MartinGonzalez 为什么你试图避免使用默认功能?在这种情况下,您可以在制作时使用类组件connectprops.data 将收集您的数据。
    • 事情是安东,我在诅咒一个开发训练营,无法通过 Redux 检查点,现在我正在研究再次进行检查点。他们给了我这些规则:不能使用useDispatch,不能使用useSelector,必须在功能组件上开发并且初始State必须只是一个数组(initialState=[])
    【解决方案2】:

    很奇怪,他们(代码训练营)会要求您使用函数组件,然后不允许您使用使函数组件如此吸引人的 React 钩子。不用担心,您仍然可以使用旧的 connect 高阶组件将您的 redux 状态和可调度操作注入到传递给组件的 props 中。

    AddToDo 组件有问题。您正在将 mapDispatchToProps 传递给 connect HOC,其中将传递 mapStateToProps 回调。您也没有使用刚刚映射的注入 addTodo 操作。您几乎不需要直接访问 store 对象来调度操作,使用 React 组件/钩子。

    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);
    

    【讨论】:

    • 非常感谢您的回答 Drew,感谢您抽出宝贵时间帮助我。我收到此错误:TypeError: todos is undefined。试图理解......在从 mapStateToProps 返回时,当你调用 state.todos 时:我在 Redux 的状态说:{title:"some title", place:"right here", description:"some example text", date: “现在”,id:“1”,状态:“进行中”} 我想把它命名为 state.title,但也没有工作。对不起我的英语和编码不好!!!
    • @MartinGonzalez 我认为问题可能在于您的减速器,因为您共享的 UI 代码和我在回答中使用的似乎对状态形状做出了一些假设。您能否更新您的问题以添加减速器以及如何创建商店并提供 redux 上下文(商店提供者)?
    • @MartinGonzalez 那么state.todosmapStateToProps 中未定义吗?
    • TypeError: todos 未定义 Todos F:/NETBUSTER/HENRY/EXAMEN/CP-M2-FT15a/src/components/Todos/Todos.js:6 3 | 4 |功能待办事项({待办事项}){ 5 |返回 ( > 6 |
      7 | {todos.map((todo) => ( 8 |

      {todo.title}

      9 | ) )}
    • @MartinGonzalez 我看不到您在哪里渲染Todos 组件。如果您正在导出 Todos 并默认导出已连接的版本,请仔细检查您是否使用默认导出,以便它正确连接到您的 redux 存储。
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签