Reactjs 当父组件使用不同的值注入道具时,子组件不触发渲染

Reactjs 当父组件使用不同的值注入道具时,子组件不触发渲染,reactjs,Reactjs,以下是我的组件: 应用程序组件: import logo from './logo.svg'; import {Component} from 'react'; import './App.css'; import {MonsterCardList} from './components/monster-list/monster-card-list.component' import {Search} from './components/search/search.component' c

以下是我的组件:

应用程序组件:

import logo from './logo.svg';
import {Component} from 'react';

import './App.css';
import {MonsterCardList} from './components/monster-list/monster-card-list.component'
import {Search} from './components/search/search.component'

class App extends Component
{
  
  constructor()
  {
    super();

    this.state = {searchText:""}
  }

  render()
  {
    console.log("repainting App component");
    return (
      <div className="App">
        <main>
          <h1 className="app-title">Monster List</h1>
          <Search callback={this._searchChanged}></Search>
          <MonsterCardList filter={this.state.searchText}></MonsterCardList>
        </main>
      </div>
    );
  }

  _searchChanged(newText)
  {
    console.log("Setting state. new text: "+newText);
    this.setState({searchText:newText}, () => console.log(this.state));
  }
}

export default App;
export class MonsterCardList extends Component
{
    constructor(props) 
    {
        super(props);
        this.state = {data:[]};
    }
    
    componentDidMount()
    {
        console.log("Component mounted");
        this._loadData();
    }

    _loadData(monsterCardCount)
    {
        fetch("https://jsonplaceholder.typicode.com/users", {
            method: 'GET',
           }).then( response =>{
            if(response.ok)
            {
                console.log(response.status);
                response.json().then(data => {
                    let convertedData = data.map( ( el, index) => {
                        return {url:`https://robohash.org/${index}.png?size=100x100`, name:el.name, email:el.email}
                    });
                    console.log(convertedData);
                    this.setState({data:convertedData});
                });
            }
            else
                console.log("Error: "+response.status+" -> "+response.statusText);
            /*let data = response.json().value;
            
            */
          }).catch(e => {
              console.log("Error: "+e);
          });
          
    }

    render() 
    {
        console.log("filter:" + this.props.filter);
        return (
            <div className="monster-card-list">
                {this.state.data.map((element,index) => {
                    if(!this.props.filter || element.email.includes(this.props.filter))
                        return <MonsterCard cardData={element} key={index}></MonsterCard>;
                })}
            </div>
        );
        
    }
}
import {Component} from "react"
import './monster-card.component.css'

export class MonsterCard extends Component
{
    constructor(props) 
    {
        super(props);
    }

    render() 
    {
        return (
            <div className="monster-card">
                <img className="monster-card-img" src={this.props.cardData.url}></img>
                <h3 className="monster-card-name">{this.props.cardData.name}</h3>
                <h3 className="monster-card-email">{this.props.cardData.email}</h3>
            </div> 
        );
    }
}
import {Component} from "react"

export class Search extends Component
{
    _searchChangedCallback = null;

    constructor(props)
    {
        super();
        this._searchChangedCallback = props.callback;
    }   
    
    render()
    {
        
        return (
            <input type="search" onChange={e=>this._searchChangedCallback(e.target.value)} placeholder="Search monsters"></input>
        );
    }
}
从“/logo.svg”导入徽标;
从“react”导入{Component};
导入“/App.css”;
从“./components/monster list/monster card list.component”导入{monster cardlist}
从“./components/Search/Search.component”导入{Search}
类应用程序扩展组件
{
构造函数()
{
超级();
this.state={searchText:}
}
render()
{
log(“重新绘制应用程序组件”);
返回(
怪物名单
);
}
_searchChanged(新文本)
{
console.log(“设置状态.新文本:“+newText”);
this.setState({searchText:newText},()=>console.log(this.state));
}
}
导出默认应用程序;
卡片列表组件:

import logo from './logo.svg';
import {Component} from 'react';

import './App.css';
import {MonsterCardList} from './components/monster-list/monster-card-list.component'
import {Search} from './components/search/search.component'

class App extends Component
{
  
