Setting State with Objects from Firebase












4














I'm having trouble setting the state of a component in React. The component is called "Search" and uses react-select. The full component is here:



class Search extends React.Component {
constructor(props){
super(props);
let options = ;
for (var x in props.vals){
options.push({ value: props.vals[x], label: props.vals[x], searchId: x });
};
this.state = {
inputValue: '',
value: options
};
}

handleChange = (value: any, actionMeta: any) => {
if(actionMeta.action == "remove-value"){
this.props.onRemoveSearch({ searchId: actionMeta.removedValue.searchId })
}
this.setState({ value });
};

handleInputChange = (inputValue: string) => {
this.setState({ inputValue });
};

handleSearch = ({ value, inputValue }) => {
this.setState({
inputValue: '',
value: [...value, createOption(inputValue)], // Eventually like to take this out...
});
this.props.onSearch({ inputValue });
}

handleKeyDown = (event: SyntheticKeyboardEvent<HTMLElement>) => {
const { inputValue, value } = this.state;
if (!inputValue) return;
switch (event.key) {
case 'Enter':
case 'Tab':
this.handleSearch({
value,
inputValue
});
event.preventDefault();
}
};

render() {
const { inputValue, value } = this.state;
return (
<div className="search">
<div className="search__title">Search</div>
<Tooltip
content={this.props.tooltipContent}
direction="up"
arrow={true}
hoverDelay={400}
distance={12}
padding={"5px"}
>
<CreatableSelect
className={"tags"}
components={components}
inputValue={inputValue}
isMulti
menuIsOpen={false}
onChange={this.handleChange}
onInputChange={this.handleInputChange}
onKeyDown={this.handleKeyDown}
placeholder="Add filters here..."
value={value}
/>
</Tooltip>
</div>
);
}
}

module.exports = Search;


You've probably noticed the strange thing that I'm doing in the constructor function. That's because I need to use data from my firebase database, which is in object form, but react-select expects an array of objects
with a "value" and "label" property. Here's what my data looks like:



enter image description here



To bridge the gap, I wrote a for-in loop which creates the array (called options) and passes that to state.value.



The problem: Because I'm using this "for in" loop, React doesn't recognize when the props have been changed. Thus, the react-select component doesn't re-render. How do I pass down these props (either modifying them inside the parent component or within the Search component) so that the Search component will re-render?










share|improve this question




















  • 2




    If your component is not unmounting, the constructor will not be rerun. So your for in loop will not be rerun unless it unmounts. Another option would be to move the options into your render method, or add an additional lifecycle method of componentDidUpdate
    – Naismith
    Nov 16 at 3:12
















4














I'm having trouble setting the state of a component in React. The component is called "Search" and uses react-select. The full component is here:



class Search extends React.Component {
constructor(props){
super(props);
let options = ;
for (var x in props.vals){
options.push({ value: props.vals[x], label: props.vals[x], searchId: x });
};
this.state = {
inputValue: '',
value: options
};
}

handleChange = (value: any, actionMeta: any) => {
if(actionMeta.action == "remove-value"){
this.props.onRemoveSearch({ searchId: actionMeta.removedValue.searchId })
}
this.setState({ value });
};

handleInputChange = (inputValue: string) => {
this.setState({ inputValue });
};

handleSearch = ({ value, inputValue }) => {
this.setState({
inputValue: '',
value: [...value, createOption(inputValue)], // Eventually like to take this out...
});
this.props.onSearch({ inputValue });
}

handleKeyDown = (event: SyntheticKeyboardEvent<HTMLElement>) => {
const { inputValue, value } = this.state;
if (!inputValue) return;
switch (event.key) {
case 'Enter':
case 'Tab':
this.handleSearch({
value,
inputValue
});
event.preventDefault();
}
};

render() {
const { inputValue, value } = this.state;
return (
<div className="search">
<div className="search__title">Search</div>
<Tooltip
content={this.props.tooltipContent}
direction="up"
arrow={true}
hoverDelay={400}
distance={12}
padding={"5px"}
>
<CreatableSelect
className={"tags"}
components={components}
inputValue={inputValue}
isMulti
menuIsOpen={false}
onChange={this.handleChange}
onInputChange={this.handleInputChange}
onKeyDown={this.handleKeyDown}
placeholder="Add filters here..."
value={value}
/>
</Tooltip>
</div>
);
}
}

