为什么在以下伪代码示例中,当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仍会显示旧值。
答案 0 :(得分:51)
因为如果父级的道具发生变化,孩子不会重新渲染,但如果其状态发生变化,则不会重新渲染:)
你所展示的是: https://facebook.github.io/react/tips/communicate-between-components.html
它会通过道具将数据从父级传递给子级,但那里没有重新登记逻辑。
您需要将一些状态设置为父级,然后在父级更改状态下重新呈现子级。 这可能有所帮助。 https://facebook.github.io/react/tips/expose-component-functions.html
答案 1 :(得分:12)
更新子项以使属性“key”等于name:
Child {
render() {
return <div key={this.props.bar}>{this.props.bar}</div>
}
}
答案 2 :(得分:10)
从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}
/>
答案 3 :(得分:8)
根据React哲学组件无法改变其道具。它们应该从父母那里收到,并且应该是不可改变的。只有父母可以改变其子女的道具。
的好解释答案 4 :(得分:6)
您应该使用setState
功能。如果没有,状态将不会保存您的更改,无论您如何使用forceUpdate。
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>
}
}
}
您的代码似乎无效。我无法测试此代码。
答案 5 :(得分:3)
使用setState函数。 所以你可以做到
this.setState({this.state.foo.bar:123})
在handle事件方法中。
一旦状态更新,它将触发更改,并将重新渲染。
答案 6 :(得分:2)
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
更改状态。
答案 7 :(得分:1)
我有同样的问题。 这是我的解决方案,我不确定这是否是个好习惯,如果不能,请告诉我:
state = {
value: this.props.value
};
componentDidUpdate(prevProps) {
if(prevProps.value !== this.props.value) {
this.setState({value: this.props.value});
}
}
UPD:现在,您可以使用React Hooks做同样的事情: (仅当component是一个函数时)
const [value, setValue] = useState(propName);
// This will launch only if propName value has chaged.
useEffect(() => { setValue(propName) }, [propName]);
答案 8 :(得分:1)
确认,添加密钥即可。我浏览了文档以尝试并理解原因。
React希望在创建子组件时高效。如果它与另一个子组件相同,它将不会呈现新组件,这会使页面加载更快。
添加键会强制React渲染新组件,从而重置该新组件的状态。
https://reactjs.org/docs/reconciliation.html#recursing-on-children
答案 9 :(得分:0)
安装包 npm install react-native-uuid 要么 纱线添加 react-native-uuid
导入 从'react-native-uuid'导入uuid;
使用此方法为孩子的 uuid 将解决重新渲染问题 uuid.v4();
答案 10 :(得分:0)
您可以使用componentWillReceiveProps
:
componentWillReceiveProps({bar}) {
this.setState({...this.state, bar})
}
答案 11 :(得分:0)
在此代码片段中,我们多次渲染子组件并传递key。
如果我们使用 setState 方法更改 checked。在我们更改其键之前,它不会反映在子组件中。我们必须将其保存在 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>
);
}
}
答案 12 :(得分:0)
我的案例涉及在 props 对象上有多个属性,并且需要在更改其中任何一个时重新渲染 Child。 上面提供的解决方案是有效的,但是为每个解决方案添加一个密钥变得乏味和肮脏(想象一下有 15 个......)。如果有人遇到这种情况 - 您可能会发现将 props 对象字符串化很有用:
<Child
key={JSON.stringify(props)}
/>
这样,props 上每个属性的每次更改都会触发 Child 组件的重新渲染。
希望对某人有所帮助。
答案 13 :(得分:0)
就我而言,我正在更新一个loading
状态,该状态已传递给组件。在按钮内,props.loading
正按预期进行(从false切换为true),但是显示微调框的三元组并没有更新。
我尝试添加密钥,添加使用useEffect()等更新的状态,但其他答案均无效。
对我有用的是改变这一点:
setLoading(true);
handleOtherCPUHeavyCode();
对此:
setLoading(true);
setTimeout(() => { handleOtherCPUHeavyCode() }, 1)
我认为是因为handleOtherCPUHeavyCode
中的过程非常繁琐,因此应用程序冻结了大约一秒钟。添加1ms超时可以使加载布尔值更新,然后然后使用繁重的代码功能即可完成工作。
答案 14 :(得分:0)
在子组件的connect方法的mapStateToProps中定义更改的道具。
function mapStateToProps(state) {
return {
chanelList: state.messaging.chanelList,
};
}
export default connect(mapStateToProps)(ChannelItem);
在我的情况下,channelList的频道已更新,因此我在mapStateToProps中添加了chanelList
答案 15 :(得分:0)
我遇到了同样的问题。
我有一个$template_html = '';
$template_txt = '';
$id_lang = $this->context->cart->id_lang;
$iso = $this->context->language->iso_code;
$iso_template = $iso.'/quotes_notify';
// $template_path = $theme_path.'modules/'.$module_name.'/mails/';
$template_path = PS_MODULE_DIR_ . $this->module->name . '/mails/';
Hook::exec('actionEmailAddBeforeContent', array(
'template' => quotes_notify,
'template_html' => &$template_html,
'template_txt' => &$template_txt,
'id_lang' => 1
), null, true);
$template_html .= Tools::file_get_contents($template_path.$iso_template.'.html');
print_r($template_html);
die();
组件正在接收Tooltip
道具,我正在根据showTooltip
条件在Parent
组件上进行更新,该组件正在if
中进行更新组件,但Parent
组件未呈现。
Tooltip
我做的错误是将const Parent = () => {
let showTooltip = false;
if(....){ showTooltip = true; }
return(
<Tooltip showTooltip={showTooltip}></Tooltip>
)
}
声明为let。
我意识到我做错了我违反了渲染工作原理的工作,用钩子代替了工作。
showTooltip
答案 16 :(得分:0)
如果不保持任何状态而只是渲染道具然后从父级调用它,则应该使Child作为功能组件。替代方法是,可以将钩子与功能组件(useState)一起使用,这将导致无状态组件重新呈现。
此外,您不应更改道具,因为它们是不可变的。维护组件的状态。
Child = ({bar}) => (bar);