【问题标题】:How do I get the updated state from Redux using useEffect如何使用 useEffect 从 Redux 获取更新的状态
【发布时间】:2020-07-07 13:43:31
【问题描述】:

我正在创建一个 MERN 堆栈在线商店网站,并且我正在从我的 Shoes.js 组件中的 useEffect 挂钩中获取我的产品。但我只是从 redux 获取初始状态,而不是更新状态。

正在获取数据,但我只能访问初始状态。所以传递给 ProductsArea 组件的值是 false 和 null 我如何获得更新的状态?

这是我的 Shoes.js 文件:

import React, { useEffect } from 'react';
import './Shoes.css';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';


import { getProducts } from '../../../actions/productsActions';
import ProductsArea from './ProductsArea';
import Navbar from '../landing/Navbar';
import Search from './Search';
export const Shoes = (props) => {

  useEffect(() => {
    props.getProducts();

    console.log(props.products);
    console.log(props.loading);
  }, []); 
  if(props.loading) {
    return (
      <h1>loading</h1>
    )
  }

  else {
    return (
      <div>
        <Navbar />
        <div className="shoes">
          <Search />
          <h1 className="productsTitle">Our Selection</h1>
            <ProductsArea loading={props.loading} products={props.products} /> 
            {/* {
              props.products.map(product => (
                <ProductCard key={product._id} product={product} />
              ))
            } */}
        </div>
      </div>
    )
  }
}

const mapStateToProps = state => ({
  products: state.products.products,
  loading: state.products.loading
})

export default connect(mapStateToProps, { getProducts })(Shoes);

这是我的 productsActions 文件

import {GET_PRODUCTS, SET_LOADING, SET_ERROR} from './types';

export const getProducts = () => async (dispatch) => {
  try{
    setLoading();
    const res = await fetch('http://localhost:5000/products');
    const data = await res.json();
    console.log(data);
    dispatch({
      type: GET_PRODUCTS,
      payload: data
    });
  }
  catch(err) {
    dispatch({
      type: SET_ERROR,
      payload: err
    })
  }
}

export const setLoading = () => {
  console.log('Loading true');
  return {
    type: SET_LOADING
  }
}

这是 getProductsReducer 文件:

import {GET_PRODUCTS, SET_LOADING, SET_ERROR} from '../actions/types';
const initialState = {
  products: [],
  loading: false,
  error: null
}

export default (state = initialState, action) => {
  switch (action.type) {
    case GET_PRODUCTS: 
    console.log(action.payload);
      return {
        ...state,
        products: action.payload,
        loading: false
      }

    case SET_LOADING: 
      return {
        ...state,
        loading: true
      };

    case SET_ERROR: 
      console.log(action.payload);
      return {
        ...state,
        error: action.payload
      };
    default: return state;
  }
}

这是我用于 redux 的 index.js 文件:

import {combineReducers} from 'redux';
import getProductReducer from './getProductReducer';

export default combineReducers({
  products: getProductReducer
});

还有 Store.js 文件:

import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const initialState = {};

const middleware = [thunk];

const store = createStore(rootReducer, initialState, composeWithDevTools(applyMiddleware(...middleware)));

export default store;

所以我检查了 redux 扩展,状态显示在我的 Home.js 页面上,但没有显示在 Shoes.js 文件中

这是 Home.js 文件:

import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { getProducts, setLoading } from '../../../actions/productsActions';
import { connect } from 'react-redux';
import {Link} from 'react-router-dom';
import './Home.css';
import Navbar from './Navbar';
export const Home = (props) => {

  useEffect(() => {
    props.setLoading();
    props.getProducts();
    //eslint-disable-next-line
    console.log(props.products);
    console.log(props.loading);
  }, []); 
  if(props.loading) {
    return <div>loading</div>
  }
  else {
  return (
      <div>
        <Navbar />
        <div className="home">
          <div className="group-1">
            <div className="branding">
              <div className="brandName">
                The
                <br/>
                Sole
                <br/>
                Store
              </div>
              <div>
                  <p>The finest designs and fits.</p>
              </div>
            </div>
            <div className="viewProducts">
              <div>
                <p>
                  Check out our latest and greatest models
                </p>
                <Link className="productsBtn" to="/shoes">GO <i className="fas fa-arrow-right"/></Link>
              </div>
            </div>
          </div>
          <div className="group-2">
            <div className="products">
              <div className="product"></div>
              <div className="product"></div>
              <div className="product"></div>
              <div className="product"></div>
            </div>
            <div className="something"></div>
          </div>
        </div>
      </div>
    )
  }
}

Home.propTypes = {
  products: PropTypes.object.isRequired,
  loading: PropTypes.bool.isRequired
}

const mapStateToProps = state => ({
  products: state.products.products,
  loading: state.products.loading
});

export default connect(mapStateToProps, {getProducts, setLoading})(Home);

尽管如此,我仍然只能从 Home.js 获取控制台中的初始状态,而不是更新状态。

我已经按照@Kalhan.Toress 的建议进行了更改,这是更新后的 Shoes.js 文件

import React, { useEffect } from 'react';
import './Shoes.css';
// import { Link } from 'react-router-dom';
import { connect } from 'react-redux';