module.exports = Search;


You've probably noticed the strange thing that I'm doing in the constructor function. That's because I need to use data from my firebase database, which is in object form, but react-select expects an array of objects
with a "value" and "label" property. Here's what my data looks like:



enter image description here



To bridge the gap, I wrote a for-in loop which creates the array (called options) and passes that to state.value.



The problem: Because I'm using this "for in" loop, React doesn't recognize when the props have been changed. Thus, the react-select component doesn't re-render. How do I pass down these props (either modifying them inside the parent component or within the Search component) so that the Search component will re-render?










share|improve this question




















  • 2




    If your component is not unmounting, the constructor will not be rerun. So your for in loop will not be rerun unless it unmounts. Another option would be to move the options into your render method, or add an additional lifecycle method of componentDidUpdate
    – Naismith
    Nov 16 at 3:12














4












4








4







I'm having trouble setting the state of a component in React. The component is called "Search" and uses react-select. The full component is here:



class Search extends React.Component {
constructor(props){
super(props);
let options = ;
for (var x in props.vals){
options.push({ value: props.vals[x], label: props.vals[x], searchId: x });
};
this.state = {
inputValue: '',
value: options
};
}

handleChange = (value: any, actionMeta: any) => {
if(actionMeta.action == "remove-value"){
this.props.onRemoveSearch({ searchId: actionMeta.removedValue.searchId })
}
this.setState({ value });
};

handleInputChange = (inputValue: string) => {
this.setState({ inputValue });
};

handleSearch = ({ value, inputValue }) => {
this.setState({
inputValue: '',
value: [...value, createOption(inputValue)], // Eventually like to take this out...
});
this.props.onSearch({ inputValue });
}

handleKeyDown = (event: SyntheticKeyboardEvent<HTMLElement>) => {
const { inputValue, value } = this.state;
if (!inputValue) return;
switch (event.key) {
case 'Enter':
case 'Tab':
this.handleSearch({
value,
inputValue
});
event.preventDefault();
}
};

render() {
const { inputValue, value } = this.state;
return (
<div className="search">
<div className="search__title">Search</div>
<Tooltip
content={this.props.tooltipContent}
direction="up"
arrow={true}
hoverDelay={400}
distance={12}
padding={"5px"}
>
<CreatableSelect
className={"tags"}
components={components}
inputValue={inputValue}
isMulti
menuIsOpen={false}
onChange={this.handleChange}
onInputChange={this.handleInputChange}
onKeyDown={this.handleKeyDown}
placeholder="Add filters here..."
value={value}
/>
</Tooltip>
</div>
);
}
}

module.exports = Search;


You've probably noticed the strange thing that I'm doing in the constructor function. That's because I need to use data from my firebase database, which is in object form, but react-select expects an array of objects
with a "value" and "label" property. Here's what my data looks like:



enter image description here



To bridge the gap, I wrote a for-in loop which creates the array (called options) and passes that to state.value.



The problem: Because I'm using this "for in" loop, React doesn't recognize when the props have been changed. Thus, the react-select component doesn't re-render. How do I pass down these props (either modifying them inside the parent component or within the Search component) so that the Search component will re-render?










share|improve this question















I'm having trouble setting the state of a component in React. The component is called "Search" and uses react-select. The full component is here:



