如何使用 React-Redux 将 XHR 请求的响应带入状态
How to bring the response of an XHR request into state with React-Redux
我正在尝试获取 XHR 请求的响应作为我的 React 容器中的道具。我想要做的是向 api 发出 GET 请求,然后将响应转换为一个名为 "game" 的对象,我可以在 React 中访问该对象。我成功地用 GET 请求做了类似的事情,该请求返回了一个名为 "games" 的对象数组,我可以在反应中对其进行映射;但是,当我尝试请求 "game" 对象时,我从 api 得到了很好的响应,但反应显示 "game" 未定义。
我认为我遇到的问题可能出在我的 reducer 或操作文件上,也许是我如何设置初始状态,但我不知道如何让它工作。
感谢您提供的所有帮助!非常感谢您的时间和耐心。
我在下面发布我的代码。
reducer 文件如下所示:
import { LOAD_GAMES, SET_CURRENT_GAME } from "../actionTypes";
const game = (state = [], action) => {
switch (action.type) {
case LOAD_GAMES:
return [...action.games];
case SET_CURRENT_GAME:
return [...action.game];
default:
return state;
}
};
export default game;
操作文件如下所示:
import { apiCall } from "../../services/api";
import { addError } from "./errors";
import { LOAD_GAMES, SET_CURRENT_GAME } from "../actionTypes";
export const loadGames = games => ({
type: LOAD_GAMES,
games
});
export const setCurrentGame = game => ({
type: SET_CURRENT_GAME,
game
});
export const fetchGames = () => {
return dispatch => {
return apiCall("GET", "api/games/")
.then(res => {
dispatch(loadGames(res));
})
.catch(err => {
dispatch(addError(err.message));
});
};
};
//WRITE A FUNCTION TO SET_CURRENT_GAME TO BE THE ID OF THE GAME THAT IS CLICKED ON.
export const getGameDetails = game_id => {
return dispatch => {
return apiCall("GET", `/api/games/${game_id}`)
.then(res => {
dispatch(setCurrentGame(res));
})
.catch(err => {
dispatch(addError(err.message));
});
};
};
export const postNewGame = title => (dispatch, getState) => {
return apiCall("post", "/api/games", { title })
.then(res => {})
.catch(err => addError(err.message));
};
React 容器如下所示:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { getGameDetails } from "../store/actions/games";
class GameDetails extends Component {
componentDidMount() {
const game_id= this.props.match.params.game_id;
this.props.getGameDetails(game_id);
}
render() {
const { game } = this.props;
return (
<div className="home-hero">
<div className="offset-1 col-sm-10">
<h4>You are viewing the Game Page for {game.title}</h4>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
game: state.game
};
}
export default connect(mapStateToProps, { getGameDetails })(
GameDetails
);
编辑——通过显示游戏响应数组的映射来工作的 GameList 容器如下所示:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { fetchGames } from "../store/actions/games";
class GameList extends Component {
componentDidMount() {
this.props.fetchGames();
}
render() {
const { games } = this.props;
let gameList = games.map(g => (
<li className="list-group-item" key= {g._id}>
<Link to={`/games/${g._id}`}>
{g.title}
</Link>
</li>
));
return (
<div className="row col-sm-8">
<div className="offset-1 col-sm-10">
<ul className="list-group" id="games">
{gameList}
</ul>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
games: state.games
};
}
export default connect(mapStateToProps, { fetchGames })(
GameList
);
澄清一下,reducer 和 action 的 "LOAD_GAMES" 部分运行良好;但是,"SET_CURRENT_GAME" 不起作用。
我认为你用错了reducer
reducer 的状态应该是对象,而不是数组 IMO,例如这样:
import { LOAD_GAMES, SET_CURRENT_GAME } from "../actionTypes";
const initState = {
current: {},
list: []
}
const game = (state = initState, action) => {
switch (action.type) {
case LOAD_GAMES:
return {
...state,
list: action.games
};
case SET_CURRENT_GAME:
return {
...state,
current: action.game
};
default:
return state;
}
};
export default game;
比 GameDetails
function mapStateToProps(state) {
return {
game: state.games.current
};
}
并且在同一个 GameList
function mapStateToProps(state) {
return {
list: state.games.list
};
}
我正在尝试获取 XHR 请求的响应作为我的 React 容器中的道具。我想要做的是向 api 发出 GET 请求,然后将响应转换为一个名为 "game" 的对象,我可以在 React 中访问该对象。我成功地用 GET 请求做了类似的事情,该请求返回了一个名为 "games" 的对象数组,我可以在反应中对其进行映射;但是,当我尝试请求 "game" 对象时,我从 api 得到了很好的响应,但反应显示 "game" 未定义。
我认为我遇到的问题可能出在我的 reducer 或操作文件上,也许是我如何设置初始状态,但我不知道如何让它工作。
感谢您提供的所有帮助!非常感谢您的时间和耐心。
我在下面发布我的代码。
reducer 文件如下所示:
import { LOAD_GAMES, SET_CURRENT_GAME } from "../actionTypes";
const game = (state = [], action) => {
switch (action.type) {
case LOAD_GAMES:
return [...action.games];
case SET_CURRENT_GAME:
return [...action.game];
default:
return state;
}
};
export default game;
操作文件如下所示:
import { apiCall } from "../../services/api";
import { addError } from "./errors";
import { LOAD_GAMES, SET_CURRENT_GAME } from "../actionTypes";
export const loadGames = games => ({
type: LOAD_GAMES,
games
});
export const setCurrentGame = game => ({
type: SET_CURRENT_GAME,
game
});
export const fetchGames = () => {
return dispatch => {
return apiCall("GET", "api/games/")
.then(res => {
dispatch(loadGames(res));
})
.catch(err => {
dispatch(addError(err.message));
});
};
};
//WRITE A FUNCTION TO SET_CURRENT_GAME TO BE THE ID OF THE GAME THAT IS CLICKED ON.
export const getGameDetails = game_id => {
return dispatch => {
return apiCall("GET", `/api/games/${game_id}`)
.then(res => {
dispatch(setCurrentGame(res));
})
.catch(err => {
dispatch(addError(err.message));
});
};
};
export const postNewGame = title => (dispatch, getState) => {
return apiCall("post", "/api/games", { title })
.then(res => {})
.catch(err => addError(err.message));
};
React 容器如下所示:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { getGameDetails } from "../store/actions/games";
class GameDetails extends Component {
componentDidMount() {
const game_id= this.props.match.params.game_id;
this.props.getGameDetails(game_id);
}
render() {
const { game } = this.props;
return (
<div className="home-hero">
<div className="offset-1 col-sm-10">
<h4>You are viewing the Game Page for {game.title}</h4>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
game: state.game
};
}
export default connect(mapStateToProps, { getGameDetails })(
GameDetails
);
编辑——通过显示游戏响应数组的映射来工作的 GameList 容器如下所示:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { fetchGames } from "../store/actions/games";
class GameList extends Component {
componentDidMount() {
this.props.fetchGames();
}
render() {
const { games } = this.props;
let gameList = games.map(g => (
<li className="list-group-item" key= {g._id}>
<Link to={`/games/${g._id}`}>
{g.title}
</Link>
</li>
));
return (
<div className="row col-sm-8">
<div className="offset-1 col-sm-10">
<ul className="list-group" id="games">
{gameList}
</ul>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
games: state.games
};
}
export default connect(mapStateToProps, { fetchGames })(
GameList
);
澄清一下,reducer 和 action 的 "LOAD_GAMES" 部分运行良好;但是,"SET_CURRENT_GAME" 不起作用。
我认为你用错了reducer
reducer 的状态应该是对象,而不是数组 IMO,例如这样:
import { LOAD_GAMES, SET_CURRENT_GAME } from "../actionTypes";
const initState = {
current: {},
list: []
}
const game = (state = initState, action) => {
switch (action.type) {
case LOAD_GAMES:
return {
...state,
list: action.games
};
case SET_CURRENT_GAME:
return {
...state,
current: action.game
};
default:
return state;
}
};
export default game;
比 GameDetails
function mapStateToProps(state) {
return {
game: state.games.current
};
}
并且在同一个 GameList
function mapStateToProps(state) {
return {
list: state.games.list
};
}