I want to wrap antd component eg. Input into MyInput so I can add support for new pros and classNames, however it stoped working when I put then inside of the Form
MyInput.js
import { Input } from 'antd';
function MyInput({ className='', ...rest }) {
const computedClassName = 'my-input '+className;
return (
<Input className={computedClassName} {...rest} />
);
}
MyInput.defaultProps = Input.defaultProps;
MyInput.propTypes = Input.propTypes;
MyInput.Group = Input.Group;
MyInput.Search = Input.Search;
MyInput.TextArea = Input.TextArea;
Now if I put <MyInput /> inside of <Form/> it stops working
DEMO
I tried to debug, looks like the saveRef function in rc-form/lib/createBaseForm is receiving null as component argument, so this makes me feel is a ref problem, but I'm not sure how to fix it :S
Nevermind I found the answer...
As per Refs documentation
refs doesnt work on stateless components, change it to class and worked
Related
Here an example of the problem :
codesandbox.io
export default function App() {
const [hasInputChanged, setHasInputChanged] = useState(false);
let colorList = ["orange", "blue", "yellow"];
function handleChange(e) {
setHasInputChanged(true);
}
const MyLittleInput = () => {
return <input onChange={(e) => handleChange(e)} />;
};
return (
<>
{colorList.map((color) => (
<MyLittleInput key={color} />
))}
</>
);
}
I tried different solutions as defining Keys or using useRef but nothing worked
It's too much code to be debugged easily, but for what I can see on the fiddle, there are serveral things wrong, first of all you are doing really too much things for a simple increment/decrement of a input value. But most important you are defining theyr value using the parametresListe state, but never really changing it wit the setParametresListe function, which should be the only way to safely change controlled form inputs.
Just try to do a bit of cleaning on your code and to use the useState as it is meat to be used
Let us know any updates!
UPDATE:
Having a look at your cleaned code, the problem is that a input inside a component gets builded again and again.
The reason for that, is that each input should have they unique "key" prop, so react can easily understand what input is changed and update only that one.
You have 2 ways to make this work, for the first, I've edited your code:
import "./styles.css";
import React, { useState } from "react";
const DEFAULT_INPUT_STATE = {
orange: "",
blue: "",
yellow: ""
};
export default function App() {
let colorList = ["orange", "blue", "yellow"];
const [inputState, setInputState] = useState(DEFAULT_INPUT_STATE);
const handleChange = (e) => {
const { name, value } = e.target;
console.log(name);
setInputState({
...inputState,
[name]: value
});
};
return (
<>
{colorList.map((color, i) => (
<input
key={color}
name={color}
value={inputState[color]}
onChange={(e) => handleChange(e)}
/>
))}
</>
);
}
As you can see, I've just removed the component for the input and did a bit of other changes, but If you still want to use a component, you can moove all the .map function inside of it, but there's no way to create the input inside a component if it is in a .map function
There is too much code, difficult to follow through, in your example. In the nutshell, I see in dev tools, when I update an input, the entire example component is re-rendered, thus all input elements got destroyed and replaced by newly created ones, without focus. It must be just a bug in your code: once an input is updated it renders different stuff, instead of just changing the input value. But it is beyond something someone here would debug for you for free :D
I'm using RangePicker from ant design in my app. I'va faced with following issue: when to click on button "reset" I can't clear the value in RangePicker component. Please help me how to do it? I've tried assign defaultValue but It doesn't work.
Use the value parameter of RangePicker instead.
Something like this should probably work. Wasnt in a position to make a enviroment and test it but hopefully you get the idea. Ask any questions if theres something that is not clear.
const SomeComponent = props => {
const [fromDate, setFromDate] = useState('2000-01-01');
const [toDate, setToDate] = useState('2000-01-02');
const onChangeDateRange = (dates, datesString) => {
setFromDate(datesString[0]);
setFromDate(datesString[1]);
//More code
}
const onResetClick = () => {
setFromDate('2000-01-01');
setToDate('2000-01-02');
}
return (
<>
<RangePicker
onChange={onChangeDateRange}
value={[moment(fromDate, dateFormat), moment(toDate, dateFormat)]}
/>
<Button onClick={onResetClick}>Reset</Button
</>
)
}
The docs on ant design are very good and at the end you can find all availible parameters a component can have. DatePicker e.g. has a allowClear. https://ant.design/components/date-picker/
(I hope and assume that there is a simple answer to this question, but I could not find it in the docs)
I've just converted a React project to use Styled Components, and love the DRYness and reusability. But, I've not yet figured out the syntax for using styled components in existing functional components that do other work too.
Here's one example:
const StyledSearchBarPane = styled(Pane)`
grid-area: search-bar;
`;
const SearchBarPane = () => {
const {query} = useContext(panelContext);
let [newQuery, setNewQuery] = useState(query);
return (
<StyledSearchBarPane>
<Bar>
<SearchInput newQuery={newQuery} setNewQuery={setNewQuery}/>
</Bar>
</StyledSearchBarPane>
);
};
How can I avoid naming StyledSearchBarPane? It's only used once -- in SearchBarPane -- and I'd rather it were simply part of the latter's definition.
Yes you can.
Basically what you need to do is use your component as you would normally do and if you want to use a local style on the component without creating one you can use a Wrapper like you did.
But the change is, instead of exporting your component you export the wrapper. Then your component will receive as props className and you need to put it where you want to apply thoses style, in the example since it's globally you put in the root element.
If you don't put the className props it won't style anything.
const SearchBarPane = ({className}) => {
const {query} = useContext(panelContext);
let [newQuery, setNewQuery] = useState(query);
return (
<div className={className}>
<Bar>
<SearchInput newQuery={newQuery} setNewQuery={setNewQuery}/>
</Bar>
</div>
);
};
const StyledSearchBarPane = styled(SearchBarPane)`
grid-area: search-bar;
`;
export default StyledSearchBarPane;
https://styled-components.com/docs/advanced
I'd like part of the record to be included in the label for a BooleanField (and BooleanInput). I'm trying to use WithProps to accomplish this.
If I use
<BooleanField source="FileSystem" label="FileSystem" />
This seems to work just fine. If, instead I try to wrap it
const makeLabel = (props)=>{
let label = `Filesystem for ${props.record.id}`;
return {label};
}
const withLabel = withProps(makeLabel);
const BooleanFieldWithLabel = compose(withLabel)((props)=>{
console.log("props after compose",props);
return <BooleanField {...props}/>
});
And then use <BooleanFieldWithLabel source="FileSystem" /> It doesn't render any label. I've tried a few different ways and nothing seems to work even though I can see in the console.log that the correct label is in props. What am I doing wrong here?
I have the same question, I cannot display the label base on field's value on "Show" page.
From react-admin source code, it seems only I set "addLabel" prop on the direct child of "SimpleShowLayout" or "TabbedShowLayout", then I can see label on my custom field.
But it is not configurable, I want to show/hide label base on field's value. Do I need to implement my own custom "SimpleShowLayout" or "TabbedShowLayout"? Or is there any better approaches?
Update my post.
I just figure out the solution by implementing an HOC like below. I am wondering is there any better approaches to implement the same feature?
import React from "react";
import get from "lodash/get";
import { TextField, DateField, Labeled } from "react-admin";
const NullableField = WrappedComponent => props => {
const { record, source } = props;
const value = get(record, source);
return value ? (
<Labeled {...props}>
<WrappedComponent {...props} />
</Labeled>
) : null;
};
const NullableTextField = NullableField(TextField);
const NullableDateField = NullableField(DateField);
export { NullableTextField, NullableDateField };
I'm trying to create a wrapper component around the react-router-dom NavLink component.
I would like my custom component to accept all of NavLinks props, and proxy them down to NavLink.
However when I do this, I'm getting:
Warning: React does not recognize the staticContext prop on a DOM
element. If you intentionally want it to appear in the DOM as a custom
attribute, spell it as lowercase staticcontext instead. If you
accidentally passed it from a parent component, remove it from the DOM
element.
A working demo of the issue can be found here:
https://codesandbox.io/s/w0n49rw7kw
There is a way to overcome that is using:
const { to, staticContext, ...rest } = this.props;
So your ...rest will never contain staticContext
This is a common problem with a simple solution as documented in the React documentation:
The unknown-prop warning will fire if you attempt to render a DOM
element with a prop that is not recognized by React as a legal DOM
attribute/property. You should ensure that your DOM elements do not
have spurious props floating around.
The spread operator can be used to pull variables off props, and put
the remaining props into a variable.
function MyDiv(props) {
const { layout, ...rest } = props
if (layout === 'horizontal') {
return <div {...rest} style={getHorizontalStyle()} />
} else {
return <div {...rest} style={getVerticalStyle()} />
}
}
You can also assign the props to a new object and delete the keys that
you’re using from the new object. Be sure not to delete the props from
the original this.props object, since that object should be considered
immutable.
function MyDiv(props) {
const divProps = Object.assign({}, props);
delete divProps.layout;
if (props.layout === 'horizontal') {
return <div {...divProps} style={getHorizontalStyle()} />
} else {
return <div {...divProps} style={getVerticalStyle()} />
}
}
This happens because you probably used {...props} somewhere in your component.
Example from React:
function MyDiv(props) {
const { layout, ...rest } = props
if (layout === 'horizontal') {
return <div {...rest} style={getHorizontalStyle()} />
} else {
return <div {...rest} style={getVerticalStyle()} />
}
}
We grab layout separately so that it won't be contained in {...rest}.
The given answer by the React docs was not quite good enough for my situation, so I found/developed one which isn't perfect, but is at least not so much of a hassle.
You can see the Q/A in which it arose here:
What is Reacts function for checking if a property applies?
The gist is, use a function to pick the bad props out for you.
const SPECIAL_PROPS = [
"key",
"children",
"dangerouslySetInnerHTML",
];
const defaultTester = document.createElement("div")
function filterBadProps(props: any, tester: HTMLElement = defaultTester) {
if(process.env.NODE_ENV !== 'development') { return props; }
// filter out any keys which don't exist in reacts special props, or the tester.
const out: any = {};
Object.keys(props).filter((propName) =>
(propName in tester) || (propName.toLowerCase() in tester) || SPECIAL_PROPS.includes(propName)
).forEach((key) => out[key] = props[key]);
return out;
}
Personally, I felt that the warning was completely useless in the first place, so I added a line which skips the check entirely when not in development mode (and warnings are suppressed). If you feel that the warnings have merit, just remove the line:
if(process.env.NODE_ENV !== 'development') { return props; }
You can use it like this:
public render() {
const tooManyProps = this.props;
const justTheRightPropsForDiv = filterBadProps(tooManyProps);
const justTheRightPropsForSpan = filterBadProps(tooManyProps, document.createElement("span"));
return (<div {...justTheRightPropsForDiv}>
<span {...justTheRightPropsForSpan} />
</div>)
}
If someone has this issue with react-admin, check if you don't have a Link as a child of Admin. Like this:
<Admin layout={props => <Layout/>}>
<Link to="/something">something</Link> <-- causing issue
</Admin>
Just move it to another component. For instance, inside the Layout.
I got the same issue when passing data in child component with camelCase property.
Warning: React does not recognize the moreInfo prop on a DOM element.
If you intentionally want it to appear in the DOM as a custom attribute,
spell it as lowercase moreinfo instead. If you accidentally passed it
from a parent component, remove it from the DOM element.
<CenteredModal
moreInfo={viewType}
/>
To fix that error, I used all lowercase letters for property.
<CenteredModal
moreinfo={viewType}
/>