how to refresh the antd pro ProFormText initialValue - reactjs

I am using antd pro to develop an app, now facing a problem is that the ProFormText initialValue did not update when the props changed. I pass the record from props and give it to the ModalForm, this is the code looks like:
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
const intl = useIntl();
const { initialState } = useModel('##initialState');
return (
<ModalForm
title={intl.formatMessage({
id: 'pages.apps.jobs.interview.updateInterview',
defaultMessage: 'New rule',
})}
width="400px"
visible={props.updateModalVisible}
onVisibleChange={(value)=>{
if(!value){
props.onCancel();
}
}}
onFinish={props.onSubmit}
>
<ProFormText
initialValue={props.values.company}
name="company"
label={intl.formatMessage({
id: 'pages.apps.jobs.interview.searchTable.company',
defaultMessage: 'company',
})}
width="md"
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.searchTable.updateForm.ruleName.nameRules"
defaultMessage="Please input the nameļ¼"
/>
),
},
]}
/>
);
}
when open the modal and give the initial value, the next time when the props value change, the ProFormText still keep the first time value. I have read this question: Update antd form if initialValue is changed seems it only works on antd. the ModalForm did not contain the useForm() method. what should I do to fix this problem and keep the value changed follow props? This is the version info:
"#ant-design/pro-form": "^1.52.0",
"#ant-design/pro-layout": "^6.32.0",
"#ant-design/pro-table": "^2.61.0",

I am facing the same problem with you, and tried follow the Update antd form if initialValue is changed instructions and works. First add:
const [form] = Form.useForm()
and bind the form with ModalForm like this:
<ModalForm
form = {form}
title={intl.formatMessage({
id: 'pages.apps.jobs.interview.updateInterview',
defaultMessage: 'New rule',
})}
width="400px"
visible={props.updateModalVisible}
onVisibleChange={(value)=>{
if(!value){
props.onCancel();
}
}}
onFinish={props.onSubmit}
>
you may facing the error Module "./antd/es/form/style" does not exist in container, just delete the .umi cache folder and rebuild the project. Finally add this code to reset the fields when the props changed:
useEffect(() => {
form.resetFields();
form.setFieldsValue(props.values);
});

Related

Updating Formik State whilst using Headless UI "Listbox" (which manages its own state, internally)

I'm struggling to get a Headless UI Listbox implementation working successfully with Formik. After reading all the docs and scouring StackOverflow, I'm yet to find an answer.
I can get the Listbox to function perfectly well on its own, and Formik is working with other, less complex (but still custom) components. That said, I can't get them working in unison. Whenever I change the selection in the Select component, I can successfully update the Headless UI state (in as much as it updates to the correct value) and the Formik state, but for some reason the active and selected properties (within Headless UI) aren't working correctly (always false).
I assume what I need to do is to make use of the onChange handler so that it updates both the Headless UI state (to keep the active and selected properties updated) and the Formik value, but this doesn't seem to work as expected.
Does anyone have any suggestions? Please see a minimal representation of the code below:
export function TestForm() {
return (
<Formik
initialValues={{ testing: {} }}
onSubmit={ alert("Submitted"); }
>
<Form>
<Select
name="testing"
items={[
{ id: 1, name: "Test 1" },
{ id: 2, name: "Test 2" },
{ id: 3, name: "Test 3" },
]}
/>
</Form>
)
}
export function Select(props) {
// Get field properties
const [field, meta, helpers] = useField(props);
// Set initial value for `Select`
const [selectedItem, setSelectedItem] = useState(null);
// On change, update `Headless UI` and `Formik` values
const handleChange = (newValue) => {
setSelectedItem(newValue); // Update the Headless UI state
helpers.setValue(newValue); // This seems to "break" the Headless UI state
};
// Return `Select` structure
return (
<Listbox
value={selectedItem}
name={props.name}
onChange={handleChange}
// onBlur={field.onBlur} ...Commented out for now as trying to figure out issue with `onChange`
>
<Listbox.Label>Test Label:</Listbox.Label>
<Listbox.Button>
{selectedItem ? selectedItem.name : "-- Select --"}
</Listbox.Button>
<Listbox.Options>
{props.items.map((item) => {
return (
<Listbox.Option
className={({ active }) => (active ? "active" : "")}
key={item.id}
value={item}
>
{({ selected }) => (
<>
{item.name}
{selected ? <CheckIcon /> : null}
</>
)}
</Listbox.Option>
);
})}
</Listbox.Options>
</Listbox>
);
}
I managed to make it work like this:
import { useField } from "formik";
interface SelectProps {
name: string;
label: string;
options: string[];
}
export const Select: React.FC<SelectProps> = ({
name,
label,
options,
}) => {
const [field] = useField({ name });
return (
<Listbox
value={field.value}
onChange={(value: string) => {
field.onChange({ target: { value, name } });
}}
>
...
</Listbox>
);
};