  constructor()
  {
    super();

    this.state = {searchText:""}
  }

  render()
  {
    console.log("repainting App component");
    return (
      <div className="App">
        <main>
          <h1 className="app-title">Monster List</h1>
          <Search callback={this._searchChanged}></Search>
          <MonsterCardList filter={this.state.searchText}></MonsterCardList>
        </main>
      </div>
    );
  }

  _searchChanged(newText)
  {
    console.log("Setting state. new text: "+newText);
    this.setState({searchText:newText}, () => console.log(this.state));
  }
}

export default App;
export class MonsterCardList extends Component
{
    constructor(props) 
    {
        super(props);
        this.state = {data:[]};
    }
    
    componentDidMount()
    {
        console.log("Component mounted");
        this._loadData();
    }

    _loadData(monsterCardCount)
    {
        fetch("https://jsonplaceholder.typicode.com/users", {
            method: 'GET',
           }).then( response =>{
            if(response.ok)
            {
                console.log(response.status);
                response.json().then(data => {
                    let convertedData = data.map( ( el, index) => {
                        return {url:`https://robohash.org/${index}.png?size=100x100`, name:el.name, email:el.email}
                    });
                    console.log(convertedData);
                    this.setState({data:convertedData});
                });
            }
            else
                console.log("Error: "+response.status+" -> "+response.statusText);
            /*let data = response.json().value;
            
            */
          }).catch(e => {
              console.log("Error: "+e);
          });
          
    }

    render() 
    {
        console.log("filter:" + this.props.filter);
        return (
            <div className="monster-card-list">
                {this.state.data.map((element,index) => {
                    if(!this.props.filter || element.email.includes(this.props.filter))
                        return <MonsterCard cardData={element} key={index}></MonsterCard>;
                })}
            </div>
        );
        
    }
}
import {Component} from "react"
import './monster-card.component.css'

export class MonsterCard extends Component
{
    constructor(props) 
    {
        super(props);
    }

    render() 
    {
        return (
            <div className="monster-card">
                <img className="monster-card-img" src={this.props.cardData.url}></img>
                <h3 className="monster-card-name">{this.props.cardData.name}</h3>
                <h3 className="monster-card-email">{this.props.cardData.email}</h3>
            </div> 
        );
    }
}
import {Component} from "react"

export class Search extends Component
{
    _searchChangedCallback = null;

    constructor(props)
    {
        super();
        this._searchChangedCallback = props.callback;
    }   
    
    render()
    {
        
        return (
            <input type="search" onChange={e=>this._searchChangedCallback(e.target.value)} placeholder="Search monsters"></input>
        );
    }
}
导出类MonsterCardList扩展组件
{
建造师(道具)
{
超级(道具);
this.state={data:[]};
}
componentDidMount()
{
控制台日志(“组件安装”);
这是。_loadData();
}
_loadData(monsterCardCount)
{
取回(“https://jsonplaceholder.typicode.com/users", {
方法:“GET”,
})。然后(响应=>{
if(response.ok)
{
console.log(响应状态);
response.json().then(数据=>{
让convertedData=data.map((el,index)=>{
返回{url:`https://robohash.org/${index}.png?size=100x100`,名称:el.name,电子邮件:el.email}
});
console.log(convertedData);
this.setState({data:convertedData});
});
}
其他的
console.log(“错误:“+response.status+”->“+response.statusText”);
/*让data=response.json().value;
*/
}).catch(e=>{
控制台日志(“错误:+e”);
});
}
render()
{
log(“filter:+this.props.filter”);
返回(
{this.state.data.map((元素,索引)=>{
如果(!this.props.filter | | element.email.includes(this.props.filter))
返回;
})}
);
}
}
卡组件:

import logo from './logo.svg';
import {Component} from 'react';

import './App.css';
import {MonsterCardList} from './components/monster-list/monster-card-list.component'
import {Search} from './components/search/search.component'

class App extends Component
{
  
  constructor()
  {
    super();

    this.state = {searchText:""}
  }

