我有一个类组件,该组件使用两个上下文,这些上下文具有从对REST API的API调用中生成的值。
我要做的是获取上下文值,并使用它们来更新我的组件状态。
我正在传递上下文值
<TextContext.Consumer>
{(textContext) => (
<UserContext.Consumer>
{(userConsumer) => {
const text = textContext.text;
const user = userConsumer.user;
if(text != null && user != null){
return (
<div className="md:flex max-w-2xl">
<div className="flex flex-col flex-1 md:pr-32">
<FuseAnimateGroup
enter={{
animation: "transition.slideUpBigIn"
}}
>
<div style={{paddingRight:"8px"}}>
<Typography variant="h4" >{text.TITLE_PAGE_PROFILE}</Typography>
<TextField
id="outlined-full-width"
style={{ margin: 8 }}
placeholder={text.PROFILE_EMAIL_PLACEHOLDER}
value = {user.email}
disabled
fullWidth
margin="normal"
variant="outlined"
InputProps={{
endAdornment: (
<InputAdornment>
<IconButton>
<EmailIcon/>
</IconButton>
</InputAdornment>
)
}}
/>
</div>
<div style={{paddingRight:"8px"}}>
<form className={classes.container} noValidate autoComplete="off">
<TextField
id="outlined-full-width"
style={{ margin: 8 }}
placeholder={text.PROFILE_NAME}
value={user.name_user}
fullWidth
margin="normal"
variant="outlined"
InputProps={{
endAdornment: (
<InputAdornment position="start">
<AccountCircle />
</InputAdornment>
)
}}
/>
</form>
</div>
<div style={{paddingRight:"8px"}}>
<TextField
id="outlined-full-width"
style={{ margin: 8 }}
value={user.address_user}
placeholder={text.PROFILE_ADDRESS_PLACEHOLDER}
fullWidth
margin="normal"
variant="outlined"
InputLabelProps={{
shrink: true,
}}
/>
</div>
<div style={{paddingRight:"8px"}}>
<form className={classes.container} noValidate autoComplete="off">
<TextField
id="outlined-full-width"
style={{ margin: 8 }}
value={user.city_user}
label={text.PROFILE_CITY_PLACEHOLDER}
className={classes.textField}
fullWidth
margin="normal"
variant="outlined"
InputProps={{
endAdornment: (
<InputAdornment position="start">
<LocationCityIcon/>
</InputAdornment>
)
}}
/>
</form>
</div>
<div>
<TextField
id="outlined-select-currency"
select
value={user.country_user}
label={text.PROFILE_COUNTRY_PLACEHOLDER}
InputProps={{
endAdornment: (
<InputAdornment>
<IconButton>
<FlagIcon/>
</IconButton>
</InputAdornment>
)
}}
fullWidth
style={{ margin: 8, paddingRight: 8}}
SelectProps={{
MenuProps: {
className: classes.menu,
},
}}
margin="normal"
variant="outlined"
/>
</div>
<div style={{padding:"10px"}}>
<Fab variant="contained" aria-label="delete" className={classes.fab}>
{text.PROFILE_CHANGE_PASSWORD_BUTTON_PLACEHOLDER}
</Fab>
</div>
<div style={{paddingRight:"8px"}}>
<Typography variant="h4" > {text.COMPANY_INFORMATION_TITLE}</Typography>
<TextField
id="outlined-full-width"
style={{ margin: 8 }}
placeholder={text.COMPANY_NAME_PLACEHOLDER}
value={user.name_company}
fullWidth
margin="normal"
variant="outlined"
InputLabelProps={{
shrink: true,
}}
/>
</div>
<div style={{paddingLeft:"10px"}}>
<form className={classes.container} noValidate autoComplete="off">
<TextField
style={divStyle}
id="outlined"
label={text.COMPANY_EU_VAT_PLACEHOLDER}
value={user.vat_company}
className={classes.textField}
margin="normal"
variant="outlined"
/>
<TextField
style={div2Style}
id="outlined"
label={text.COMPANY_NUMBER_PLACEHOLDER}
value={user.registration_number_company}
className={classes.textField}
margin="normal"
variant="outlined"
/>
</form>
</div>
<div style={{paddingRight:"8px"}}>
<TextField
id="outlined-full-width"
style={{ margin: 8 }}
value={user.address_company}
placeholder={text.COMPANY_ADDRESS_PLACEHOLDER}
fullWidth
margin="normal"
variant="outlined"
InputLabelProps={{
shrink: true,
}}
/>
</div>
<div style={{paddingRight:"8px"}}>
<form className={classes.container} noValidate autoComplete="off">
<TextField
id="outlined-full-width"
style={{ margin: 8 }}
label={text.COMPANY_CITY_PLACEHOLDER}
value={user.city_company}
className={classes.textField}
fullWidth
margin="normal"
variant="outlined"
InputProps={{
endAdornment: (
<InputAdornment position="start">
<LocationCityIcon/>
</InputAdornment>
)
}}
/>
</form>
</div>
<div>
<TextField
id="outlined-select-currency"
select
label={text.COMPANY_COUNTRY_PLACEHOLDER}
fullWidth
style={{ margin: 8, paddingRight: 8}}
SelectProps={{
MenuProps: {
className: classes.menu,
},
}}
InputProps={{
endAdornment: (
<InputAdornment>
<IconButton>
<FlagIcon/>
</IconButton>
</InputAdornment>
)
}}
margin="normal"
variant="outlined"
/>
</div>
</FuseAnimateGroup>
</div>
<div className="flex flex-col md:w-320">
<FuseAnimateGroup
enter={{
animation: "transition.slideUpBigIn"
}}
>
<Button variant="contained" size="large" color="default" className={classes.button}>
{text.UPDATE_BUTTON_TEXT}
</Button>
</FuseAnimateGroup>
</div>
</div>
);
} else return <div>Loading...</div>
}
}
</UserContext.Consumer>
)}
</TextContext.Consumer>
我已经尝试通过执行以下操作来更新渲染器内的状态
<TextContext.Consumer>
{(textContext) => (
<UserContext.Consumer>
{(userConsumer) => {
const text = textContext.text;
const user = userConsumer.user;
this.setState({
user:user,
text: text,
})
</UserContext.Consumer>
)}
</TextContext.Consumer>
此方法的问题在于,它引发“超出最大更新深度”。错误。
我应该怎么做?
答案 0 :(得分:1)
“超出最大更新深度。”错误。
请勿setState()
内render()
。
我应该怎么做?
const User = (props) => {
return (
<>
<span>{props.user}</span>
<span>{props.text}</span>
</>
);
}
// in render
<TextContext.Consumer>
{(textContext) => (
<UserContext.Consumer>
{(userConsumer) => (
<User
text={textContext.text}
user={userConsumer.user}
/>
))}
</UserContext.Consumer>
)}
</TextContext.Consumer>
<User />
仍然会在道具(用户,文字)每次更改时重新呈现。
答案 1 :(得分:0)
您无法更新渲染功能中的状态。
就像那样,您将处于渲染的无限循环中。每当您更改触发渲染功能的状态时,便会再次更改状态,依此类推。
无论如何,您不需要将该状态存储在本地状态中即可使用它,您可以直接从上下文中使用它。
答案 2 :(得分:0)
首先-您确定您确实需要在状态中存储上下文吗?我看不出有任何理由将上下文(始终可用)复制到状态。只是使用上下文中的值,而不是状态中的值。
但是,如果您确实需要它,则无法在render函数中更新状态,因为它将导致无限的更新循环。有一些方法可以这样做:
return (
<TextContext.Consumer>
{({ text }) => (
<UserContext.Consumer>
({user}) => <ExtractedComponent text={text} user={user} />
</UserContext.Consumer>
)}
</TextContext.Consumer>
);
然后,您只需要为getDerrivedStateFromProps()
覆盖ExtractedComponent
,就可以在道具更改时获得新状态。
if (state.user !== user || state.text !== text) {
this.setState({ user, text });
}
const YourComponent = () => {
const { user } = useContext(UserContext);
const { text } = useContext(TextContext);
const [ state, setState ] = useState({});
useEffect(() => {
setState({ user, text });
}, [ user, text ]);
}