Exporting variables to siblings elements - javascript

Im creating simple test React app.
I've got a small database filled with JS objects. When user types query into a searchbar and presses enter i export this.state.form (string from searchbar) to a variable. Then I iterate through database and if I find a record's name equal to form variable I want to display the details of this object in a div.
However, this div component is in another, sibling JS file and I cant figure out how to effectively export variables and their values to sibling files without Redux.
With pseudo code it would be something like this:
var isFound;
var arrayNumber;
// I iterate through the array of objects with for loop to find correct object and store "i" to arrayNumber and want to export it
// If record is found i set isFound to true, otherwise to false
In a new file I render a simple div, where I want to do the following
//if isFound is false
<div>Not found</div>
//if found
<div>database[i].details</div>

Try to create parent components for these 2 components.
For example, now your structure is smth like
<Component>
<Subcomponent />
<Subcomponent />
... other content
</Component>
You should change it to
<Component>
<ParentSubcomponent>
<Subcomponent />
<Subcomponent />
</ParentSubcomponent>
... other content
</Component>
And leave to ParentComponent to handle search & display using callbacks for Subcomponents (change ParentComponent's state on Subcomponent onClick on search button, that will rerender second Subcomponent because of provided props, that are get from ParentComponent's state (actually it's search result), have been changed, so save data about search & display info in ParentSubcomponent's state.
So single source of truth will be ParentSubcomponent's state, 1st Subcomponent uses callback to update it with the search result, 2nd Subcomponent gets search result (from state) as a props and updates itself.

Related

How to design a complicated form in React

I need to create a form in React made of multiple components, such as <TextField>, <DropDown>, <DatePicker> where each one has a different props, some of them are common such as Id, Label
Question is how should I program this, I have come with a few ideas ->
It would be easier to split it into separate arrays: dropdowns, textFields, datePickers and then render them via .map(), but it wouldn't work as they are not in order in the form
Put all of components into array and render them via .map() with if/switch/function where I would decide which component is which
const App = (props) => {
const forms = props.forms
const getItem(type) {
if (type === Type.DropDown) {
return <Dropdown dropDownProps>
}
....
}
return (
forms.map(item => {
return getItem(item.type)
})
)
}
Next question is how/where to store all props - there is about 10 of these fields in the form, so should I do some file like InitData.ts with
const FirstField = {id: 0, label: "FirstField"}
...
but then how would I pass props such as onChange etc?
Also how should I store all those inputs using hooks? Array of strings, or some object?
Always base your components on abstraction and try to make them reusable, so assume I want to create a login form.
I would create a folder called common having common components, like text field and dropdowns as a way of reusing them.
and then another component for wrapping up most of the functionalities: handling submit events, handling form validation, render input, render dropdown. Most of these functionalities are core in my form, so abstract them away into a separate component called form component.
finally, I create another component called loginForm, in which I call these functionalities to render them.
I store the initial field values of type empty strings in a state hook inside loginform and pass it as an argument to the props of the form component.

How a component pass a prop to another component?

Newbie here, I am studying the documentation of react and in React Context API, I couldn't understand something, I won't understand the rest of the subject if I don't understand it. Can anyone help me what does it mean through using an example?
The Toolbar component must take an extra "theme" prop
and pass it to the ThemedButton. This can become painful
if every single button in the app needs to know the theme
because it would have to be passed through all components.
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
function Toolbar(props) {
// The Toolbar component must take an extra "theme" prop
// and pass it to the ThemedButton. This can become painful
// if every single button in the app needs to know the theme
// because it would have to be passed through all components.
return (
<div>
<ThemedButton theme={props.theme} />
</div>
);
}
class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme} />;
}
}
The Toolbar component must take an extra "theme" prop
this can be like <Toolbar theme="dark">
and pass it to the ThemedButton
how Toolbar component pass this prop to ThemedButton? and kindly clarify the rest of the comment as well.
Thank you for any help? You are kind
In your Toolbar component, it takes a parameter props, props is whatever properties have been passed to it when calling it, as in <Toolbar param1="someString" param2={someVariable}>, in this case the props value in Toolbar will be an object with the data you passed as key=value like for example: {param1: "someString", param2: content_of_someVariable}
And if you don't actually use those props (properties)/parameters in Toolbar, but rather in a subcomponent, then you have to pass them again to another level, like in <ThemedButton theme={props.theme} />, then ThemedButton itself finally passes the value to the component that actually makes use of, which is in your case: <Button theme={this.props.theme} />;.
So you had to pass the theme across multiple components, which don't use it or care at all about it, just to get it through to the final Button component.
(answer ends here, below is my effort to explain context API in an easy way)
To avoid that annoying level to level to another..., you can use the context API. Because it is really incontinent to pass a value across 3-4+ levels/components every time you want to use it in the last one in the chain.
Think about the context like a variable defined and exported on a root level and holds some data (like the user login status for example, or the theme infomation), and whenever you require that data, you import it and use it directly. You use the Provider property of the context you define (MyContext.Provider) to assign the data to it, and you use the Consumer property (MyContext.Consumer) to consume/access that data you assigned in the provider.
The beauty of the context consumer, is that whenever the data is updated in the provider, the consumer immediately gets the new data and triggers a re-render with the new data.
I hope I explained it in a simple and clear way. Write a comment with any questions or unclear parts and I can try my best to improve the answer.
Best of luck!
Props are properties that help define the way your JSX appears on the page.
When you use a component that you have created, you can pass it props like below:
<MyComponent myProp={myPropValue} />
You can continue to pass props down through the component hierarchy as well. So say you have a component tree like below:
MyComponent
--MySubComponent
----MySubSubComponent
You can pass props from MyComponent to MySubSubComponent like so:
<MyComponent myProps={MyProps} />
<MySubComponent mySubProps={props.myProps} /> //Props are the value you gave in the parent component
<MySubSubComponent mySubSubProps={props.mySubProps} />
Whatever title you give the props when declaring the component in JSX is the title you will call to get the value of the prop like props.myProps