  render()
  {
    console.log("repainting App component");
    return (
      <div className="App">
        <main>
          <h1 className="app-title">Monster List</h1>
          <Search callback={this._searchChanged}></Search>
          <MonsterCardList filter={this.state.searchText}></MonsterCardList>
        </main>
      </div>
    );
  }

  _searchChanged(newText)
  {
    console.log("Setting state. new text: "+newText);
    this.setState({searchText:newText}, () => console.log(this.state));
  }
}

export default App;
export class MonsterCardList extends Component
{
    constructor(props) 
    {
        super(props);
        this.state = {data:[]};
    }
    
    componentDidMount()
    {
        console.log("Component mounted");
        this._loadData();
    }

    _loadData(monsterCardCount)
    {
        fetch("https://jsonplaceholder.typicode.com/users", {
            method: 'GET',
           }).then( response =>{
            if(response.ok)
            {
                console.log(response.status);
                response.json().then(data => {
                    let convertedData = data.map( ( el, index) => {
                        return {url:`https://robohash.org/${index}.png?size=100x100`, name:el.name, email:el.email}
                    });
                    console.log(convertedData);
                    this.setState({data:convertedData});
                });
            }
            else
                console.log("Error: "+response.status+" -> "+response.statusText);
            /*let data = response.json().value;
            
            */
          }).catch(e => {
              console.log("Error: "+e);
          });
          
    }

    render() 
    {
        console.log("filter:" + this.props.filter);
        return (
            <div className="monster-card-list">
                {this.state.data.map((element,index) => {
                    if(!this.props.filter || element.email.includes(this.props.filter))
                        return <MonsterCard cardData={element} key={index}></MonsterCard>;
                })}
            </div>
        );
        
    }
}
import {Component} from "react"
import './monster-card.component.css'

export class MonsterCard extends Component
{
    constructor(props) 
    {
        super(props);
    }

    render() 
    {
        return (
            <div className="monster-card">
                <img className="monster-card-img" src={this.props.cardData.url}></img>
                <h3 className="monster-card-name">{this.props.cardData.name}</h3>
                <h3 className="monster-card-email">{this.props.cardData.email}</h3>
            </div> 
        );
    }
}
import {Component} from "react"

export class Search extends Component
{
    _searchChangedCallback = null;

    constructor(props)
    {
        super();
        this._searchChangedCallback = props.callback;
    }   
    
    render()
    {
        
        return (
            <input type="search" onChange={e=>this._searchChangedCallback(e.target.value)} placeholder="Search monsters"></input>
        );
    }
}
从“react”导入{Component}
导入“./monster card.component.css”
导出类扩展组件
{
建造师(道具)
{
超级(道具);
}
render()
{
返回(
{this.props.cardData.name}
{this.props.cardData.email}
);
}
}
搜索组件:

import logo from './logo.svg';
import {Component} from 'react';

import './App.css';
import {MonsterCardList} from './components/monster-list/monster-card-list.component'
import {Search} from './components/search/search.component'

class App extends Component
{
  
  constructor()
  {
    super();

    this.state = {searchText:""}
  }

  render()
  {
    console.log("repainting App component");
    return (
      <div className="App">
        <main>
          <h1 className="app-title">Monster List</h1>
          <Search callback={this._searchChanged}></Search>
          <MonsterCardList filter={this.state.searchText}></MonsterCardList>
        </main>
      </div>
    );
  }

  _searchChanged(newText)
  {
    console.log("Setting state. new text: "+newText);
    this.setState({searchText:newText}, () => console.log(this.state));
  }
}

export default App;
export class MonsterCardList extends Component
{
    constructor(props) 
    {
        super(props);
        this.state = {data:[]};
    }
    
    componentDidMount()
    {
        console.log("Component mounted");
        this._loadData();
    }

    _loadData(monsterCardCount)
    {
        fetch("https://jsonplaceholder.typicode.com/users", {
            method: 'GET',
           }).then( response =>{
            if(response.ok)
            {
                console.log(response.status);
                response.json().then(data => {
                    let convertedData = data.map( ( el, index) => {
                        return {url:`https://robohash.org/${index}.png?size=100x100`, name:el.name, email:el.email}
                    });
                    console.log(convertedData);
                    this.setState({data:convertedData});
                });
            }
            else
                console.log("Error: "+response.status+" -> "+response.statusText);
            /*let data = response.json().value;
            
            */
          }).catch(e => {
              console.log("Error: "+e);
          });
          
    }

