[英]Why doesn't this React component re-render when its prop changes?
[英]React: why child component doesn't update when prop changes
為什么在下面的偽代碼示例中,當 Container 更改 foo.bar 時,Child 不重新呈現?
Container {
handleEvent() {
this.props.foo.bar = 123
},
render() {
return <Child bar={this.props.foo.bar} />
}
Child {
render() {
return <div>{this.props.bar}</div>
}
}
即使我在修改 Container 中的值后調用forceUpdate()
,Child 仍然顯示舊值。
更新孩子的屬性“key”等於名稱。 每次密鑰更改時,組件都會重新渲染。
Child {
render() {
return <div key={this.props.bar}>{this.props.bar}</div>
}
}
因為如果父級的 props 發生變化,子級不會重新渲染,但是如果它的 STATE 發生變化:)
你展示的是這個: https : //facebook.github.io/react/tips/communicate-between-components.html
它將通過 props 將數據從父級傳遞給子級,但那里沒有重新渲染邏輯。
您需要為父級設置一些狀態,然后在父級更改狀態時重新渲染子級。 這可能會有所幫助。 https://facebook.github.io/react/tips/expose-component-functions.html
我有同樣的問題。 這是我的解決方案,我不確定這是好的做法,如果不是,請告訴我:
state = {
value: this.props.value
};
componentDidUpdate(prevProps) {
if(prevProps.value !== this.props.value) {
this.setState({value: this.props.value});
}
}
UPD:現在你可以使用 React Hooks 做同樣的事情:(僅當組件是一個函數時)
const [value, setValue] = useState(propName);
// This will launch only if propName value has chaged.
useEffect(() => { setValue(propName) }, [propName]);
確認,添加一個 Key 有效。 我瀏覽了文檔以嘗試了解原因。
React 希望在創建子組件時高效。 如果它與另一個子組件相同,則不會呈現新組件,這會使頁面加載速度更快。
添加一個 Key 會強制 React 渲染一個新組件,從而重置該新組件的 State。
https://reactjs.org/docs/reconciliation.html#recursing-on-children
當從functions
和useState
創建 React 組件時。
const [drawerState, setDrawerState] = useState(false);
const toggleDrawer = () => {
// attempting to trigger re-render
setDrawerState(!drawerState);
};
這不工作
<Drawer
drawerState={drawerState}
toggleDrawer={toggleDrawer}
/>
這確實有效(添加密鑰)
<Drawer
drawerState={drawerState}
key={drawerState}
toggleDrawer={toggleDrawer}
/>
根據 React 哲學,組件不能改變它的 props。 它們應該從父級接收並且應該是不可變的。 只有父級可以更改其子級的道具。
關於狀態與道具的很好解釋
另外,請閱讀此線程為什么我不能在 react.js 中更新道具?
您應該使用setState
函數。 如果沒有,無論您如何使用 forceUpdate,state 都不會保存您的更改。
Container {
handleEvent= () => { // use arrow function
//this.props.foo.bar = 123
//You should use setState to set value like this:
this.setState({foo: {bar: 123}});
};
render() {
return <Child bar={this.state.foo.bar} />
}
Child {
render() {
return <div>{this.props.bar}</div>
}
}
}
您的代碼似乎無效。 我無法測試此代碼。
在這個代碼片段中,我們多次渲染子組件並傳遞key 。
如果我們使用setState方法更改檢查。 在我們更改其key之前,它不會反映在 Child 組件中。 我們必須將其保存在 child 的 state 中,然后相應地更改它以呈現 child。
class Parent extends Component { state = { checked: true } render() { return ( <div className="parent"> { [1, 2, 3].map( n => <div key={n}> <Child isChecked={this.state.checked} /> </div> ) } </div> ); } }
使用 setState 函數。 所以你可以這樣做
this.setState({this.state.foo.bar:123})
在句柄事件方法中。
一旦狀態被更新,它就會觸發變化,並且會發生重新渲染。
如果 Child 不維護任何狀態並且只是渲染 props 然后從父級調用它,您可能應該將 Child 作為功能組件。 替代方法是您可以將鈎子與功能組件 (useState) 一起使用,這將導致無狀態組件重新渲染。
你也不應該改變 propas,因為它們是不可變的。 維護組件的狀態。
Child = ({bar}) => (bar);
export default function DataTable({ col, row }) {
const [datatable, setDatatable] = React.useState({});
useEffect(() => {
setDatatable({
columns: col,
rows: row,
});
/// do any thing else
}, [row]);
return (
<MDBDataTableV5
hover
entriesOptions={[5, 20, 25]}
entries={5}
pagesAmount={4}
data={datatable}
/>
);
}
此示例使用useEffect
在props
更改時更改狀態。
我的案例涉及在 props 對象上有多個屬性,並且需要在更改其中任何一個時重新渲染 Child。 上面提供的解決方案是有效的,但是為每一個添加一個密鑰,每個都變得乏味和骯臟(想象一下有 15 個......)。 如果有人面臨這個問題 - 您可能會發現將 props 對象字符串化很有用:
<Child
key={JSON.stringify(props)}
/>
這樣,props 上每個屬性的每次更改都會觸發 Child 組件的重新渲染。
希望對某人有所幫助。
我遇到了同樣的問題。 我有一個Tooltip
這是接收組件showTooltip
道具,我是更新有關Parent
基於一個組成部分if
條件下,它是在得到更新Parent
組成部分,但Tooltip
組件沒有渲染。
const Parent = () => {
let showTooltip = false;
if(....){ showTooltip = true; }
return(
<Tooltip showTooltip={showTooltip}></Tooltip>
)
}
我犯的錯誤是將showTooltip
聲明為 let 。
我意識到我做錯了什么,我違反了渲染工作原理,用鈎子代替它完成了這項工作。
const [showTooltip, setShowTooltip] = React.useState<boolean>(false);
在子組件的 connect 方法的 mapStateToProps 中定義更改的道具。
function mapStateToProps(state) {
return {
chanelList: state.messaging.chanelList,
};
}
export default connect(mapStateToProps)(ChannelItem);
就我而言,channelList 的頻道已更新,因此我在 mapStateToProps 中添加了 chanelList
就我而言,我正在更新傳遞給組件的loading
狀態。 在 Button 內, props.loading
按預期通過(從 false 切換到 true),但顯示微調器的三元沒有更新。
我嘗試添加一個鍵,添加一個使用 useEffect() 等更新的狀態,但其他答案都不起作用。
對我有用的是改變這個:
setLoading(true);
handleOtherCPUHeavyCode();
對此:
setLoading(true);
setTimeout(() => { handleOtherCPUHeavyCode() }, 1)
我認為這是因為handleOtherCPUHeavyCode
的進程非常繁重和密集,因此應用程序凍結了handleOtherCPUHeavyCode
一秒鍾。 添加 1ms 超時允許加載布爾值更新,然后繁重的代碼功能可以完成它的工作。
您可以使用componentWillReceiveProps
:
componentWillReceiveProps({bar}) {
this.setState({...this.state, bar})
}
一個相當古老的問題,但它是一個常青問題,如果只有錯誤的答案和解決方法,它也不會變得更好。 子對象沒有更新的原因不是缺少key或缺少狀態,原因是你沒有遵守不變性原則。
react 的目標是讓應用程序更快、更靈敏、更易於維護等等,但你必須遵循一些原則。 React 節點僅在必要時重新渲染,即如果它們已更新。 React 如何知道組件是否已更新? 因為狀態變了。 現在不要把它和 setState 鈎子混在一起。 狀態是一個概念,每個組件都有它的狀態。 狀態是組件在給定時間點的外觀或行為。 如果您有一個靜態組件,那么您始終只有一種狀態,而不必處理它。 如果組件必須以某種方式改變,它的狀態就會改變。
現在反應非常具有描述性。 組件的狀態可以從一些不斷變化的信息中導出,並且這些信息可以存儲在組件外部或內部。 如果信息存儲在內部,那么這是組件必須跟蹤自己的一些信息,我們通常使用像 setState 這樣的鈎子來管理這些信息。 如果此信息存儲在我們的組件之外,那么它就會存儲在不同的組件內,並且該組件必須跟蹤它,即它們的狀態。 現在另一個組件可以通過 props 將它們的狀態傳遞給我們。
這意味着如果我們自己的管理狀態發生變化或者通過 props 傳入的信息發生變化,則反應重新渲染。 這是自然行為,您不必將道具數據傳輸到您自己的狀態。 現在是非常重要的一點:當信息發生變化時,react 如何知道? 簡單:是進行比較! 每當你設置一些狀態或給 react 一些它必須考慮的信息時,它會將新給出的信息與實際存儲的信息進行比較,如果它們不相同,react 將重新呈現該信息的所有依賴項。 在這方面不一樣意味着 javascript === 運算符。 也許你已經明白了。 讓我們看看這個:
let a = 42; let b = a; console.log('is a the same as b?',a === b); // a and b are the same, right? --> true a += 5; // now let's change a console.log('is a still the same as b?',a === b); // --> false
我們正在創建一個值的實例,然后創建另一個實例,將第一個實例的值分配給第二個實例,然后更改第一個實例。 現在讓我們看一下對象的相同流程:
let a = { num: 42}; let b = a; console.log('is a the same as b?',a === b); // a and b are the same, right? --> true a.num += 5; // now let's change a console.log('is a still the same as b?',a === b); // --> true
this.props.foo.bar = 123
實際上更新了“this”指向的內存中的一個值。 React 無法通過比較對象引用來識別此類更改。 您可以更改對象的內容一千次,並且引用將始終保持不變,並且 react 不會重新渲染依賴組件。 這就是為什么您必須將 react 中的所有變量視為不可變的。 要進行可檢測的更改,您需要一個不同的參考,並且您只能通過新對象獲得它。 因此,您不必更改您的對象,而是將其復制到一個新對象,然后您可以在將其移交以做出反應之前更改其中的某些值。 看:
let a = {num: 42}; console.log('a looks like', a); let b = {...a}; console.log('b looks like', b); console.log('is a the same as b?', a === b); // --> false
如果您遵守不變性,所有子節點都會使用新的道具數據更新。
如果道具是對象JSON.stringify(obj)
並將其設置為功能組件的key
,我有同樣的問題重新渲染對象道具。 只為反應key
設置一個id
對我不起作用。 奇怪的是,要更新組件,您必須在key
上包含所有對象屬性並將其連接起來。
function Child(props) {
const [thing, setThing] = useState(props.something)
return (
<>
<div>{thing.a}</div>
<div>{thing.b}</div>
</>
)
}
...
function Caller() {
const thing = [{a: 1, b: 2}, {a: 3, b: 4}]
thing.map(t => (
<Child key={JSON.stringify(t)} something={thing} />
))
}
現在,只要thing
對象在運行時更改它的值, Child
組件就會正確地重新渲染它。
考慮到涉及 props 的渲染限制和我們對狀態的好處,如果你使用反應鈎子,你可以使用一些技巧。 例如,您可以使用 useEffect 手動將道具轉換為狀態。 它可能不應該是最佳實踐,但在這些情況下它會有所幫助。
import { isEqual } from 'lodash';
import { useEffect, useState } from 'react';
export const MyComponent = (props: { users: [] }) => {
const [usersState, setUsersState] = useState([]);
useEffect(() => {
if (!isEqual(props.users, usersState)) {
setUsersState(props.users);
}
}, [props.users]);
<OtherComponent users={usersState} />;
};
安裝包 npm install react-native-uuid 或 yarn add react-native-uuid
從'react-native-uuid'導入導入uuid;
將此方法用於子級的 uuid 將解決重新渲染問題 uuid.v4();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.