#reactjs #use-state
#reactjs #use-state
Вопрос:
Я использовал хук useState() во всем моем проекте для управления формами. Он всегда работал так, как задумано. Однако в компоненте RoleEditCard я вообще не смог использовать хук useState.
Если я сделаю это:
const [roleName, setRoleName] = useState(props.roleInfo.role_name);
console.log(roleName, props.roleInfo.role_name);
Я получаю следующее в консоли:
undefined New Role
С «Новой ролью», являющейся ожидаемым значением обеих переменных. В чем проблема?
Мой полный код (здесь использовались только reactjs и react-bootstrap):
// Here, we handle the form for adding new role.
// Package imports
import React, { useState } from 'react';
// import { Multiselect } from 'multiselect-react-dropdown';
// React Bootstrap components import
import Container from 'react-bootstrap/Container';
import Accordion from 'react-bootstrap/Accordion';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Card from 'react-bootstrap/Card';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import { FaTimes, FaCheck } from 'react-icons/fa';
// CSS Module imports
import classes from './RoleEditCard.module.css';
const RoleEditCard = (props) => {
// State handling
const [roleName, setRoleName] = useState(props.roleInfo.role_name);
const [roleDescription, setRoleDescription] = useState(props.roleInfo.role_description);
const [rolePrivileges, setRolePrivileges] = useState([...props.privilegeInfo]);
const [roleInfo, setRoleInfo] = useState({...props.roleInfo});
console.log(roleInfo, props.roleInfo);
// Handle submission of form
const submitHandler = event => {
if (roleName !== props.role.role_name || roleDescription !== props.role.role_description || JSON.stringify(rolePrivileges) !== JSON.stringify(props.role.role_privileges)) {
// Send details to container
props.onSubmission({
roleName: roleName,
roleDescription: roleDescription,
rolePrivileges: rolePrivileges.map(optionObject => optionObject.sub_menu_name)
});
} else {
console.log("NO CHANGES!");
}
// Prevent page reload
event.preventDefault();
}
const resetHandler = event => {
setRoleName("");
setRoleDescription("");
setRolePrivileges([]);
// Prevent page reload
event.preventDefault();
}
return (
<Container className={classes.PageContents}>
<Row>
<Col sm={{ span: '8', offset: '2' }}>
<Card className={classes.editCard}>
<Card.Body>
<Form onSubmit={submitHandler}>
<Form.Row className='text-left'>
<Form.Group as={Col} controlId="formRoleName" md='6'>
<Form.Label>Role Name:</Form.Label>
<Form.Control
placeholder="Role Name"
value={roleInfo.role_name}
required
onChange={event => { setRoleInfo({ ...roleInfo, role_name: event.target.value })}}
/>
</Form.Group>
</Form.Row>
<Form.Row className='text-left'>
<Form.Group as={Col} controlId="formRoleDescription" md='12'>
<Form.Label>Description:</Form.Label>
<Form.Control
type='textarea'
placeholder="Describe the Role"
value={roleDescription}
required
onChange={event => { setRoleDescription(event.target.value) }}
/>
</Form.Group>
</Form.Row>
{/* Privilege Selection */}
<Form.Row className='text-left'>
<Form.Group as={Col} controlId='formPrivilege'>
<Form.Label>Select Privileges</Form.Label>
<Accordion defaultActiveKey="0">
{props.privileges.map((mainmenu, index) => (
<Card key={mainmenu.id}>
<Card.Header>
<Row>
<Accordion.Toggle as={Col} variant="link" eventKey={mainmenu.id}>
{mainmenu.main_menu_name}
</Accordion.Toggle>
</Row>
</Card.Header>
{ mainmenu.Sub_Menus.length ? (
<Accordion.Collapse eventKey={mainmenu.id}>
<Card.Body>
{mainmenu.Sub_Menus.map(submenu => (
<Form.Check
type='checkbox'
value={submenu.sub_menu_name}
key={submenu.sub_menu_name}
defaultChecked={props.originalPrivileges.indexOf(submenu.sub_menu_name) !== -1}
onClick={event => {
const curVal = event.target.value;
const privList = JSON.parse(JSON.stringify(rolePrivileges));
if (privList.indexOf(curVal) !== -1) {
privList.splice(privList.indexOf(curVal), 1);
} else {
privList.push(curVal);
}
setRolePrivileges(privList);
}}
label={submenu.sub_menu_name}
/>
))}
</Card.Body>
</Accordion.Collapse>
) : null}
</Card>
))}
</Accordion>
</Form.Group>
</Form.Row>
<Form.Row className='justify-content-md-center'>
<Col md='auto'>
<Button variant="primary" type="submit" className={classes.FormButton}>
<FaCheck color='white' height='24' /> Submit
</Button>
</Col>
<Col md='auto'></Col>
<Col md='auto'>
<Button variant="danger" type="button" className={classes.FormButton} onClick={resetHandler}>
<FaTimes color='white' height='24' /> Reset
</Button>
</Col>
</Form.Row>
</Form>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
)
}
export default RoleEditCard
Вот как я вызвал RoleEditCard:
<RoleEditCard
onSubmission={this.submitHandler}
roleInfo={this.state.roleDetails}
privilegeInfo={this.state.privilegeDetails}
originalPrivileges={this.state.originalPrivileges}
privileges={this.state.records}
/>
Примечание: roleDetails, privilegeDetails и т. Д. были определены в componentDidMount() компонента класса.
Кроме того, я также использовал аналогичный код useState в UserEditCard:
// Package import
import React, { useState } from 'react';
// Bootstrap Components
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Card from 'react-bootstrap/Card';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import { FaTimes, FaCheck } from 'react-icons/fa';
// CSS Modules
import classes from './UserEditCard.module.css';
const UserEditCard = (props) => {
const [fullName, setFullName] = useState(props.UserInfo.full_name);
const [phoneNumber, setPhoneNumber] = useState(props.UserInfo.phone_number);
const [status, setStatus] = useState(props.UserInfo.status);
const submitHandler = event => {
//this.onSubmission
if (fullName !== props.UserInfo.full_name || phoneNumber !== props.UserInfo.phone_number || status !== props.UserInfo.status) {
props.onSubmission({
fullName: fullName,
phoneNumber: phoneNumber,
status: status
});
} else {
console.log("NO CHANGE!");
}
event.preventDefault();
}
const resetHandler = event => {
setFullName(props.UserInfo.full_name);
setPhoneNumber(props.UserInfo.phone_number);
setStatus(props.UserInfo.status);
// Prevent page reload
event.preventDefault();
}
return (
<Container className={classes.PageContents}>
<Row>
<Col sm={{ span: '8', offset: '2' }}>
<Card className={classes.editCard}>
<Card.Body>
<Form onSubmit={submitHandler}>
<Form.Row className='text-left'>
<Form.Group as={Col} controlId="formFullName" md='6'>
<Form.Label>Full Name:</Form.Label>
<Form.Control
value={fullName}
placeholder="Full Name"
required
onChange={event => {
setFullName(event.target.value);
}}
/>
</Form.Group>
</Form.Row>
<Form.Row className='text-left'>
<Form.Group as={Col} controlId="formEmailId" md='6'>
<Form.Label>Email Address:</Form.Label>
<Form.Control
value={props.UserInfo.email_id}
disabled
/>
</Form.Group>
<Form.Group as={Col} controlId="formPhoneNumber" md='6'>
<Form.Label>Phone Number:</Form.Label>
<Form.Control
placeholder="1234567890"
value={phoneNumber}
required
// May start with plus; cannot end with whitespace; maximum length of 20 characters
pattern='^(?= ?d ( ?d )*$).{1,20}$'
onChange={event => {
setPhoneNumber(event.target.value);
}}
/>
</Form.Group>
</Form.Row>
<Form.Row className='text-left'>
<Form.Group as={Col} controlId="formRoleSelect">
<Form.Label>Role</Form.Label>
<Form.Control
as="select"
value={props.UserInfo.role_name}
disabled
>
<option value={props.UserInfo.role_name}>{props.UserInfo.role_name}</option>
{/* Company List */}
{/* {props.roleOptions.map(role => <option value={role} key={role}>{role}</option>)} */}
</Form.Control>
</Form.Group>
<Form.Group as={Col}>
<Form.Label>Status</Form.Label>
<Form.Control
as="select"
value={status}
onChange={event => {
setStatus(event.target.value);
}}
required
>
<option value='Active'>Active</option>
<option value='Inactive'>Inactive</option>
<option value='Deleted'>Deleted</option>
</Form.Control>
</Form.Group>
</Form.Row>
<Form.Row className='justify-content-md-center'>
<Col md='auto'>
<Button variant="primary" type="submit" className={classes.FormButton}>
<FaCheck color='white' height='24' /> Submit
</Button>
</Col>
<Col md='auto'></Col>
<Col md='auto'>
<Button variant="danger" type="button" className={classes.FormButton} onClick={resetHandler}>
<FaTimes color='white' height='24' /> Reset
</Button>
</Col>
</Form.Row>
</Form>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
)
}
export default UserEditCard
Комментарии:
1. Попробуйте напечатать это состояние внутри useEffect при визуализации компонента
useEffect(() => console.log(roleInfo, props.roleInfo), [])
. Вероятно, это не определено, потому что реквизиты еще не были переданы вашему компонентуRoleEditCard
2. На это невозможно ответить, не показав нам, как вы используете
<RoleEditCard ... />
.3. Вы асинхронно извлекаете
roleInfo
данные из удаленного ресурса? Вы видите другой журнал перед этим журналом с обоими значениямиundefined
? Обратите внимание, что начальное значение touseState
устанавливается только один раз при монтировании, поэтому, если оно находитсяundefined
на монтировании, но позже изменяется на какое-то значение, вы не увидите, что это отражено в состоянии, пока вы явно не обновите его новым значением.4. Попробуйте вести журнал следующим образом:
console.log('rendering',JSON.stringify(roleInfo), JSON.stringify(props.roleInfo));
сколько раз он регистрируется и что он регистрирует?5. Примечание: roleDetails, privilegeDetails и т. Д. были определены в componentDidMount() компонента класса . Ваш родительский
componentDidMount
элемент вызывается только после того, как ваш дочерний элемент монтируется, и в этот момент начальное состояние уже будет установлено. Вот почему вы видите это какundefined
. ИтакuseState
, хук работает правильно. Но если ваш родитель действительно управляет всеми этими данными, ваш компонент, вероятно, должен контролироваться и вообще не иметь собственного состояния. Он может получать все в качестве реквизитов и передавать ему обработчики вызовов.
Ответ №1:
Вы пробовали что-то еще внутри useState, например
const [roleName, setRoleName] = useState("Hello");
посмотрите, печатает ли console.log имя роли "Hello"
, и если да, просто укажите это, чтобы исправить ваше состояние:
const role = props.roleInfo.role_name;
useEffect(() => setRoleName(role), [role]);