在反应中更改状态时组件不会重新渲染

Posted

技术标签:

【中文标题】在反应中更改状态时组件不会重新渲染【英文标题】:Component is not re rendering when state is changed in react 【发布时间】:2021-11-07 13:35:27 【问题描述】:

我现在连续 2 天面临这个错误,我无法修复它!!!所以,我正在使用https://www.weatherapi.com/这个api创建一个天气应用程序,我使用了引导程序中的导航栏,我可以使用这个搜索选项,所以如果用户搜索特定状态,它将显示来自该状态的数据,当我使用不同的组件来保持App.js 的清洁时,我已经在App.js 中声明了一个状态,我可以通过Navbar.js 中的按钮进行更新,该按钮将作为道具传递给Display.js(显示数据),但是当我进入一个状态并点击提交时,页面重新加载(我认为)它只是回到我用作虚拟对象的原始状态。它不会使用新数据重新渲染 Display.js。我尝试通过在浏览器上使用它来检查它并返回响应。 这是代码。 应用.js

import React,useState from 'react';
import Navbar from './Navbar.js';
import Display from './Display.js'
function App() 
  const[placeName,setPlaceName] = useState('Raipur')
  let key = 'not gonna tell';

  return (
   <>
   <Navbar setPlaceName=setPlaceName />
   <Display key=key placeName=placeName />
   </>
  );


export default App;

Navbar.js

import React from 'react';

function Navbar(props) 
  return(
   <>
    <nav className="navbar navbar-expand-lg navbar-dark bg-dark">
  <div className="container-fluid">
    <a className="navbar-brand" href="/">Navbar</a>
    <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="/navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span className="navbar-toggler-icon"></span>
    </button>
    <div className="collapse navbar-collapse" id="navbarSupportedContent">
      <ul className="navbar-nav me-auto mb-2 mb-lg-0">
        <li className="nav-item">
          <a className="nav-link active" aria-current="page" href="/">Home</a>
        </li>
        <li className="nav-item">
          <a className="nav-link" href="/">Link</a>
        </li>
        <li className="nav-item dropdown">
          <a className="nav-link dropdown-toggle" href="/" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Dropdown
          </a>
          <ul className="dropdown-menu" aria-labelledby="navbarDropdown">
            <li><a className="dropdown-item" href="/">Action</a></li>
            <li><a className="dropdown-item" href="/">Another action</a></li>
            <li><hr className="dropdown-divider"/></li>
            <li><a className="dropdown-item" href="/">Something else here</a></li>
          </ul>
        </li>
        <li className="nav-item">
          <a className="nav-link disabled">Disabled</a>
        </li>
      </ul>
      <form className="d-flex">
        <input className="form-control me-2" type="search" placeholder="Search" aria-label="Search"/>
        <button onClick=props.setPlaceName className="btn btn-outline-success" type="submit">Search</button>
      </form>
    </div>
  </div>
</nav>
   </>
  );


export default Navbar;

显示.js

import React,useState,useEffect from 'react';

function Display(props) 
  
  const[weatherInfo,setWeatherInfo] = useState([]);
  
  const getWeatherInfo = async () =>
    let url =`https://api.weatherapi.com/v1/current.json?key=$props.key&q=$props.placeName&aqi=no`;
    let weatherInfo = await fetch(url);
    let parsedweatherInfo = await weatherInfo.json();
    setWeatherInfo(parsedweatherInfo.location);
  
  // eslint-disable-next-line
  useEffect(async () =>
    getWeatherInfo();
  ,[])
  return (
    <>
    <div className="container">
    <div className="row"> 
    Object.values(weatherInfo).map((key,value)=>
    return(
     <div className="col" key=key>
     key 
     </div>
    )  
    ) 
    </div>
    </div>
    </>
  )


export default Display;

