Could not console log the updated state array - javascript

I am making a simple application where the user can create a new form on a button click, so for this, I have an array state like this :
const [numbers, setNumbers] = useState([0]);
const [count, setCount] = useState([0]);
And on my button onClick method I have this,
setCount(count + 1);
setNumbers(numbers.concat(numbers[0] + count));
In my render method, I have :
{numbers.map((number) => {
return (
<div key={number}>
<InputCreator id={number} value={number} />
</div>
);
})}
And my InputCreator component is a simple callback component with few textfields.
So far, it works well. Lately I wanted to add a delete functionality where the user can delete that particular form. So, I added.a button inside this form and on the onClick method, I tried console loging the "numbers" state to check everything is working, but it logs only the default value I have given while creating the state and not the updated state. What could be the reason ? So my idea is to delete that index from the array using the props passed, so that the component will re-render with the updated number of forms. Is there a better way to do this ?
EDIT : This is my InputCreator component,
const InputCreator = useCallback((props) => {
const { id, value } = props;
// console.log(titles[id]);
return (
<div>
<Col xs={12} md={8}>
<div className={styles.container}>
<Form
noValidate
validated={false}
onSubmit={handleSubmit}
encType="multipart/form-data"
>
<Form.Group controlId="formGroupTitle">
<Form.Label>Title</Form.Label>
<Form.Control
type="text"
placeholder="Title"
onChange={(e) => handleChange(e, value)}
name="title"
value={titles[id]}
/>
</Form.Group>
<Form.Group controlId="formGroupTitle">
<Form.Label>Description</Form.Label>
<Form.Control
type="text"
name="description"
placeholder="Max limit 30"
onChange={(e) => handleChange(e, value)}
maxLength={31}
value={descriptions[id]}
/>
</Form.Group>
<Button
variant="outline-primary"
size="sm"
className={styles.deleteBtn}
onClick={(e) => handleDelete(e, number)}
>
X
</Button>
</Form>
)})
handleDelete :
const handleDelete = (e, value) => {
e.preventDefault();
console.log(numbers);
}

I will just point out the mistakes I see as your question is not worded clearly.
Keys aren't passed into they are passed into list in order to create a list for every element with a unique ID. I am not sure what you are trying to do in your render method but I would suggest doing something like this :
const renderNumbers = () => myArray.map((number, index) =>
<MyComponent key={index} number={number} />
To delete an element. Create a function that takes in the ID. Filter it to show a new array without that ID, below is an example that you ca apply.
const deletePerson = (id) => {
setNumbers(numbers.filter((number) => number.id !== id));
};
Send this handle to the button that deletes the element
const handleDeleteNumber = () => {
deleteNumber(number.id);
};
Make a single handleInputChange() that you can use for all input changes. Such as this one :
const handleInputChange = (event) => {
setInfo({ ...info, [event.target.name]: event.target.value });
};
In the tag you pass in id and values separately like this
value={descriptions}
key={id}

Related

OnChange on a FormControl taking a long time to update State : Redux-React Bootstrap

FormView
export default function FormView({jobName}) {
const dispatch = useAppDispatch();
// FETCHING POST API RESPONSE STORED IN REDUX STORE
const { fetched_api_response } = useAppSelector(mainDetails);
useEffect(() => {
dispatch(
postRequestAPICall({
jobname: jobName
})
);
}, []);
//Working as Expected Updating a new key pair to existing object **fetch_api_response** in real time.
const handleChange = (e) => {
const {name, value} = e.target;
dispatch(add_new_key_pair_for_fetch_api_response({
newPropertyName:name,
newPropertyValue: value
}))
}
const handleSubmit = (e) => {
//Also Working as Expected Submitting Modified fetched_api_response result to formFinalSubmit Api Response
dispatch(form_submit_final({ submittedForm:fetched_api_response }))
event.preventDefault();
event.persist();
}
return (
<div>
<Form onSubmit={handleSubmit}>
<Form.Group >
<Form.Control
type="input"
name="color"
onChange={handleChange}
/>
</Form.Group>
<Form.Group >
<Form.Control
type="input"
name="shape"
onChange={handleChange}
/>
</Form.Group>
<FormModalView fetchedApiResponse={fetched_api_response} />
<Button type="submit"></Button>
</Form>
</div>
)
FormModalView
export default function FormModalView({fetchedApiResponse}) {
const dispatch = useAppDispatch();
const [displayModal, setDisplayModalPostgres] = React.useState(false);
const [modalFormInputs, setModalFormInputs] = React.useState<Record<string, any>>(fetchedApiResponse);
// This is Causing the Problem Taking a very long time to update a single Character in the state variable. Not getting any errors as well
**const onFormModalChange = (e) => {
const {name, value} = e.target;
setModalFormInputs((prevState) => ({
...prevState,
[name]: value
}));
};**
//Modal Inputs have are Editable Inputs with default values coming from api.
//Once the value is changed i want onChange to trigger and update and existing key_value in the api
//this wont create a new key-value pair
const TestApiresponse = () => {
return (
<div>
<Form.Group >
<Form.Control
type="text"
name="shape"
onChange={handleChange}
defaultValue={modalFormInputs.tenant}
/>
</Form.Group>
</div>);
};
return (
<span>
<Button onClick={handleShow}>Advance Options</Button>
<Modal show={displayModal} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title> Form Modal </Modal.Title>
</Modal.Header>
<Modal.Body>
<TestApiresponse />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={handleSubmit}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
<span/>
)}
}
I am Trying a display a Form & a modalForm in React Bootstrap && Redux
Where FormView Contains inputs which add new property keys & values to a state stored in redux.
and
FormModalView contains inputs modify existing property values of the same state stored in redux.
FormView functionality is working as Expected :)
but
FormSubView contains Form inputs taking a really long time to update the state i am not understanding what i am doing wrong or which rule of react i am breaking
need help here.
Whats Surprising is i have already created a another Editform which had formView and FormModalView only for editing a state in redux store and thats working as expected.
only the combination where i am adding new key/pair or updating new key/pair in redux store is where i am facing an issue.