MUI: The `getOptionLabel` method of Autocomplete returned undefined instead of a string

I am having trouble configuring this error (below), when I click the autocomplete search the display data is blank the error shows on the console
when i tried to type
the api fetch on when the user typing
where did i get wrong?
LocationSearch
const propTypes = {
getOptionLabel: PropTypes.func,
value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
}
const defaultProps = {
getOptionLabel: () => {},
value: '',
}
const LocationSearch = ({
getOptionLabel,
value,
})
....
<Autocomplete
getOptionLabel={getOptionLabel}
value={value}
/>
Parent
import {LocationSearch} from '../../component/LocationSearch'
......
<LocationSearch
getOptionLabel={(options) => options.title}
value={threatLocation}
/>
error
try providing an array of objects in the getOptionLabel parameter as autocomplete option maps data and find the key as you are looking for maybe that works.
<Autocomplete
getOptionLabel={[{title:'a', name: 'a'}, {title:'b', name: 'b'}]}
value={value}
/>

Validating a child input type file with react-hook-form and Yup

I'm creating a form with a file upload with help of react-hook-form and Yup. I am trying to use the register method in my child component. When passing register as a prop (destructured in curly braces) the validation and submiting doesn't work. You can always submit the form and the submitted file object is empty.
Here's a sandbox link.
There are several of problems with your code.
1- register method returns an object with these properties:
{
onChange: function(){},
onBlur:function{},
ref: function(){}
}
when you define your input like this:
<input
{...register('photo')}
...
onChange={(event) => /*something*/}
/>
actually you are overrding the onChange method which has returned from register method and react-hook-form couldn't recognize the field change event. The solution to have your own onChange alongside with react-hook-form's onChange could be something like this:
const MyComp = ()=> {
const {onChange, ...registerParams} = register('photo');
...
return (
...
<input
{...params}
...
onChange={(event) => {
// do whatever you want
onChange(event)
}}
/>
);
}
2- When you delete the photo, you are just updating your local state, and you don't update photo field, so react-hook-form doesn't realize any change in your local state.
the problems in your ImageOne component could be solved by change it like this:
function ImageOne({ register, errors }) {
const [selectedImage, setSelectedImage] = useState(null);
const { onChange, ...params } = register("photo");
return (
...
<Button
className="delete"
onClick={() => {
setSelectedImage(null);
//Make react-hook-form aware of changing photo state
onChange({ target: { name: "photo", value: [] } });
}}
>
...
<input
//name="photo"
{...params}
type="file"
accept="image/*"
id="single"
onChange={(event) => {
setSelectedImage(event.target.files[0]);
onChange(event); // calling onChange returned from register
}}
/>
...
);
}
3- Since your input type is file so, the value of your photo field has length property that you can use it to handle your validation like this:
const schema = yup.object().shape({
photo: yup
.mixed()
.test("required", "photo is required", value => value.length > 0)
.test("fileSize", "File Size is too large", (value) => {
return value.length && value[0].size <= 5242880;
})
.test("fileType", "Unsupported File Format", (value) =>{
return value.length && ["image/jpeg", "image/png", "image/jpg"].includes(value[0].type)
}
)
});
Here is the full edited version of your file.

Handle a custom component using React Hook Forms and React Table