示例响应


    "location": 
        "name": "London",
        "region": "City of London, Greater London",
        "country": "United Kingdom",
        "lat": 51.52,
        "lon": -0.11,
        "tz_id": "Europe/London",
        "localtime_epoch": 1631360600,
        "localtime": "2021-09-11 12:43"
    ,
    "current": 
        "last_updated_epoch": 1631359800,
        "last_updated": "2021-09-11 12:30",
        "temp_c": 21.0,
        "temp_f": 69.8,
        "is_day": 1,
        "condition": 
            "text": "Partly cloudy",
            "icon": "//cdn.weatherapi.com/weather/64x64/day/116.png",
            "code": 1003
        ,
        "wind_mph": 11.9,
        "wind_kph": 19.1,
        "wind_degree": 250,
        "wind_dir": "WSW",
        "pressure_mb": 1017.0,
        "pressure_in": 30.03,
        "precip_mm": 0.0,
        "precip_in": 0.0,
        "humidity": 64,
        "cloud": 50,
        "feelslike_c": 21.0,
        "feelslike_f": 69.8,
        "vis_km": 10.0,
        "vis_miles": 6.0,
        "uv": 5.0,
        "gust_mph": 10.5,
        "gust_kph": 16.9
    

希望你能帮忙:)

【问题讨论】:

请提供一个最小的示例,以便更容易发现确切的问题 【参考方案1】:

当用户点击按钮时,您实际上并没有更新状态。

button onClick=props.setPlaceName

应该是这样的

button onClick=() => props.setPlaceName("Hello world")

【讨论】:

【参考方案2】:

您的代码的相关部分在Navbar 组件中:您没有向setter 函数提供新的placeName

因此,例如,您的 Navbar 组件应该看起来像这样:

function Navbar(props) 
  // This state stores the updated input value
  const [inputPlaceName, setInputPlaceName] = useState('');

  // This function provides `setPlaceName` with the input value
  function setGlobalPlaceName() 
    props.setPlaceName(inputPlaceName);
  

  return (
    <form>
      <input type="search" onChange=setInputPlaceName />
      <button onClick=setGlobalPlaceName type="submit">
        Search
      </button>
    </form>
  );

然后,尝试订阅Display 组件以更新props.placeName。这是通过将其添加到其useEffect 的依赖项数组中来完成的:

useEffect(getWeatherInfo, [props.placeName])

【讨论】:

它仍然不起作用,它会重新加载并返回默认值 什么意思?当 placeName 更新时,它会重新渲染 Display,但没有此更新的可视化表示 - 仅更新 getWeatherInfo 函数 我想我明白你的意思了。我已经编辑了我的答案 Idk whh 但我尝试了你所说的一切但它仍然不起作用【参考方案3】:

工作应用https://codesandbox.io/s/jovial-pascal-kww85?file=/src/App.js

注意:

    Prop 名称不能作为 key,因为这个名字是为唯一标识组件而保留的。(我使用 apikey 作为名字)
    <Display  apikey=key placeName=placeName />
    
    在导航栏中,您必须使用另一种状态来跟踪文本框中的输入。
    const  [input, setInput] =  useState("");
    
    在导航栏中应该是 onClick=() => props.setPlaceName(input)
    value=input
    onChange=(e) =>  setInput(e.target.value)
    
    提交上的表单元素阻止默认不刷新页面。
    <form  className="d-flex"  onSubmit=(e) =>  e.preventDefault()>
    
    当 props.placename 更改时,在 Display 中调用 useEffect。
    useEffect(async  ()  =>  
    
    getWeatherInfo();
    
    ,  [props.placeName]);
    

【讨论】:

没什么用 ;~; ,我什至尝试过你的工作应用程序,但是当我按下搜索时它只是重新加载并返回到默认值 有人改了 我改成原版了,请检查 你是个传奇,谢谢 :D

以上是关于在反应中更改状态时组件不会重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

使用 Lodash.remove 通过 Vuex 突变更改状态不会触发我的 Vue 组件中的反应式重新渲染

state 用作组件中的 props,状态更改不会重新渲染组件

React 子组件不会在其状态更改时重新渲染

高阶组件状态正在正确更新,但接收道具的包装组件不会在状态更改时重新渲染

即使调用了渲染函数中的 console.log,组件也不会在状态更改时重新渲染

将新的商店状态放入道具后,反应不会重新渲染