class Search extends React.Component {
constructor(props){
super(props);
let options = ;
for (var x in props.vals){
options.push({ value: props.vals[x], label: props.vals[x], searchId: x });
};
this.state = {
inputValue: '',
value: options
};
}

handleChange = (value: any, actionMeta: any) => {
if(actionMeta.action == "remove-value"){
this.props.onRemoveSearch({ searchId: actionMeta.removedValue.searchId })
}
this.setState({ value });
};

handleInputChange = (inputValue: string) => {
this.setState({ inputValue });
};

handleSearch = ({ value, inputValue }) => {
this.setState({
inputValue: '',
value: [...value, createOption(inputValue)], // Eventually like to take this out...
});
this.props.onSearch({ inputValue });
}

handleKeyDown = (event: SyntheticKeyboardEvent<HTMLElement>) => {
const { inputValue, value } = this.state;
if (!inputValue) return;
switch (event.key) {
case 'Enter':
case 'Tab':
this.handleSearch({
value,
inputValue
});
event.preventDefault();
}
};

render() {
const { inputValue, value } = this.state;
return (
<div className="search">
<div className="search__title">Search</div>
<Tooltip
content={this.props.tooltipContent}
direction="up"
arrow={true}
hoverDelay={400}
distance={12}
padding={"5px"}
>
<CreatableSelect
className={"tags"}
components={components}
inputValue={inputValue}
isMulti
menuIsOpen={false}
onChange={this.handleChange}
onInputChange={this.handleInputChange}
onKeyDown={this.handleKeyDown}
placeholder="Add filters here..."
value={value}
/>
</Tooltip>
</div>
);
}
}

module.exports = Search;


You've probably noticed the strange thing that I'm doing in the constructor function. That's because I need to use data from my firebase database, which is in object form, but react-select expects an array of objects
with a "value" and "label" property. Here's what my data looks like:



enter image description here



To bridge the gap, I wrote a for-in loop which creates the array (called options) and passes that to state.value.



The problem: Because I'm using this "for in" loop, React doesn't recognize when the props have been changed. Thus, the react-select component doesn't re-render. How do I pass down these props (either modifying them inside the parent component or within the Search component) so that the Search component will re-render?







javascript arrays reactjs firebase firebase-realtime-database






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 16 at 14:49









Frank van Puffelen

227k28370396




227k28370396










asked Nov 16 at 3:01









Harry Cramer

347214




347214








  • 2




    If your component is not unmounting, the constructor will not be rerun. So your for in loop will not be rerun unless it unmounts. Another option would be to move the options into your render method, or add an additional lifecycle method of componentDidUpdate
    – Naismith
    Nov 16 at 3:12














  • 2




    If your component is not unmounting, the constructor will not be rerun. So your for in loop will not be rerun unless it unmounts. Another option would be to move the options into your render method, or add an additional lifecycle method of componentDidUpdate
    – Naismith
    Nov 16 at 3:12








2




2




If your component is not unmounting, the constructor will not be rerun. So your for in loop will not be rerun unless it unmounts. Another option would be to move the options into your render method, or add an additional lifecycle method of componentDidUpdate
– Naismith
Nov 16 at 3:12




If your component is not unmounting, the constructor will not be rerun. So your for in loop will not be rerun unless it unmounts. Another option would be to move the options into your render method, or add an additional lifecycle method of componentDidUpdate
– Naismith
Nov 16 at 3:12












1 Answer
1






active

oldest

votes


















1














I would suggest not using the value state. What you do is simply copying props into your state. You can use props in render() method directly.



I reckon you use the value state because you need to update it based on user actions. In this case, you could lift this state up into the parent component.



class Parent extends React.Component {
constructor() {
this.state = { value: //structure should be the same as props.vals in ur code };
}
render() {
return (
<Search vals={this.state.value}/>
);
}
}

class Search extends React.Component {
constructor(props){
super(props);

this.state = {
inputValue: '',
};
}

render() {
const { inputValue } = this.state;
const { vals } = this.props;
let options = ;
for (var x in vals){
options.push({ value: vals[x], label: vals[x], searchId: x });
};
return (
<div className="search">
<div className="search__title">Search</div>
<Tooltip
content={this.props.tooltipContent}
direction="up"
arrow={true}
hoverDelay={400}
distance={12}
padding={"5px"}
>
<CreatableSelect
value={options}
/>
</Tooltip>
</div>
);
}
}

module.exports = Search;





share|improve this answer























