我正在开展一个新项目。我正在使用带有redux和thunk的create-react-app。 api服务器是一个单独的项目,它使用node / express和mongo / mongoose作为数据库。我想在创建或删除项目操作后重定向到项目列表视图。如果重定向位于组件本身中,则重定向在操作完成之前发生,并且在创建或删除发生之前重新发送列表。因此,我试图使用thunk在动作的.then()部分中调度重定向动作。重定向成功更改了浏览器中的URL,但未触发重新呈现。如何从create action或delete操作获取重定向以触发重新呈现stockitems列表组件?
完整代码位于:https://github.com/jhlindell/BarCode-app/tree/stockitem 服务器位于:https://github.com/jhlindell/BarCode-server/tree/jon
我的index.js:
import 'bootstrap/dist/css/bootstrap.css';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import React from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';
import { ConnectedRouter } from 'connected-react-router'
import { createStore, applyMiddleware, compose } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { createBrowserHistory } from 'history';
// import { browserHistory } from 'react-router'
import reducers from './reducers';
import thunk from 'redux-thunk';
import { connectRouter, routerMiddleware } from 'connected-react-router'
import { logger } from 'redux-logger';
const history = createBrowserHistory();
const reactRouterMiddleware = routerMiddleware(history);
const middleWares = [
thunk,
logger,
reactRouterMiddleware
]
const store = createStore(
connectRouter(history)(reducers),
composeWithDevTools(applyMiddleware(...middleWares)));
ReactDOM.render(
<Provider store = {store}>
<ConnectedRouter history={history}>
<App history={history}/>
</ConnectedRouter>
</Provider>
, document.getElementById('root'));
registerServiceWorker();
我的app.js文件:
import './App.css';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Footer from './components/Nav/Footer';
import NavBar from './components/Nav/NavBar';
import React, { Component } from 'react';
import StockItemCreate from './components/StockItems/StockItemCreate';
import StockItemDetail from './components/StockItems/StockItemDetail';
import StockItemList from './components/StockItems/StockItemList';
import HomePage from './components/HomePage';
class App extends Component {
com
render() {
const flexCol = {
display: 'flex',
flexDirection: 'column',
};
const flex0 = {
flex: 0
};
const flex1 = {
display: 'flex',
flex: '1 1 100%',
};
return (
<Router>
<div className="App" style={flexCol}>
<div style={flex0}>
<NavBar />
</div>
<div style={flex1} id="mainBlock">
<Switch>
<Route exact path='/' component={HomePage} />
<Route exact path='/stockitems/create' component={StockItemCreate} />
<Route exact path='/stockitems' component={StockItemList} />
<Route path='/stockitems/:id' component={StockItemDetail} />
</Switch>
</div>
<div style={flex0}>
<Footer />
</div>
</div>
</Router>
);
}
}
export default App;
列表组件:
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import React, {Component} from 'react';
import { getStockItemList, clearStockItemList } from '../../actions';
const listStyle = {
display: 'flex',
margin: 'auto'
}
class StockItemList extends Component {
componentDidMount(){
this.props.getStockItemList();
}
componentWillUnmount(){
this.props.clearStockItemList();
}
render(){
return (
<div style={listStyle}>
{this.props.stockItemList ? <ul className="list-group">
{this.props.stockItemList.map((item) => {
return <li
className="list-group-item"
key={item.name}
onClick={()=> this.props.history.push(`/stockitems/${item._id}`)}
>{item.name}</li>
})}
</ul> : <span>loading...</span>}
</div>
);
}
}
function mapStateToProps(state){
return { stockItemList: state.stockItemList }
}
function mapDispatchToProps(dispatch){
return bindActionCreators({ getStockItemList, clearStockItemList }, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(StockItemList);
创建组件:
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import React, {Component} from 'react';
import { createStockItem } from '../../actions'
const cardStyle = {
display: 'flex',
margin: 'auto',
};
const formStyle = {
display: 'flex',
flexDirection: 'column',
width: '80%',
margin: 'auto'
};
class StockItemCreate extends Component{
constructor(props){
super(props);
this.state = {
name: '',
description: ''
}
}
handleFormSubmit = (event) => {
event.preventDefault();
this.props.createStockItem(this.state);
this.clearForm();
//this.props.history.push('/stockitems');
}
handleInputChange = (event) => {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({[name]: value});
}
clearForm = () => {
this.setState({ name: '', description: ''});
}
render(){
return(
<form className="card" onSubmit={this.handleFormSubmit} style={cardStyle}>
<div className="card-header">
<h3>Add new ingredient</h3>
</div>
<div className="card-block mt-2">
<div style={formStyle}>
<label>Name</label>
<input name="name" type="text"
onChange={(e) => {this.handleInputChange(e)}}
placeholder="Name"
value={this.state.name}/>
</div>
<div className="mt-2" style={formStyle}>
<label>Description</label>
<input name="description" type="text"
onChange={(e) => {this.handleInputChange(e)}}
placeholder="Description"
value={this.state.description}/>
</div>
</div>
<div className="btn-group mb-2 mt-2" style={{padding: '0', margin: 'auto'}}>
<button className="btn btn-primary" type="submit">
Submit
</button>
<button className="btn btn-secondary" type="button" onClick={()=>this.clearForm()}>
Cancel
</button>
</div>
</form>
)
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({ createStockItem }, dispatch);
}
export default connect(null, mapDispatchToProps)(StockItemCreate);
最后,调用重定向的操作文件:
import axios from 'axios';
import { push, replace } from 'connected-react-router'
const URL = 'http://localhost:8000';
export function getStockItemList(){
return function(dispatch){
axios.get(`${URL}/api/stock_items/`)
.then((response) => {
dispatch({ type: 'STOCK_ITEM_LIST', payload: response.data });
})
.catch((error) => {
console.log('error getting stock items');
});
}
}
export function clearStockItemList(){
return { type: 'CLEAR_STOCK_ITEM_LIST' };
}
export function getStockItemById(id){
return function(dispatch){
axios.get(`${URL}/api/stock_items/${id}`)
.then((response) => {
dispatch({ type: 'SINGLE_STOCK_ITEM', payload: response.data });
})
.catch((error) => {
console.log('error getting stock item by id');
dispatch(push('/stockitems'));
});
}
}
export function clearSingleStockItem(){
return { type: 'CLEAR_SINGLE_STOCK_ITEM' };
}
export function createStockItem(item){
return function(dispatch){
axios.post(`${URL}/api/stock_items/`, item)
.then((response)=> {
console.log("response", response);
dispatch(push('/stockitems'));
})
.catch((error) => {
//create error container to post error to
console.log('error creating stock item', error);
});
}
}
export function deleteStockItem(id){
return function(dispatch){
axios.delete(`${URL}/api/stock_items/${id}`)
.then((response)=> {
console.log("delete response: ", response);
dispatch(push('/stockitems'));
})
.catch((error) => {
//create error container to post error to
console.log('error deleting stock item', error);
});
}
}
答案 0 :(得分:1)
请考虑使用push
中的connected-react-router
作为“动作创建者”,而不是this.props.history.push
答案 1 :(得分:0)
从此更改:
<Switch>
<Route path="/">
<Welcome />
</Route>
<Redirect to="/" />
</Switch>
对此:
<Switch>
<>
<Route path="/">
<Welcome />
</Route>
<Redirect to="/" />
</>
</Switch>
...为我工作。
我正在尝试为未明确指定的任何路径实现基本的后备重定向,因此诸如http:// localhost:3000 / askfjasdf之类的随机路径将重定向至http://localhost:3000
。由于某种原因,将片段添加为<Switch>
的顶级子级就可以了。