I'm trying to set up a custom component to my react-hook-forms and react-table
const selectedUserIds = watch(`user_ids`) || [];
<Controller
control={control}
name={fieldName("user_ids")}
render={({ field: { value, onChange } }) => (
<UserTable selectedUserIds={selectedUserIds} updatePropertySelection={onChange}/>
)}
/>
UserTable:
function updatePropertyTableSelection(ids){
const ids = extractIds(ids);
updatePropertySelection(ids);
}
const selectedUserIdsForTable = convertIdsToTableFormat(selectedUserIds)
return (
<React.Fragment>
<BasicTable
tableHeader={() => null}
columns={[
{
Header: "User Name",
accessor: "attributes.name",
}
]}
data={data}
selectedRows={selectedUserIdsForTable}
onSelectedRowsChange={updatePropertyTableSelection}
/>
</React.Fragment>
)
When I associate the onChange handler to updatePropertySelection I get stuck in an infinite rerender. How should I prevent that?
I faced the same issue and I fix it by following this:
First one, my issue comes from the old react-hook-form, now I'm using ^7.14.2 and its resolve issue.
Second solution fixed issue by replacing onChange to field.onChange
for example (from real project):
<Controller
name={"explanation"}
control={props.control}
render={({field}) => {
return (
<MyEditor
placeholder={t("onlineAssessments.question.explanationPlaceholder")}
onPressEnter={props.onPressEnter}
onChange={(val, editor) => {
// notify parent
field.onChange(val);
// calc count
setExplanationCount(editor?.getBody().innerText.trim().length)
}
}
/>
)
}
}
/>
and I think this change comes from the latest update..
May you have something keep re-render trigger, base on your table, you may need to useCallBack or useMemo to prevent re-render on each visit else if dependency change, for example:
const updatePropertyTableSelection = useCallBack((ids) => {
const ids = extractIds(ids);
updatePropertySelection(ids);
}, []);
and
const selectedUserIdsForTable = useMemp(() => { convertIdsToTableFormat(selectedUserIds)
}, []);
Note: Don't forget to update dependency only if it's needed and only to what you needed to re-render

Reloading a button on event change in React Typescript

I am having a simple form in React, which looks like:
const [placeOptions] = useState([
{ value: 'USA', label: 'USA' },
{ value: 'MEX', label: 'Mexico' },
]);
const [name, setName] = useState('');
const [place, setPlace] = useState('USA');
....
<input onChange={event => setName(event.target.value)} type="text"/>
<select onChange={event => setPlace(event.target.value)}>
{placeOptions.map(item => (
<option key={item.value} value={item.value}>
{item.label}
</option>
))}
</select>
<CustomButton id="custom-btn" props={[name, place]} />
The above Custom button is just rendering once and is taking the default null and 'USA' value. It should Ideally send props to every event change, possibly refreshing the component once event is triggered. I am unable to determine how do I refresh a component on event change and pass the correct state to the props.
Edit: The below is the CustomButton.tsx file:
export function CustomButton({ props, id }: { props?:any, id?:string}) {
var name = props ? props[0] : '';
var place = props ? props[1] : '';
useEffect(() => {
renderButton(id);
}
return(
<React.Fragment>
<div id={id}></div>
</React.Fragment>
);
async function renderButton(id: string) {
... // Some logic involving the props passed
}
}
Edit 2:
This the code sandbox: https://codesandbox.io/s/amazing-dust-315dk?file=/src/App.js
All I want is to change the props too and dynamically render the custom button.
The problem is how you define the name and the place variable in CustomButton Component.
Variables of javascript defined like var let, and const will not trigger re-renders in React Button. States and Props only can trigger re-renders in React Components.
So if you do something like this in the parent file:
// All same code excepet
<CutomButtom id="cutom-btn" name={name} place={place} />
You can get name and place directly from props and use them as it is like:
export function CustomButton({ name, place, id }: { name: string, place: string, id:string}){
// NO need for defining name and place now, just use them directly...
}
Another improvement you can make is to define PropsType separately:
export interface CustomButtonProps {
id: string;
name:string;
place:string;
}
export function CustomButton({name, place, id}:CustomButtonProps){
}

Resources