  • Yes, I am using the value state because the react-select component relies on it. Could you perhaps give a short example of what you mean by "lifting" the state up to my parent component? How could I accomplish that? Thank you.
    – Harry Cramer
    Nov 16 at 19:11










  • Many things depend on the "value" state in my Search component so I'm a little unclear about how to lift it up.
    – Harry Cramer
    Nov 16 at 19:17










  • Please see my updated answer for a brief demo. Without insights into ur code, I can't provide a working demo. You may also need to update your event handler functions.
    – tingxuanz
    Nov 20 at 23:02











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53330809%2fsetting-state-with-objects-from-firebase%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














I would suggest not using the value state. What you do is simply copying props into your state. You can use props in render() method directly.



I reckon you use the value state because you need to update it based on user actions. In this case, you could lift this state up into the parent component.



class Parent extends React.Component {
constructor() {
this.state = { value: //structure should be the same as props.vals in ur code };
}
render() {
return (
<Search vals={this.state.value}/>
);
}
}

class Search extends React.Component {
constructor(props){
super(props);

this.state = {
inputValue: '',
};
}

render() {
const { inputValue } = this.state;
const { vals } = this.props;
let options = ;
for (var x in vals){
options.push({ value: vals[x], label: vals[x], searchId: x });
};
return (
<div className="search">
<div className="search__title">Search</div>
<Tooltip
content={this.props.tooltipContent}
direction="up"
arrow={true}
hoverDelay={400}
distance={12}
padding={"5px"}
>
<CreatableSelect
value={options}
/>
</Tooltip>
</div>
);
}
}

module.exports = Search;





share|improve this answer























  • Yes, I am using the value state because the react-select component relies on it. Could you perhaps give a short example of what you mean by "lifting" the state up to my parent component? How could I accomplish that? Thank you.
    – Harry Cramer
    Nov 16 at 19:11










  • Many things depend on the "value" state in my Search component so I'm a little unclear about how to lift it up.
    – Harry Cramer
    Nov 16 at 19:17










  • Please see my updated answer for a brief demo. Without insights into ur code, I can't provide a working demo. You may also need to update your event handler functions.
    – tingxuanz
    Nov 20 at 23:02
















1














I would suggest not using the value state. What you do is simply copying props into your state. You can use props in render() method directly.



I reckon you use the value state because you need to update it based on user actions. In this case, you could lift this state up into the parent component.



class Parent extends React.Component {
constructor() {
this.state = { value: //structure should be the same as props.vals in ur code };
}
render() {
return (
<Search vals={this.state.value}/>
);
}
}

class Search extends React.Component {
constructor(props){
super(props);

this.state = {
inputValue: '',
};
}

render() {
const { inputValue } = this.state;
const { vals } = this.props;
let options = ;
for (var x in vals){
options.push({ value: vals[x], label: vals[x], searchId: x });
};
return (
<div className="search">
<div className="search__title">Search</div>
<Tooltip
content={this.props.tooltipContent}
direction="up"
arrow={true}
hoverDelay={400}
distance={12}
padding={"5px"}
>
<CreatableSelect
value={options}
/>
</Tooltip>
</div>
);
}
}

module.exports = Search;





share|improve this answer























  • Yes, I am using the value state because the react-select component relies on it. Could you perhaps give a short example of what you mean by "lifting" the state up to my parent component? How could I accomplish that? Thank you.
    – Harry Cramer
    Nov 16 at 19:11










  • Many things depend on the "value" state in my Search component so I'm a little unclear about how to lift it up.
    – Harry Cramer
    Nov 16 at 19:17