    render() 
    {
        console.log("filter:" + this.props.filter);
        return (
            <div className="monster-card-list">
                {this.state.data.map((element,index) => {
                    if(!this.props.filter || element.email.includes(this.props.filter))
                        return <MonsterCard cardData={element} key={index}></MonsterCard>;
                })}
            </div>
        );
        
    }
}
import {Component} from "react"
import './monster-card.component.css'

export class MonsterCard extends Component
{
    constructor(props) 
    {
        super(props);
    }

    render() 
    {
        return (
            <div className="monster-card">
                <img className="monster-card-img" src={this.props.cardData.url}></img>
                <h3 className="monster-card-name">{this.props.cardData.name}</h3>
                <h3 className="monster-card-email">{this.props.cardData.email}</h3>
            </div> 
        );
    }
}
import {Component} from "react"

export class Search extends Component
{
    _searchChangedCallback = null;

    constructor(props)
    {
        super();
        this._searchChangedCallback = props.callback;
    }   
    
    render()
    {
        
        return (
            <input type="search" onChange={e=>this._searchChangedCallback(e.target.value)} placeholder="Search monsters"></input>
        );
    }
}
从“react”导入{Component}
导出类搜索扩展组件
{
_searchChangedCallback=null;
建造师(道具)
{
超级();
这.\u searchChangedCallback=props.callback;
}   
render()
{
返回(
这是.\u searchChangedCallback(e.target.value)}占位符=“搜索怪物”>
);
}
}

问题是,我看到输入中键入的文本如何正确地流向应用程序组件并调用回调,但是,当在“searchChanged”中更改状态时,MonsterCardList似乎不会重新呈现。

\u loadData
在下面的代码中首次装入组件时,只会调用一次

componentDidMount()
{
    console.log("Component mounted");
    this._loadData();
}
当您在
构造函数中设置状态时
意味着它也会设置
此.state.filter
一次。当
searchText
道具更改时,状态不会更改,因此不会重新播放

constructor(props) 
{
    super(props);
    this.state = {data:[], filter:this.props.searchText};
}
如果您需要在道具更改时重新播放,请使用
componentdiddupdate
lifecyclehook

componentDidUpdate(prevProps) 
{
  if (this.props.searchText !== prevProps.searchText) 
  {
    this._loadData();
  }
}

我看到您在
MonsterCardList
组件中使用了state
filter
filter:this.props.searchText
。但是您只在该组件中传递了一个prop
filter
filter={this.state.searchText}
)。因此,props
searchText
未定义


我看到您不需要使用state
过滤器
。用
this.props.filter

替换
this.state.filter
,<。这不是一个与react相关的问题,而是一个javascript问题,它与此相关,没有绑定到_searchChanged函数中的App类

我想我们在构造函数中这样绑定它:

this._searchChanged = this._searchChanged.bind(this); 
或者我们只使用和箭头功能:

_searchChanged = (newText) => 
{
    console.log("Setting state. new text: "+newText);
    this.setState({filter:newText}, () => console.log(this.state));
}

一切正常。

@不错,看看这个!!这不是我想要的。我不想每次组件更新时都触发loadData。我们的想法是这样做一次(这只是一个测试,从api检索的代码稍后不会出现在这个组件中)。因此,正如下面的用户所说,我已经更改了对渲染方法中道具的访问权限(谢谢!)。据我所知,当应用程序组件从搜索组件获取数据并执行设置状态时,这将触发moster卡列表渲染,该渲染将使用注入的新道具。但这不起作用。为什么?啊,是的,谢谢你。我经常玩代码,把那部分放在这里了。我已经编辑了这个问题来访问怪物卡列表中的道具,而不是状态。现在不是应该更新吗?因为从应用组件,状态被改变,并且注入了一个新的过滤器道具。但是仍然没有触发渲染方法。没有取消它。你不需要这样捆绑。可以使用箭头函数表示法自动将函数绑定到此上下文。