I have the following React render function:
render: function () {
return (
<Popup onClose={this.props.onClose}>
<Form entity="strategy" edit="/strategies/edit/" add="/strategies/add/">
<h2>Create/Edit Strategy</h2>
<StrategyForm pending={this.state.pending} formData={this.state.data} />
<div className="col-md-6">
<Assisting />
</div>
</Form>
</Popup>
);
}
I would like to make the h2 heading be based on the body class, so my question is...can I do this?
render: function () {
return (
<Popup onClose={this.props.onClose}>
<Form entity="strategy" edit="/strategies/edit/" add="/strategies/add/">
if ( $('body').hasClass("this") ) {
<h2>Create This Strategy</h2>
} else {
<h2>Create Another Strategy</h2>
}
<StrategyForm pending={this.state.pending} formData={this.state.data} />
<div className="col-md-6">
<Assisting />
</div>
</Form>
</Popup>
);
}
If this is a terrible idea, can someone tell me what is a better way to do this in React?
As has already been noted in some of the comments on the OP, you could do it, but it's not really the "React" way.
A better solution would probably be to pass a prop into the usage of your component or have a flag on the state of your component -- then use that prop/flag to render.
Pseudocode:
render() {
return (
if (this.props.someProp) {
<h2>Create this Strategy</h2>
} else {
<h2>Create this Strategy</h2>
}
);
}
IMO using jQuery in the component methods is fine (e.g. componentDidMount(), or other event/utility methods) but usually you'll want to avoid this in render(). The whole purpose of React components is maintaining state, so on-the-fly usage of jQuery like your example defeats that idea.
Let's say for example you're rendering your component this way:
ReactDOM.render(<MyComponent />, document.getElementById('some-div'));
You can pass properties to your component:
ReactDOM.render(
<MyComponent someProp={true} />,
document.getElementById('some-div')
);
Or in your case:
ReactDOM.render(
<MyComponent someProp={$('body').hasClass("this")} />,
document.getElementById('some-div')
);
...something like that. It's an over-simplified example (not tested, so beware syntax errors) but that should help explain my thought process.
Alternatively, you use the componentDidMount() method on your class.
componentDidMount() {
this.setState({
someProp : $('body').hasClass("this")
});
}
and then in render() check against this.state.someProp.
Related
I found a similar question here: React component closing tag
but i am still confuse...
why when I do this it doesnt work? innertherinner doesnt get rendered.
function Outer(props) {
return (
<Inner>
<InnerTheInner />
</Inner>
)
}
function Inner(props) {
return (
<>
</>
)
}
function InnerTheInner() {
return (
<>
innertheinner
</>
)
}
ReactDOM.render(
<React.StrictMode>
<Outer user='nishi' avatar='avatar photo' />
</React.StrictMode>,
document.getElementById('root')
);
isnt it equivalent to this:
<Outer>
<Inner>
<InnerTheInner>
InnerTheInner
</InnerTheInner>
</Inner>
</Outer>
You need
function Inner(props) {
return <>{props.children}</>;
}
else it would just render always
return (
<>
</>
)
Checkout https://reactjs.org/docs/composition-vs-inheritance.html
In fact you're rendering an empty Fragment using Inner component - without any child nodes. React components do not render its children inside unless you tell them to do so explicitly:
function Inner(props) {
return (
<>
{props.children}
</>
)
}
That way, every component that is passed inside the <Inner> will be rendered (as it's a part of the children prop).
Also you can simplify it, as there's no need to use Fragment at all, just return props.children and you're good to go.
function Inner(props) {
return props.children
}
I have a React-Select Field, inside a Formik Field, that when you select an item from the dropdown options, all the Parent Components are rerendered. This is the deepest child component available in the Container.
And it re-renders 4 Parents. Which is kind of Problematic. I want to limit the rerender of the Component to only itself.
The above happens because each Child Process passes
props to the Container, which is the master form.
And onSubmit it takes all the info(props) and makes the API Call.
I tried doing it with shouldComponentUpdate but no luck. I tried to do it with SetState, but that though fell in the water, as I couldn't make it work(Got a ton of errors).
--TLDR--
THE PROBLEM:
Make a Component retain the rendering to only itself. External Components used in it Formik and React-Select.
Here is the code for that:
<div className="w-50">
<Field
name={`${keyField}.${index}.permissions`}
render={({ field: { value, name }, form: { setFieldValue, setFieldTouched } }) => (
<div>
<label htmlFor="namespace-permissions" className="font-weight-medium">
Permissions in Namespace <Asterisk />
</label>
<Select
isMulti
closeMenuOnSelect={false}
id="namespace-permissions"
defaultValue={convertNamespaceToDefaultValue(
dependencies.namespacePermissions,
value
)}
options={convertNamespaceToSelect(dependencies.namespacePermissions)}
onChangeCallback={values => {
setFieldValue(name, convertSelectToNamespacesData(values));
setFieldTouched(name, true);
}}
/>
<ErrorMessage name={name} component={FormErrorMessage} />
</div>
)}
/>
</div>
The dependacies prop is what makes the trip up the tree, to the master form Props, and rerenders the entire Component Tree. This also, ties with another question I had yesterday, about react-select's closeMenuOnSelect={false} not working correctly.
^This is the reason why that happens. Thank you..
I don't know how you would be able to do this with the libraries that you're using. But when I don't want my components rendering unnecessarily I use React.memo it will shallow compare the props object and decide if needs to update.
From React DOCS
WITHOUT REACT MEMO
function App() {
return(
<Parent1/>
);
}
function Parent1(props) {
console.log('Rendering Parent1...');
const [parentState,setParentState] = React.useState(true);
return(
<Parent2
setParentState={setParentState}
/>
);
}
function Parent2(props) {
console.log('Rendering Parent2...');
return(
<Child
setParentState={props.setParentState}
/>
);
}
function Child(props) {
console.log('Rendering Child...');
return(
<button onClick={()=>props.setParentState((prevState)=>!prevState)}>Update ParentState</button>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
WITH REACT.MEMO
function App() {
return(
<Parent1/>
);
}
function Parent1(props) {
console.log('Rendering Parent1...');
const [parentState,setParentState] = React.useState(true);
return(
<Parent2
setParentState={setParentState}
/>
);
}
const Parent2 = React.memo(function Parent2(props) {
console.log('Rendering Parent2...');
return(
<Child
setParentState={props.setParentState}
/>
);
}
);
const Child = React.memo(function Child(props) {
console.log('Rendering Child...');
return(
<button onClick={()=>props.setParentState((prevState)=>!prevState)}>Update ParentState</button>
);
}
);
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
I would check if Formik's onSubmit is being called and if that's triggering the tree to re-render. If you have a button with type=button that could be triggering a form submit.
There is also a bug with Formik before v2 where Field will mount and unmount all of it's children on every update if given the render function through render or component prop. Instead just pass the render function as the Fields child.
I am new in react.
I try to output two components with react 16+, that starting like this:
function InsuranceInfo(props) {...
// and
function InsuranceCustomerInfo(props) {...
and main component render function look like this
render()
{
return (
<InsuranceInfo args={this.state.orderIfo}/>,
<InsuranceCustomerInfo args={this.state.orderIfo}>
)
}
when i load the page i see only last one.
can any one help please? thank you!
Do not use comma (,) sign between component. Either wrap the returning component in some html element
render()
{
return (
<div>
<InsuranceInfo args={this.state.orderIfo}/>
<InsuranceCustomerInfo args={this.state.orderIfo} />
</div>
)
}
or use React Fragments:
render()
{
return (
<React.Fragment>
<InsuranceInfo args={this.state.orderIfo}/>
<InsuranceCustomerInfo args={this.state.orderIfo} />
</React.Fragment>
)
}
Try this, which use Fragment
render()
{
return (
<>
<InsuranceInfo args={this.state.orderIfo}/>
<InsuranceCustomerInfo args={this.state.orderIfo}>
</>
)
}
Or array
render()
{
return [
<InsuranceInfo key="info" args={this.state.orderIfo}/>,
<InsuranceCustomerInfo key="customer" args={this.state.orderIfo}>
];
}
The proper way to achieve what you want is to use HOC (Higher-Order Components)
Have a look at the documentation here for more details.
So I have this simple class before I change it to pure function as eslint told me to do
class user extends Component {
render(){
return(
<Aux>
<UserTable title="User" type="user" role={this.props.location.roleAction}/>
</Aux>
)
}
}
export default user;
and then I got the eslint error said that component should be written as pure function and I try to change that to pure function like down bellow
const user = () => (
<Aux>
<UserTable title="User" type="user" role={this.props.location.roleAction} />
</Aux>
);
export default user;
and after change it to arrow function, I can't read the this.props.location.roleAction I got an error "cannot read property "location" of undefined " .why is that could happen? any solution to fix the error so I can using the arrow function and able to read the property. it work fine when I use the previous written component.
any help would be really appreciate.
In the pure function ("Stateless Functional Component" or SFC) form, you receive props as a parameter:
const user = props => ( // <−−−− Here
<Aux>
<UserTable title="User" type="user" role={props.location.roleAction} />
^−−−−−− no `this` here since it's
a parameter
</Aux>
);
This is covered in the docs here. Here's a simple runnable example:
const Example = props => (
<div>{props.text}</div>
);
ReactDOM.render(
<div>
<Example text="one" />
<Example text="two" />
</div>,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Lets say I have a view component that has a conditional render:
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
MyInput looks something like this:
class MyInput extends React.Component {
...
render(){
return (
<div>
<input name={this.props.name}
ref="input"
type="text"
value={this.props.value || null}
onBlur={this.handleBlur.bind(this)}
onChange={this.handleTyping.bind(this)} />
</div>
);
}
}
Lets say employed is true. Whenever I switch it to false and the other view renders, only unemployment-duration is re-initialized. Also unemployment-reason gets prefilled with the value from job-title (if a value was given before the condition changed).
If I change the markup in the second rendering routine to something like this:
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<span>Diff me!</span>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
It seems like everything works fine. Looks like React just fails to diff 'job-title' and 'unemployment-reason'.
Please tell me what I'm doing wrong...
Change the key of the component.
<Component key="1" />
<Component key="2" />
Component will be unmounted and a new instance of Component will be mounted since the key has changed.
Documented on You Probably Don't Need Derived State:
When a key changes, React will create a new component instance rather than update the current one. Keys are usually used for dynamic lists but are also useful here.
What's probably happening is that React thinks that only one MyInput (unemployment-duration) is added between the renders. As such, the job-title never gets replaced with the unemployment-reason, which is also why the predefined values are swapped.
When React does the diff, it will determine which components are new and which are old based on their key property. If no such key is provided in the code, it will generate its own.
The reason why the last code snippet you provide works is because React essentially needs to change the hierarchy of all elements under the parent div and I believe that would trigger a re-render of all children (which is why it works). Had you added the span to the bottom instead of the top, the hierarchy of the preceding elements wouldn't change, and those element's wouldn't re-render (and the problem would persist).
Here's what the official React documentation says:
The situation gets more complicated when the children are shuffled around (as in search results) or if new components are added onto the front of the list (as in streams). In these cases where the identity and state of each child must be maintained across render passes, you can uniquely identify each child by assigning it a key.
When React reconciles the keyed children, it will ensure that any child with key will be reordered (instead of clobbered) or destroyed (instead of reused).
You should be able to fix this by providing a unique key element yourself to either the parent div or to all MyInput elements.
For example:
render(){
if (this.state.employed) {
return (
<div key="employed">
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div key="notEmployed">
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
OR
render(){
if (this.state.employed) {
return (
<div>
<MyInput key="title" ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<MyInput key="reason" ref="unemployment-reason" name="unemployment-reason" />
<MyInput key="duration" ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
Now, when React does the diff, it will see that the divs are different and will re-render it including all of its' children (1st example). In the 2nd example, the diff will be a success on job-title and unemployment-reason since they now have different keys.
You can of course use any keys you want, as long as they are unique.
Update August 2017
For a better insight into how keys work in React, I strongly recommend reading my answer to Understanding unique keys in React.js.
Update November 2017
This update should've been posted a while ago, but using string literals in ref is now deprecated. For example ref="job-title" should now instead be ref={(el) => this.jobTitleRef = el} (for example). See my answer to Deprecation warning using this.refs for more info.
Use setState in your view to change employed property of state. This is example of React render engine.
someFunctionWhichChangeParamEmployed(isEmployed) {
this.setState({
employed: isEmployed
});
}
getInitialState() {
return {
employed: true
}
},
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<span>Diff me!</span>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
I'm working on Crud for my app. This is how I did it Got Reactstrap as my dependency.
import React, { useState, setState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import firebase from 'firebase';
// import { LifeCrud } from '../CRUD/Crud';
import { Row, Card, Col, Button } from 'reactstrap';
import InsuranceActionInput from '../CRUD/InsuranceActionInput';
const LifeActionCreate = () => {
let [newLifeActionLabel, setNewLifeActionLabel] = React.useState();
const onCreate = e => {
const db = firebase.firestore();
db.collection('actions').add({
label: newLifeActionLabel
});
alert('New Life Insurance Added');
setNewLifeActionLabel('');
};
return (
<Card style={{ padding: '15px' }}>
<form onSubmit={onCreate}>
<label>Name</label>
<input
value={newLifeActionLabel}
onChange={e => {
setNewLifeActionLabel(e.target.value);
}}
placeholder={'Name'}
/>
<Button onClick={onCreate}>Create</Button>
</form>
</Card>
);
};
Some React Hooks in there