调用useffect()时未触发Redux操作(从数据库获取)
我正试图建立一个电子商务网站来学习Redux 目前,我正在尝试在安装组件时获取类别。因为我使用的是功能组件,所以我知道这是通过调用useffect()方法实现的 另外,我使用json服务器作为RESTAPI 我确信我已经成功地编写了我的增强器以传递到应用商店(开发工具和thunk)、创建的操作、还原器等等 我的问题是,当组件挂载时,操作不会触发 注意:在引入中间件和获取请求之前,一切正常。还考虑获取请求成功。 以下是涉及的代码 “src/index.js”调用useffect()时未触发Redux操作(从数据库获取),redux,react-redux,use-effect,Redux,React Redux,Use Effect,我正试图建立一个电子商务网站来学习Redux 目前,我正在尝试在安装组件时获取类别。因为我使用的是功能组件,所以我知道这是通过调用useffect()方法实现的 另外,我使用json服务器作为RESTAPI 我确信我已经成功地编写了我的增强器以传递到应用商店(开发工具和thunk)、创建的操作、还原器等等 我的问题是,当组件挂载时,操作不会触发 注意:在引入中间件和获取请求之前,一切正常。还考虑获取请求成功。 以下是涉及的代码 “src/index.js” import React from '
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()
时,它能工作吗?作为旁注,如果您只希望它在mountuseEffect(()=>{props.fetchCategories()},[])上运行,请将空括号作为useEffect的第二个参数包含在内。
@Grant Singleton,我在它之前尝试在useEffect外部调用它,但不起作用。必须是我将分派映射到道具的方式,或者是我执行操作的方式。我还尝试了此解决方案:“”,但仍然不起作用。另外,我知道操作中有第二个括号为空的参数:)console.log(),以查看它是否正在触发。然后将console.log()放入减速器中。查明行动或减速器是否未启动。我还没有看到您在操作中用来分派到减速机的语法,所以这可能是问题所在,但我还不确定。天哪,谢谢!这是处理具有使用效果的提取请求的正确方法吗?如果有一个最佳实践,你可以发布一个链接吗?无论如何,谢谢是的,这是一种方法,因为useEffect正在替换这里的组件。我唯一的建议是添加[]
,这样fetch只在mount上运行。如果没有它,你可能会得到比你需要的更多。如果您想向自己证明这一点,请尝试登录到useEffect内部的控制台,查看它何时运行