import { getProducts } from '../../../actions/productsActions';
import ProductsArea from './ProductsArea';
import Navbar from '../landing/Navbar';
import Search from './Search';
export const Shoes = (props) => {

  useEffect(() => {  
    props.fetchData();
    console.log(JSON.parse(props.products.products));
  }, []); 

  if(props.loading) {
    return (
      <h1>loading</h1>
    )
  }

  else {
    return (
      <div>
        <Navbar />
        <div className="shoes">
          <Search />
          <h1 className="productsTitle">Our Selection</h1>
            <ProductsArea loading={props.loading} products={JSON.parse(props.products.products)} /> 
            {/* {
              props.products.map(product => (
                <ProductCard key={product._id} product={product} />
              ))
            } */}
        </div>
      </div>
    )
  }
}

const mapDispatchToProps = dispatch => {
  return {
    fetchData: () => dispatch(getProducts())
  };
};

const mapStateToProps = state => ({
  products: state.products.products,
  loading: state.products.loading
})

export default connect(mapStateToProps, mapDispatchToProps)(Shoes);

我可以从主页单击指向 Shoes 页面的链接,一切正常,但是一旦我重新加载 Shoes.js 页面或直接转到它,我得到的错误是: 错误:引发了跨域错误。 React 无法访问开发中的实际错误对象。

这是我启用了 CORS 的服务器端的 App.js 文件:

const express = require('express');
const app = express();
const bodyParser = require('body-parser')
const productRoute = require('./products/productRoute');
const orderRoute = require('./orders/orderRoute');
const userRoute = require('./users/userRoute');
const adminRoute = require('./admins/adminRoute');
app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin','*');
    res.header('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type, Authorization, Accept');
    if(res.method === 'OPTIONS') {
        res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, PATCH, DELETE');
    }
    next();
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

app.use('/products', productRoute);
app.use('/orders', orderRoute);
app.use('/users', userRoute);
app.use('/admin', adminRoute);


app.use((req, res, next) => {
    const error = new Error();
    error.status = 404;
    next(error);
});

app.use((error, req, res, next) => {
    res.status(error.status || 500 ).json({
        error: error
    })
});

module.exports = app;

非常感谢任何帮助! 谢谢!

【问题讨论】:

  • console.log(action.payload);in reducer 有什么好处
  • 我得到了 products 数组,这就是我要找的
  • 如何在 redux 开发工具中探索状态?你的状态符合你的预期吗?
  • 我检查并使用另一个文件更新了我的帖子,该文件正在更新 redux 中的状态。但是 Shoes.js 没有在 redux 开发者工具中显示更新状态

标签: reactjs react-redux react-hooks


【解决方案1】:

我认为您发送同步操作的方式不正确

通过调用props.getProducts();,它将返回一个同步函数,正如我所见,这不会触发任何调度操作

const getProducts = () => async (dispatch) => {
  try{
  ....

确保它在下面放置console.log 并检查它

useEffect(() => {
    const returnedFromAction = props.getProducts();
    console.log(returnedFromAction); // this should prints the returned function and it will not get dispatched
    ....
}

这里你需要通过执行如下返回函数来调度同步操作

您必须添加mapDispatchToProps,如下所示

....
const mapDispatchToProps = dispatch => {
  return {
    fetchData: () => dispatch(getProducts())
  };
};    

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

然后在useEffect 内部使用这个fetchData 函数来调度获取操作,所以现在在useEffect

useEffect(() => {
  props.fetchData();
}, []);

这将为您完成工作,我为您创建了一个示例演示,请查看here

不使用redux hooks,这将与您的方法保持一致,但您可以通过以下方式轻松执行另一种方法。


import { useDispatch } from 'react-redux'; // import the dispatcher

const App = props => {
  const dispatch = useDispatch(); // get a reference to dispatch
  useEffect(() => {
    dispatch(getProducts()); // dispatch the action
  }, []);

in here

【讨论】:

  • 谢谢!有效!现在 Shoes.js 正在更新 redux 中的状态,但是当我控制台记录 getProducts 返回的函数时,它表明这是一个承诺。当我访问 props.products 或映射它时,它仍然是一个空数组并给我一个错误我使用了 mapDispatchToProps 方法,你能详细说明一下吗?我不太了解 MapDispatchToProps(这是第一次使用 Redux)
  • 很高兴能帮到你!!,我强烈建议你查看官方文档react-redux.js.org/using-react-redux/connect-mapstate,并从头开始阅读文档,您将在那里获得相当多的知识
  • 现在 Shoes.js 正在更新 redux 中的状态,但是当我控制台记录 getProducts 返回的函数时,它表明这是一个承诺。当我访问 props.products 或映射它时,它仍然是一个空数组并给我一个错误。你能指导我如何访问更新的状态而不是它给我的初始状态吗?
  • 我用更新后的代码和我收到的错误更新了我的帖子
  • 我猜你的错误是A cross-origin error was thrown,我猜你的反应应用程序和api托管在不同的域或同一域的不同端口中,我认为你可能需要单独讨论,首先检查如何通过谷歌搜索解决它,然后在 SO 中提出问题,快乐编码
猜你喜欢
  • 2021-05-18
  • 2020-08-16
  • 2021-08-30
  • 2021-03-06
  • 2021-11-01
  • 2020-01-29
  • 2020-06-10
  • 2022-01-04
  • 2019-10-15
相关资源
最近更新 更多