调用useffect()时未触发Redux操作(从数据库获取)

调用useffect()时未触发Redux操作(从数据库获取),redux,react-redux,use-effect,Redux,React Redux,Use Effect,我正试图建立一个电子商务网站来学习Redux 目前,我正在尝试在安装组件时获取类别。因为我使用的是功能组件,所以我知道这是通过调用useffect()方法实现的 另外,我使用json服务器作为RESTAPI 我确信我已经成功地编写了我的增强器以传递到应用商店(开发工具和thunk)、创建的操作、还原器等等 我的问题是,当组件挂载时,操作不会触发 注意:在引入中间件和获取请求之前,一切正常。还考虑获取请求成功。 以下是涉及的代码 “src/index.js” import React from '

我正试图建立一个电子商务网站来学习Redux

目前,我正在尝试在安装组件时获取类别。因为我使用的是功能组件,所以我知道这是通过调用useffect()方法实现的

另外,我使用json服务器作为RESTAPI

我确信我已经成功地编写了我的增强器以传递到应用商店(开发工具和thunk)、创建的操作、还原器等等

我的问题是,当组件挂载时,操作不会触发

注意:在引入中间件和获取请求之前,一切正常。还考虑获取请求成功。

以下是涉及的代码

“src/index.js”

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore, applyMiddleware, compose } from 'redux'
import { Provider } from 'react-redux'
import rootReducer from './reducers'
import thunk from 'redux-thunk'

const composedEnhancers = compose(applyMiddleware(thunk), window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())

const store = createStore(
  rootReducer, /* preloadedState, */
  composedEnhancers
);

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.

serviceWorker.unregister();
import * as actions from './../actions'

const initState = {
    categories: [],
    currentCategory: 'any',
    toggler: 'hidden'
}

const rootReducer = (state = initState, action) => {
    switch (action.type) {
        case actions.SELECT_CATEGORY:
            return { ...state, currentCategory: action.payload.value }
        case actions.FETCH_CATEGORIES:
            return { ...state, categories: action.payload }
        case actions.TOGGLE:
            return { ...state, toggler: action.payload.toggler }
        default:
            return state
    }
}

export default rootReducer
“actions/index.js”中的操作创建者:

export const FETCH_CATEGORIES = 'FETCH_CATEGORIES'
export const fetchCategories = () => (dispatch) => {
    fetch("http://localhost:7000/categories")
        .then(response => response.json())
        .then(categories => {
            return {
                type: FETCH_CATEGORIES,
                payload: categories
            }
        })

}
“reducers/index.js”

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore, applyMiddleware, compose } from 'redux'
import { Provider } from 'react-redux'
import rootReducer from './reducers'
import thunk from 'redux-thunk'

const composedEnhancers = compose(applyMiddleware(thunk), window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())

const store = createStore(
  rootReducer, /* preloadedState, */
  composedEnhancers
);

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.

serviceWorker.unregister();
import * as actions from './../actions'

const initState = {
    categories: [],
    currentCategory: 'any',
    toggler: 'hidden'
}

const rootReducer = (state = initState, action) => {
    switch (action.type) {
        case actions.SELECT_CATEGORY:
            return { ...state, currentCategory: action.payload.value }
        case actions.FETCH_CATEGORIES:
            return { ...state, categories: action.payload }
        case actions.TOGGLE:
            return { ...state, toggler: action.payload.toggler }
        default:
            return state
    }
}

export default rootReducer
“Filter.js”组件

import React, { useEffect } from 'react';
import { connect } from 'react-redux'
import { selectCategory, fetchCategories } from '../../../../actions'



const Filter = (props) => {

    // const [minPrice, setMinPrice] = useState(0)
    // const handleMinPrice = event => {
    //     setMinPrice(event.target.value)
    // }

    // const [maxPrice, setMaxPrice] = useState(0)
    // const handleMaxPrice = event => {
    //     setMaxPrice(event.target.value)
    // }

    // const [department, setDepartment] = useState("select")
    // const handleDepartment = event => {
    //     console.log(event.target.value)
    //     setDepartment(event.target.value)
    // }
    // console.log(props);


    const handleChange = event => {
        event.preventDefault()
        props.selectCategory(event.target.value)
    }

    useEffect(() => {
        props.fetchCategories()
    })


    return (
        <div className="filter-form col-12">
            <form id="filter-category">
                <label htmlFor="category">Category</label>
                <select className="col-12" id="category" name="category" size="5" value={props.currentCategory} onChange={(event) => handleChange(event)}>
                    {props.categories.map(category => <option key={category.value} value={category.value}>{category.name}</option>)}
                </select>
            </form>
            {props.currentCategory !== 'any' && <form id="filter-department">
                <label htmlFor="department">Department</label>
                <select className="col-12" id="department" name="department" size="5" value='{department}' onChange='{handleDepartment}'>
                    <option value="select">--- Select ---</option>
                    <option value="desktop PCs">Desktop PCs</option>
                    <option value="laptops">Laptops</option>
                    <option value="gamepads">Gamepads</option>
                    <option value="headphones">Headphones</option>
                    <option value="microphones">Microphones</option>
                    <option value="keyboards">Keyboards</option>
                </select>
            </form>}
            {/* <form id="filter-price">
                <label htmlFor="minimum-price">Min. Price: {minPrice}£</label>
                <input type="range" min="1" max="100" value={minPrice} className="slider col-xs-12" id="minimum-price" onChange={handleMinPrice} />
                <label htmlFor="maximum-price">Max. Price: {maxPrice}£</label>
                <input type="range" min="100" max="1000" value={maxPrice} className="slider col-xs-12" id="maximum-price" onChange={handleMaxPrice} />
            </form> */}
        </div>
    );
}

const mapStateToProps = (state) => {
    return {
        categories: state.categories,
        currentCategory: state.currentCategory
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        selectCategory: (value) => {
            dispatch(selectCategory(value))
        },
        fetchCategories: () => {
            dispatch(fetchCategories())
        }

    }
}

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

我在这里遗漏了什么?

尝试在操作中这样调度,该操作将触发reducer FETCH\u类别:

export const fetchCategories = () => (dispatch) => {
    fetch("http://localhost:7000/categories")
        .then(response => response.json())
        .then(categories => {
            // **Changes start here
            dispatch ({
                type: FETCH_CATEGORIES,
                payload: categories
            })
            // **Changes end here
        })

}

当您在useEffect外部调用
fetchCategories()
时,它能工作吗?作为旁注,如果您只希望它在mount
useEffect(()=>{props.fetchCategories()},[])上运行,请将空括号作为useEffect的第二个参数包含在内。
@Grant Singleton,我在它之前尝试在useEffect外部调用它,但不起作用。必须是我将分派映射到道具的方式,或者是我执行操作的方式。我还尝试了此解决方案:“”,但仍然不起作用。另外,我知道操作中有第二个括号为空的参数:)console.log(),以查看它是否正在触发。然后将console.log()放入减速器中。查明行动或减速器是否未启动。我还没有看到您在操作中用来分派到减速机的语法,所以这可能是问题所在,但我还不确定。天哪,谢谢!这是处理具有使用效果的提取请求的正确方法吗?如果有一个最佳实践,你可以发布一个链接吗?无论如何,谢谢是的,这是一种方法,因为useEffect正在替换这里的组件。我唯一的建议是添加
[]
,这样fetch只在mount上运行。如果没有它,你可能会得到比你需要的更多。如果您想向自己证明这一点,请尝试登录到useEffect内部的控制台,查看它何时运行