how to get value in dynamic text input in react.js?

I made one page in react.js project that has a text input and a button for each row of data.
I want to get each input value by on click button and do process over it.
{data.map((item, index) => <div><span>{item}</span>
<input type="text" placeholder='enter value' />
<button onClick={() => {alert(inputValue) }}>
click me
</button>
</div>
)}
You can do something like this
const data = [0, 1, 2, 3];
export default function App() {
const [inputs, setInputs] = useState({});
return (
<div className="App">
{data.map((item) => (
<div key={item}>
<input
onChange={(e) =>
setInputs((prev) => {
return { ...prev, [item]: e.target.value };
})
}
/>
<button onClick={() => alert(inputs[item])}>Click</button>
</div>
))}
</div>
);
}
Codesandbox: https://codesandbox.io/s/divine-wildflower-1ge7ev?file=/src/App.js:58-550
The correct react way of doing this would be to create a standalone component e.g. UserInput and keep track of user input's state:
// Create state
const [input, setInput] = React.useState('')
return (
<input type="text" placeholder='enter value'
onChange={event => setInput(event.target.value)}
/>
<button onClick={() => {alert(input) }}>
click me
</button>
);
You can then add this to your current component as follows:
{data.map((item, index) => <div><span>{item}</span><UserInput/></div>)}
I suggest you use an object instead of an array. It's more appropriate for key-value pairs.
If you use an object, it will be easier, readable and more maintainable.
How to do this?
You just need to modify your code to loop through the keys of your object then every time the input value changes (onChange), then set the value of the object onChange={(e) => data[key]=e.target.value}. To access the value when the button of the field is clicked, just use the data[key].

Set the react-bootstrap checkbox to uncheck state