  • Please see my updated answer for a brief demo. Without insights into ur code, I can't provide a working demo. You may also need to update your event handler functions.
    – tingxuanz
    Nov 20 at 23:02














1












1








1






I would suggest not using the value state. What you do is simply copying props into your state. You can use props in render() method directly.



I reckon you use the value state because you need to update it based on user actions. In this case, you could lift this state up into the parent component.



class Parent extends React.Component {
constructor() {
this.state = { value: //structure should be the same as props.vals in ur code };
}
render() {
return (
<Search vals={this.state.value}/>
);
}
}

class Search extends React.Component {
constructor(props){
super(props);

this.state = {
inputValue: '',
};
}

render() {
const { inputValue } = this.state;
const { vals } = this.props;
let options = ;
for (var x in vals){
options.push({ value: vals[x], label: vals[x], searchId: x });
};
return (
<div className="search">
<div className="search__title">Search</div>
<Tooltip
content={this.props.tooltipContent}
direction="up"
arrow={true}
hoverDelay={400}
distance={12}
padding={"5px"}
>
<CreatableSelect
value={options}
/>
</Tooltip>
</div>
);
}
}

module.exports = Search;





share|improve this answer














I would suggest not using the value state. What you do is simply copying props into your state. You can use props in render() method directly.



I reckon you use the value state because you need to update it based on user actions. In this case, you could lift this state up into the parent component.



class Parent extends React.Component {
constructor() {
this.state = { value: //structure should be the same as props.vals in ur code };
}
render() {
return (
<Search vals={this.state.value}/>
);
}
}

class Search extends React.Component {
constructor(props){
super(props);

this.state = {
inputValue: '',
};
}

render() {
const { inputValue } = this.state;
const { vals } = this.props;
let options = ;
for (var x in vals){
options.push({ value: vals[x], label: vals[x], searchId: x });
};
return (
<div className="search">
<div className="search__title">Search</div>
<Tooltip
content={this.props.tooltipContent}
direction="up"
arrow={true}
hoverDelay={400}
distance={12}
padding={"5px"}
>
<CreatableSelect
value={options}
/>
</Tooltip>
</div>
);
}
}

module.exports = Search;






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 20 at 6:08

























answered Nov 16 at 3:53









tingxuanz

365




365












  • Yes, I am using the value state because the react-select component relies on it. Could you perhaps give a short example of what you mean by "lifting" the state up to my parent component? How could I accomplish that? Thank you.
    – Harry Cramer
    Nov 16 at 19:11










  • Many things depend on the "value" state in my Search component so I'm a little unclear about how to lift it up.
    – Harry Cramer
    Nov 16 at 19:17










  • Please see my updated answer for a brief demo. Without insights into ur code, I can't provide a working demo. You may also need to update your event handler functions.
    – tingxuanz
    Nov 20 at 23:02


















  • Yes, I am using the value state because the react-select component relies on it. Could you perhaps give a short example of what you mean by "lifting" the state up to my parent component? How could I accomplish that? Thank you.
    – Harry Cramer
    Nov 16 at 19:11










  • Many things depend on the "value" state in my Search component so I'm a little unclear about how to lift it up.
    – Harry Cramer
    Nov 16 at 19:17










  • Please see my updated answer for a brief demo. Without insights into ur code, I can't provide a working demo. You may also need to update your event handler functions.
    – tingxuanz
    Nov 20 at 23:02
















Yes, I am using the value state because the react-select component relies on it. Could you perhaps give a short example of what you mean by "lifting" the state up to my parent component? How could I accomplish that? Thank you.
– Harry Cramer
Nov 16 at 19:11




Yes, I am using the value state because the react-select component relies on it. Could you perhaps give a short example of what you mean by "lifting" the state up to my parent component? How could I accomplish that? Thank you.
– Harry Cramer
Nov 16 at 19:11












Many things depend on the "value" state in my Search component so I'm a little unclear about how to lift it up.
– Harry Cramer
Nov 16 at 19:17




Many things depend on the "value" state in my Search component so I'm a little unclear about how to lift it up.
– Harry Cramer
Nov 16 at 19:17












Please see my updated answer for a brief demo. Without insights into ur code, I can't provide a working demo. You may also need to update your event handler functions.
– tingxuanz
Nov 20 at 23:02




Please see my updated answer for a brief demo. Without insights into ur code, I can't provide a working demo. You may also need to update your event handler functions.
– tingxuanz
Nov 20 at 23:02


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53330809%2fsetting-state-with-objects-from-firebase%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

ComboBox Display Member on multiple fields

Is it possible to collect Nectar points via Trainline?