最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to retrieve data from Redux store using functional components and avoiding useSelector & useDispatch -

programmeradmin2浏览0评论

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
Add a ment  | 

2 Answers 2

Reset to default 4

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

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论