I am a newbie to react and I was not able to figure how to reset the checkbox to uncheck stat on resetting. I have used the react-bootstrap form and need to reset the checkboxes to default state on a button click.
export const pitch: FC<pitchProps> = ({ pitchData, totalNoOfData }) => {
const [loading, setLoading] = useState(false);
const [totalRows, setTotalRows] = useState(totalNoOfData);
const formData = {
searchData: pitchParam.searchString,
searchCriteria: pitchParam.searchStatus,
};
const handleFormData = (e: any) => {
if (e.target.type === "checkbox") {
e.target.checked
? formData.searchCriteria.push(e.target.id)
: (formData.searchCriteria = formData.searchCriteria.filter(
(item: any) => item !== e.target.id
));
} else {
formData.searchData = e.target.value;
}
};
return (
<div className={styles.mainTableContainer}>
<div className="d-flex ml-2">
<Form className="w-100">
<Form.Row>
<Form.Label className={styles.label}>NEW </Form.Label>
<Form.Check
className={styles.checkbox}
type="checkbox"
id="OLD"
onChange={(e: any) => handleFormData(e)}
/>
<Form.Label className={styles.label}> OLD </Form.Label>
<Form.Check
className={styles.checkbox}
type="checkbox"
id="OUTDATED"
onChange={(e: any) => handleFormData(e)}
/>
<Form.Label className={styles.label}>OUTDATED </Form.Label>
<Form.Check
className={styles.checkbox}
type="checkbox"
id="SUCCESS"
onChange={(e: any) => handleFormData(e)}
/>
</Form.Row>
</Form>
</div>
</div>
);
};
Your checkbox component is not fully controlled by you, so it is an uncontrolled component.
Solution 1 : using reference
As your checkbox is controlled by the bootstrap-form you need to create a reference and pass it to the checkbox to manipulate the checked value:
import React, {useRef} from 'react';
// reset of the codes
// in the pitch component
const checkboxRef = useRef(null);
Now, pass the checkboxRef into the checkbox component within ref property:
<Form.Check
type={type}
id={`default-${type}`}
label={`default ${type}`}
ref={checkboxRef} // <--------- here
/>
Now, try to add another button with a reset handler:
const handleResetCheckbox = () => {
checkboxRef.current.checked = false
}
Solultion 2 : using react key
You can also do the same with a different approach by using the React component's key.
If the key gets changes, react will remove the component and create a new one. so you can use this key property to uncheck (reset) the checkboxes:
define a key with useState and pass it to the checkbox component:
const [key, setKey] = useState(false)
<Form.Check
key={key} // <--------- added here
type={type}
id={`default-${type}`}
label={`default ${type}`}
/>
Now, in the handleResetCheckbox, change the key:
const handleResetCheckbox = () => {
setKey(prevState => !prevState)
}
So, when you reset the checkbox, the key will change then React will remove the old checkbox and render a new one. more information in React documentation.

React 16.13: useState wait for state to update before render

I have an array of strings, and it's count in state:
const [count, setCount] = useState(0);
const [strings, setStrings] = useState([""]);
So in the beginning I always have an element in the state.
On a button click I'm adding to the count and the list:
function onClickAdd() {
setStrings(prev => [...prev, ""]);
setCount(count + 1);
}
I'm rendering multiple text fields based on this count, and the value of those text fields is set from the array index (range is a custom function, returns array of values from start -> end):
function makeInputs(count, onRemove) {
return range(1, count).map(id => {
return (
<TextInput type="url" validate onChange={e => onChange(e, id)} value={strings[id]}
icon={<Button style={{backgroundColor: "red"}} onClick={() => onRemove(id)}><Icon>remove</Icon></Button>} />
);
});
}
But whenever I click the add button, new field is rendered and the value of new fields is set to undefined (strings array is not updated yet), and I get a warning:
index.js:1 Warning: A component is changing an uncontrolled input of type url to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component
How can I delay the render until list is resized?
I've tried moving setCount() to useEffect() but doing that doesn't make the new fields show up at all.
https://codesandbox.io/s/aged-dew-eud84?fontsize=14&hidenavigation=1&theme=dark
Try this
function Form() {
const [values, setValues] = useState([]);
return (
<div>
<button onClick={() => setValues([...values, ""])}>Add</button>
{values.map((value, idx) =>
<div key={String(idx)}>
<input
type="text"
value={value}
onChange={(e) => {
values[idx] = e.target.value;
setValues([...values]);
}}
/>
</div>
)}
</div>
);
}

How to get selected data from child state to parent in React

I have a flight page with various cards with different route information in each. Within each card I have a select button which is identified by the flightID.
Select(FD) {
this.state={route:''};
return (
<div>
{FD.FlightID}
<label>
<Checkbox id={FD.FlightID}
name={FD.FlightID}
checked={this.setState.route}
onChange={this.handleCheckboxChange}
/>
<span>Select</span>
</label>
</div>
)
}
The Select method is called within each card.
return data.map( FD1 => (
<Row>
<Card className="card">
<Card body className="text-center">
<CardTitle data-es-label="location"> Location:
{FD1.Departure}
</CardTitle>
<CardText data-es-label="Price">Price
{FD1.price}
</CardText>
{this.Select(FD1)}
<CardActions>'
How do I access the data of the specific card selected to send to make a booking?
EDIT:
the handleCheckBoxChange
handleCheckboxChange = event =>
this.setState({ route: event.target.checked });
One way to do this is to pass id in onChange method like this
<Checkbox
...
onChange={() => this.handleCheckboxChange(FD.FlightID)}
/>
Then in parent component you can get your element from data array like this
handleCheckboxChange = (id) => {
const selected = data.find(e => e.FlightID = id);
...
}
If you want to pass some data through more components you need to read about React context (https://reactjs.org/docs/context.html)
try this.
<Checkbox
id={FD.FlightID}
name={FD.FlightID}
checked={this.setState.route}
onChange={() => this.handleCheckboxChange(FD)}
/>

Categories

Resources