Render multiple React components into a single DOM element

I'm looking to render multiple modals into a single ReactDOM element. Here's the HTML structure that React renders to.
<body>
<div id="modal-socket"></div> // Insert multiple here
<div id="wrapper">
// Other content goes here
</div>
</body>
There's a long story behind why I need to render multiple components into #modal-socket but I want to do something akin to this:
ReactDOM.render(<AddMeasurableModal />, document.getElementById("modal-socket"));
ReactDOM.render(<AddMeasurableModal />, document.getElementById("modal-socket"));
ReactDOM.render(<AddMeasurableModal />, document.getElementById("modal-socket"));
Obviously this replaces the current content of #modal-socket on each render call.. So I don't get my end result. Boo.
Did a search and found a few answers on it but none meet my needs.
Cheers.
As you told in a comment, the dynamic way would be something like this
Inside of a main component you could do:
Imagine having an array like:
let myArray = [
{
prop1: 'hello world'
},
{
prop1: 'Hey there!'
}
]
//Then in the render function (you can put that array into the state or something)
render(){
return (
<div>
{myArray.map((entry,index) => {
return <AddMeasurableModal key={index} {...entry} />
})}
</div>
)
}
this will create as many AddMeasurableModal components as there are entrys in the myArray variable and add every property stored as props onto the component (In this case, every AddMeasurableModal component has access to the this.props.prop1 value, because of the {...entry} spread syntax)
Notice how I only put myArray.map() into the render function inside of {}?
React renders every array of components without further configuration inside of the render function. And Array.map() returns an array. Just make sure to return only valid react elements! When doing this, don't forget to add a uniqe key prop to each element to avoid warnings.
EDIT: in this case, the key prop is the current index in the array, but when fetching data from a server I would recommend to use a uniqe id from the database or something to avoid rendering bugs.
If you don't want to map over an array, you can just set a number of components and then loop over them, creating an array of components and put them into the render function.
Wrap your multiple modals into 1 container and render that, eg:
let modals = (
<div>
<AddMeasurableModal />
<AddMeasurableModal />
<AddMeasurableModal />
</div>
);
ReactDOM.render(modals, document.getElementById("modal-socket"));

How change state or property of an outer / separate component in reactjs?

