ReactJS:如何从子组件访问道具
ReactJS: how to access prop from child component
我正在学习 React.js 并且我正在尝试制作一个网站 API。
对于我的一个小部件,我想显示几个口袋妖怪及其统计信息。
为此,我有一个主要组件,它将调用 API 并填充我的状态数组,然后在地图中调用 CardPokemon 子组件以显示每个口袋妖怪。
这是我的问题,在我的 Web 控制台中,我可以看到我的不同 pokemons 统计状态数组正在填满,但在我的主要组件的渲染中,我的数组的值仍然是“未定义的”。
我试图在我的代码中实现这个问题的第一个答案:,但我仍然遇到同样的问题,我的数组的值在渲染中保持“未定义”。
我在这里放了一部分代码,如有任何帮助,我们将不胜感激。
class CardPokemon extends Component {
render() {
return (
<div className="Card">
<div className="Card__img">
<img src={this.props.pokemonImgProp[this.props.id]} alt="" />
</div>
...
</div>
);
}
}
class GenerationPokemonStat extends Component {
constructor(props) {
super(props);
this.state = {
pokemonNameListAPI: [],
pokemonImgAPI: []
...
};
}
searchAllPokemon = () => {
let number = 151; //for the 151 first pokemon
Axios.get(`http://localhost:5000/getPokemonByGeneration/allPokemonGen/${number}`)
.then(res => {
var i;
for (i = 0; i < number; i++) {
let copyNameArray = this.state.pokemonNameListAPI.slice();
copyNameArray[i] = res.data.results[i].name;
this.setState({ pokemonNameListAPI: copyNameArray })
Axios.get(`http://localhost:5000/getPokemonByGeneration/one_pokemon_gen/${this.state.pokemonNameListAPI[i]}`)
.then(response => {
let copyImgArray = this.state.pokemonImgAPI.slice();
copyImgArray[i] = response.data.sprites.front_default;
this.setState({ pokemonImgAPI: copyImgArray });
...
//everything display normally in web console here
console.log(response);
console.log(this.state.pokemonNameAPI[i]);
console.log(this.state.pokemonImgAPI[i]);
})
}
})
}
render() {
let pokemonNameListAPI = this.state.pokemonNameListAPI;
let pokemonImgAPI = this.state.pokemonImgAPI;
//appears to be undefined in web console
console.log(this.state.pokemonImgAPI[0]);
if(!pokemonNameListAPI) {
return null;
}
return (
<>
<div>
<button onClick={this.searchAllPokemon}>Search Pokemon</button>
{pokemonNameListAPI[151] === undefined ? <h1 style={{ textAlign: 'center' }}>Loading...</h1> : (
<>
<div className="grid-container">
{pokemonNameListAPI.map((i) => {
//this console.log show me undefined for pokemonImgAPI[i]
console.log(pokemonImgAPI[i]);
return <CardPokemon
key={i}
id={i}
pokemonImgProp={pokemonImgAPI}
/>
})}
</div>
</>
)}
</div>
</>
);
}
}
export default GenerationPokemonStat;
代码已编辑但仍无法运行
我已尝试实施您告诉我的内容,但仍然无法正常工作,我这样做对吗?
function CardPokemon({ pokemonStatProp }) {
return (
<div className="Card">
<div className="Card__img">
<img src={pokemonStatProp[1]} alt="" />
</div>
<div className="Card__name">
{pokemonStatProp[0]}
</div>
</div>
);
}
class GenerationPokemonStat extends Component {
constructor(props) {
super(props);
this.state = {
pokemonNameAPI: [],
pokemonImgAPI: [],
pokemonLoading: true
};
}
searchAllPokemon = () => {
this.setState({ pokemonLoading: true });
let number = 10;
Axios.get(`http://localhost:5000/getPokemonByGeneration/allPokemonGen/${number}`)
.then(res => {
let nameArray = this.state.pokemonNameListAPI.slice();
let imgArray = this.state.pokemonImgAPI.slice();
for (let i = 0; i < number; i++) {
nameArray[i] = res.data.results[i].name;
Axios.get(`http://localhost:5000/getPokemonByGeneration/one_pokemon_gen/${nameArray[i]}`)
.then(response => {
imgArray[i] = response.data.sprites.front_default;
})
}
this.setState({ pokemonNameListAPI: nameArray });
this.setState({ pokemonImgAPI: imgArray });
this.setState({ pokemonLoading: false });
})
}
render() {
return (
<>
<div>
<button onClick={this.searchAllPokemon}>Search Pokemon</button>
{this.state.pokemonLoading === true ? <h1 style={{ textAlign: 'center' }}>Loading...</h1> : (
<>
<div className="grid-container">
{this.state.pokemonNameListAPI.map((i) => {
let pokemonStat = [];
pokemonStat[0] = this.state.pokemonNameListAPI[i];
pokemonStat[1] = this.state.pokemonImgAPI[i];
return <CardPokemon
key={i}
pokemonStatProp={pokemonStat}
/>
})}
</div>
</>
)}
</div>
</>
);
}
}
export default GenerationPokemonStat;
您不应在设置状态后立即尝试读取状态,因为状态更新可能会异步执行(请参阅 State Updates May Be Asynchronous)。在您的情况下,这可能意味着第二次 axios 调用未获得您期望的参数并返回空结果。
试试这个:
searchAllPokemon = () => {
let number = 151; //for the 151 first pokemon
Axios.get(`http://localhost:5000/getPokemonByGeneration/allPokemonGen/${number}`)
.then(res => {
// Could also use computed property name.
var combined: {name, img}[] = [];
for (let i = 0; i < number; i++) {
combined.push({name: res.data.results[i].name});
Axios.get(`http://localhost:5000/getPokemonByGeneration/one_pokemon_gen/${res.data.results[i].name}`)
.then(response => {
// Have an img for a name.
// Find the array item matching this name so we can
// set the img value.
// This requires you to have the pokemon name in results.
// If using computed property we could use bracket
// notation here instead of find.
let c = combined.find(f => f.name === response.data.sprites.front.name);
c.img = response.data.sprites.front_default;
...
})
}
this.setState({combinedAPI: combined})
})
}
此外,请记住,每当您更新状态时,React 都会检测到状态更改并导致组件刷新。您当前正在一个循环中执行两个 setState 调用。我会考虑将你的 axios 结果构造成局部变量和 setState,一次,在循环之外。
我正在学习 React.js 并且我正在尝试制作一个网站 API。
对于我的一个小部件,我想显示几个口袋妖怪及其统计信息。
为此,我有一个主要组件,它将调用 API 并填充我的状态数组,然后在地图中调用 CardPokemon 子组件以显示每个口袋妖怪。
这是我的问题,在我的 Web 控制台中,我可以看到我的不同 pokemons 统计状态数组正在填满,但在我的主要组件的渲染中,我的数组的值仍然是“未定义的”。
我试图在我的代码中实现这个问题的第一个答案:
我在这里放了一部分代码,如有任何帮助,我们将不胜感激。
class CardPokemon extends Component {
render() {
return (
<div className="Card">
<div className="Card__img">
<img src={this.props.pokemonImgProp[this.props.id]} alt="" />
</div>
...
</div>
);
}
}
class GenerationPokemonStat extends Component {
constructor(props) {
super(props);
this.state = {
pokemonNameListAPI: [],
pokemonImgAPI: []
...
};
}
searchAllPokemon = () => {
let number = 151; //for the 151 first pokemon
Axios.get(`http://localhost:5000/getPokemonByGeneration/allPokemonGen/${number}`)
.then(res => {
var i;
for (i = 0; i < number; i++) {
let copyNameArray = this.state.pokemonNameListAPI.slice();
copyNameArray[i] = res.data.results[i].name;
this.setState({ pokemonNameListAPI: copyNameArray })
Axios.get(`http://localhost:5000/getPokemonByGeneration/one_pokemon_gen/${this.state.pokemonNameListAPI[i]}`)
.then(response => {
let copyImgArray = this.state.pokemonImgAPI.slice();
copyImgArray[i] = response.data.sprites.front_default;
this.setState({ pokemonImgAPI: copyImgArray });
...
//everything display normally in web console here
console.log(response);
console.log(this.state.pokemonNameAPI[i]);
console.log(this.state.pokemonImgAPI[i]);
})
}
})
}
render() {
let pokemonNameListAPI = this.state.pokemonNameListAPI;
let pokemonImgAPI = this.state.pokemonImgAPI;
//appears to be undefined in web console
console.log(this.state.pokemonImgAPI[0]);
if(!pokemonNameListAPI) {
return null;
}
return (
<>
<div>
<button onClick={this.searchAllPokemon}>Search Pokemon</button>
{pokemonNameListAPI[151] === undefined ? <h1 style={{ textAlign: 'center' }}>Loading...</h1> : (
<>
<div className="grid-container">
{pokemonNameListAPI.map((i) => {
//this console.log show me undefined for pokemonImgAPI[i]
console.log(pokemonImgAPI[i]);
return <CardPokemon
key={i}
id={i}
pokemonImgProp={pokemonImgAPI}
/>
})}
</div>
</>
)}
</div>
</>
);
}
}
export default GenerationPokemonStat;
代码已编辑但仍无法运行 我已尝试实施您告诉我的内容,但仍然无法正常工作,我这样做对吗?
function CardPokemon({ pokemonStatProp }) {
return (
<div className="Card">
<div className="Card__img">
<img src={pokemonStatProp[1]} alt="" />
</div>
<div className="Card__name">
{pokemonStatProp[0]}
</div>
</div>
);
}
class GenerationPokemonStat extends Component {
constructor(props) {
super(props);
this.state = {
pokemonNameAPI: [],
pokemonImgAPI: [],
pokemonLoading: true
};
}
searchAllPokemon = () => {
this.setState({ pokemonLoading: true });
let number = 10;
Axios.get(`http://localhost:5000/getPokemonByGeneration/allPokemonGen/${number}`)
.then(res => {
let nameArray = this.state.pokemonNameListAPI.slice();
let imgArray = this.state.pokemonImgAPI.slice();
for (let i = 0; i < number; i++) {
nameArray[i] = res.data.results[i].name;
Axios.get(`http://localhost:5000/getPokemonByGeneration/one_pokemon_gen/${nameArray[i]}`)
.then(response => {
imgArray[i] = response.data.sprites.front_default;
})
}
this.setState({ pokemonNameListAPI: nameArray });
this.setState({ pokemonImgAPI: imgArray });
this.setState({ pokemonLoading: false });
})
}
render() {
return (
<>
<div>
<button onClick={this.searchAllPokemon}>Search Pokemon</button>
{this.state.pokemonLoading === true ? <h1 style={{ textAlign: 'center' }}>Loading...</h1> : (
<>
<div className="grid-container">
{this.state.pokemonNameListAPI.map((i) => {
let pokemonStat = [];
pokemonStat[0] = this.state.pokemonNameListAPI[i];
pokemonStat[1] = this.state.pokemonImgAPI[i];
return <CardPokemon
key={i}
pokemonStatProp={pokemonStat}
/>
})}
</div>
</>
)}
</div>
</>
);
}
}
export default GenerationPokemonStat;
您不应在设置状态后立即尝试读取状态,因为状态更新可能会异步执行(请参阅 State Updates May Be Asynchronous)。在您的情况下,这可能意味着第二次 axios 调用未获得您期望的参数并返回空结果。
试试这个:
searchAllPokemon = () => {
let number = 151; //for the 151 first pokemon
Axios.get(`http://localhost:5000/getPokemonByGeneration/allPokemonGen/${number}`)
.then(res => {
// Could also use computed property name.
var combined: {name, img}[] = [];
for (let i = 0; i < number; i++) {
combined.push({name: res.data.results[i].name});
Axios.get(`http://localhost:5000/getPokemonByGeneration/one_pokemon_gen/${res.data.results[i].name}`)
.then(response => {
// Have an img for a name.
// Find the array item matching this name so we can
// set the img value.
// This requires you to have the pokemon name in results.
// If using computed property we could use bracket
// notation here instead of find.
let c = combined.find(f => f.name === response.data.sprites.front.name);
c.img = response.data.sprites.front_default;
...
})
}
this.setState({combinedAPI: combined})
})
}
此外,请记住,每当您更新状态时,React 都会检测到状态更改并导致组件刷新。您当前正在一个循环中执行两个 setState 调用。我会考虑将你的 axios 结果构造成局部变量和 setState,一次,在循环之外。