Current DOM tree is like:
<comp1>
<div>
<comp2></comp2>
<comp3>
<comp4 />
<comp4 />
.........
.........
.........
</comp3>
</div>
<comp5></comp5>
</comp1>
Component5 i.e. is my modal. I want to set it's state and props by onclick event on
My objective is to display the detail data on a modal based on the selection.
So I need to set the state and props of modal component accordingly. How can I that in the current structure?
The old fashioned way, which is fine for a small page, is to move all states into the root node (comp1). Other components become stateless. The root node passes to its children the properties they want to render, alongside the setters required to mutate the properties. For instance, comp5 gets a property username which is just the value of comp1.state.username, plus a property setUsername, which is a function taking a username string parameter in which comp1 uses setState to update its state's username. This way comp5 can render and update the username, and other components are aware of the change (setState triggers a render of children).
For more complex apps, passing all these properties to children gets tedious, and you can resort to framework like flux and redux.
i think standard way of doing it is something like this
in your react component:
constructor(props) {
...
this.state = {selectedComp4: null
...
}
}
...
handleSelectedComp4Change (yourData) {
this.setState({selectedComp4: yourData})
}
...
render() {
...
return (
<comp1>
<div>
<comp2></comp2>
<comp3>
<comp4 onSelectedComp4Change = {this.handleSelectedComp4Change}/>
<comp4 onSelectedComp4Change = {this.handleSelectedComp4Change}/>
...
</comp3>
</div>
<comp5 SelectedComp4={this.state.selectedComp4}></comp5>
</comp1>
)
}
in comp4 send your data: onClick={() => { this.props.onSelectedComp4Change(someData) }}
in comp5 use your data in this.props.SelectedComp4
EDIT:
just like #Valéry said

React.js properties

I am currently going through the documentation of React.js and have a question about this.props, which according to the docs should be considered immutable and only pushed downwards down the ownership tree since bubbling custom events upwards is discouraged.
Say that I have a UI where the state of a component in the header of the page should be shared with another component that is nested somewhere in the body of the page, let's take a simple checkbox that represents some specific state that will influence the visibility of some nested spans or divs.
The only I way I currently see this achieved is by creating a state property that is pushed downwards from the top element to the child elements.
The two related questions I have with this is:
Does this mean that I should create one component that owns the entire page? (Is rendering the entire page with a single owner component an acceptable thing to do? I understand the concepts of Virtual DOM and diffing so I assume it's not a problem, still I'd like some confirmation in case I miss out on something relevant);
Is it ok to change the property on this.props when clicking the checkbox, in order to re-render the other components on the page? This doesn't make the props immutable (perhaps they mean just that setting new props on this.props down the chain is not accepted to avoid an untransparent stack trace in case of bugs, but changing the value of a state property is?).
Some confirmation would be appreciated.
Thanks.
1) It is fine to have one parent for the whole page, but is not always necessary. It depends on if it is necessary to share the state between components.
2) You never want to alter props via this.props.someValue = newValue. If you need to modify the parent state from a child component, it should always be done with a callback. The example below shows how to share the checkbox state between multiple components using the callback function handleClick to modify the state of is_checked.
JSFiddle of example: https://jsfiddle.net/mark1z/o7noph4y/
var Parent = React.createClass({
getInitialState: function(){
return ({is_checked: 0})
},
handleClick: function(){
this.setState({is_checked: !this.state.is_checked})
},
render: function(){
return (
<div>
<CheckBox is_checked={this.state.is_checked} handleClick={this.handleClick}/>
<OtherComponent is_checked={this.state.is_checked} />
</div>
);
}
});
var CheckBox = React.createClass({
render: function() {
return (
<input type="checkbox" onChange={this.props.handleClick}> Show other component </input>
);
}
});
var OtherComponent = React.createClass({
render: function() {
return (
<div style={{marginTop: 20}}>
{this.props.is_checked ? 'The checkbox is ticked' : 'The checkbox is not ticked'}
</div>
);
}
});
React.render(<Parent />, document.getElementById('container'));
I guess having one master component isn't an issue. The docs suggest that you find the topmost component that can supply it's children with the needed data - and this could easily be the toplevel master component. As I understand this you would have a master component for your main page - that should be the only one that uses state, the children just render what they are given in props. So no, props should not be altered by a child that doesn't own the data, it is the topmost components prerogative to do so. Let's say you have another widget on the page that only cares for a distinct set of data you would make this the root of another tree that fetches data and sets it's state and the props of it's children.
Here is a crappy graph for this situation:
App -(props)-> ItemList -(props)-> Item -(props)-> Photo
+ + |
+ ++++++++++ |----(props)-> LikeButton
+ + |
(fetch) + |
+ + * ---(props)-> Description
++(setState)++
Widget -(props)-> Whether
However it gets more interesting when facebook's graphql is finalized and every component can declare the needed data on it's own, I'm looking forward to it. But until then the toplevel component has to know which data every child needs and all the parent nodes need to hand this data down.

Categories